diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..4a04784b892 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Question + url: https://stackoverflow.com/questions/tagged/visual-studio-code + about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index a0435cb1d3e..00000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: Question -about: The issue tracker is not for questions. Please ask questions on https://stackoverflow.com/questions/tagged/visual-studio-code. - ---- - -🚨 The issue tracker is not for questions 🚨 - -If you have a question, please ask it on https://stackoverflow.com/questions/tagged/visual-studio-code. diff --git a/.github/classifier.yml b/.github/classifier.yml index 8acb0002347..92da2b03f5f 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -144,6 +144,7 @@ explorer-custom: [], extension-host: [], extensions: [], + extensions-development: [ octref ], file-decorations: [], file-encoding: { assignees: [], diff --git a/.github/commands.yml b/.github/commands.yml index 21ebd49ec3c..0e78ac749fa 100644 --- a/.github/commands.yml +++ b/.github/commands.yml @@ -18,42 +18,56 @@ { type: 'label', name: '*dev-question', + allowTriggerByBot: true, action: 'close', comment: "We have a great developer community [over on slack](https://aka.ms/vscode-dev-community) where extension authors help each other. This is a great place for you to ask questions and find support.\n\nHappy Coding!" }, { type: 'label', name: '*extension-candidate', + allowTriggerByBot: true, action: 'close', comment: "We try to keep VS Code lean and we think the functionality you're asking for is great for a VS Code extension. Maybe you can already find one that suits you in the [VS Code Marketplace](https://aka.ms/vscodemarketplace). Just in case, in a few simple steps you can get started [writing your own extension](https://aka.ms/vscodewritingextensions). See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" }, { type: 'label', name: '*not-reproducible', + allowTriggerByBot: true, action: 'close', comment: "We closed this issue because we are unable to reproduce the problem with the steps you describe. Chances are we've already fixed your problem in a recent version of VS Code. If not, please ask us to reopen the issue and provide us with more detail. Our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines might help you with that.\n\nHappy Coding!" }, { type: 'label', name: '*out-of-scope', + allowTriggerByBot: true, action: 'close', - comment: "This issue is being closed to keep the number of issues in our inbox on a manageable level, we are closing issues that are not going to be addressed in the foreseeable future: We look at the number of votes the issue has received and the number of duplicate issues filed. More details [here](https://aka.ms/vscode-out-of-scope). If you disagree and feel that this issue is crucial: We are happy to listen and to reconsider.\n\nIf you wonder what we are up to, please see our [roadmap](https://aka.ms/vscoderoadmap) and [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nThanks for your understanding and happy coding!" + comment: "We closed this issue because we don't plan to address it in the foreseeable future. You can find more detailed information about our decision-making process [here](https://aka.ms/vscode-out-of-scope). If you disagree and feel that this issue is crucial: We are happy to listen and to reconsider.\n\nIf you wonder what we are up to, please see our [roadmap](https://aka.ms/vscoderoadmap) and [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nThanks for your understanding and happy coding!" + }, + { + type: 'comment', + name: 'causedByExtension', + allowUsers: ['cleidigh', 'usernamehw', 'gjsjohnmurray', 'IllusionMH'], + action: 'updateLabels', + addLabel: '*caused-by-extension' }, { type: 'label', name: '*caused-by-extension', + allowTriggerByBot: true, action: 'close', comment: "This issue is caused by an extension, please file it with the repository (or contact) the extension has linked in its overview in VS Code or the [marketplace](https://aka.ms/vscodemarketplace) for VS Code. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" }, { type: 'label', name: '*as-designed', + allowTriggerByBot: true, action: 'close', comment: "The described behavior is how it is expected to work. If you disagree, please explain what is expected and what is not in more detail. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" }, { type: 'label', name: '*english-please', + allowTriggerByBot: true, action: 'close', comment: "This issue is being closed because its description is not in English, that makes it hard for us to work on it. Please open a new issue with an English description. You might find [Bing Translator](https://www.bing.com/translator) useful." }, diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..276121a227b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,9 @@ + + +This PR fixes # diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..55415410f7c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,112 @@ +name: CI + +on: + push: + branches: + - master + - release/* + pull_request: + branches: + - master + - release/* + +jobs: + linux: + runs-on: ubuntu-latest + env: + CHILD_CONCURRENCY: "1" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v1 + # TODO: rename azure-pipelines/linux/xvfb.init to github-actions + - run: | + sudo apt-get update + sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 + sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb + sudo chmod +x /etc/init.d/xvfb + sudo update-rc.d xvfb defaults + sudo service xvfb start + name: Setup Build Environment + - uses: actions/setup-node@v1 + with: + node-version: 10 + # TODO: cache node modules + - run: yarn --frozen-lockfile + name: Install Dependencies + - run: yarn electron x64 + name: Download Electron + - run: yarn gulp hygiene --skip-tslint + name: Run Hygiene Checks + - run: yarn gulp tslint + name: Run TSLint Checks + - run: yarn monaco-compile-check + name: Run Monaco Editor Checks + - run: yarn compile + name: Compile Sources + - run: yarn download-builtin-extensions + name: Download Built-in Extensions + - run: DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests" + name: Run Unit Tests + - run: DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" + name: Run Integration Tests + + windows: + runs-on: windows-2016 + env: + CHILD_CONCURRENCY: "1" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: 10 + - uses: actions/setup-python@v1 + with: + python-version: '2.x' + - run: yarn --frozen-lockfile + name: Install Dependencies + - run: yarn electron + name: Download Electron + - run: yarn gulp hygiene --skip-tslint + name: Run Hygiene Checks + - run: yarn gulp tslint + name: Run TSLint Checks + - run: yarn monaco-compile-check + name: Run Monaco Editor Checks + - run: yarn compile + name: Compile Sources + - run: yarn download-builtin-extensions + name: Download Built-in Extensions + - run: .\scripts\test.bat --tfs "Unit Tests" + name: Run Unit Tests + - run: .\scripts\test-integration.bat --tfs "Integration Tests" + name: Run Integration Tests + + darwin: + runs-on: macos-latest + env: + CHILD_CONCURRENCY: "1" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: 10 + - run: yarn --frozen-lockfile + name: Install Dependencies + - run: yarn electron x64 + name: Download Electron + - run: yarn gulp hygiene --skip-tslint + name: Run Hygiene Checks + - run: yarn gulp tslint + name: Run TSLint Checks + - run: yarn monaco-compile-check + name: Run Monaco Editor Checks + - run: yarn compile + name: Compile Sources + - run: yarn download-builtin-extensions + name: Download Built-in Extensions + - run: ./scripts/test.sh --tfs "Unit Tests" + name: Run Unit Tests + - run: ./scripts/test-integration.sh --tfs "Integration Tests" + name: Run Integration Tests diff --git a/.vscode/launch.json b/.vscode/launch.json index 1d8207865fd..25279b09fd3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -123,8 +123,7 @@ "request": "launch", "name": "Launch VS Code", "windows": { - "runtimeExecutable": "${workspaceFolder}/scripts/code.bat", - "timeout": 20000 + "runtimeExecutable": "${workspaceFolder}/scripts/code.bat" }, "osx": { "runtimeExecutable": "${workspaceFolder}/scripts/code.sh" @@ -132,6 +131,7 @@ "linux": { "runtimeExecutable": "${workspaceFolder}/scripts/code.sh" }, + "timeout": 20000, "env": { "VSCODE_EXTHOST_WILL_SEND_SOCKET": null }, @@ -158,6 +158,22 @@ "${workspaceFolder}/out/**/*.js" ] }, + { + "type": "node", + "request": "launch", + "name": "Launch VS Code (Web)", + "runtimeExecutable": "yarn", + "runtimeArgs": [ + "web" + ], + }, + { + "type": "chrome", + "request": "launch", + "name": "Launch VS Code (Web, Chrome)", + "url": "http://localhost:8080", + "preLaunchTask": "Run web" + }, { "type": "node", "request": "launch", @@ -216,7 +232,10 @@ "cwd": "${workspaceFolder}", "outFiles": [ "${workspaceFolder}/out/**/*.js" - ] + ], + "env": { + "MOCHA_COLORS": "true" + } }, { "type": "node", @@ -251,10 +270,11 @@ ], "compounds": [ { - "name": "Debug VS Code Main and Renderer", + "name": "Debug VS Code Main, Renderer & Extension Host", "configurations": [ "Launch VS Code", - "Attach to Main Process" + "Attach to Main Process", + "Attach to Extension Host" ] }, { @@ -279,4 +299,4 @@ ] }, ] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 551d18bb0ce..ef1f7370d26 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,6 +39,7 @@ ], "typescript.tsdk": "node_modules/typescript/lib", "npm.exclude": "**/extensions/**", + "npm.packageManager": "yarn", "emmet.excludeLanguages": [], "typescript.preferences.importModuleSpecifier": "non-relative", "typescript.preferences.quoteStyle": "single", @@ -60,5 +61,6 @@ "remote.extensionKind": { "msjsdiag.debugger-for-chrome": "workspace" }, + "gulp.autoDetect": "off", "files.insertFinalNewline": true } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5db8fb3fbc5..d1a697bb41d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,7 +5,10 @@ "type": "npm", "script": "watch", "label": "Build VS Code", - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "isBackground": true, "presentation": { "reveal": "never" @@ -73,8 +76,8 @@ "problemMatcher": [] }, { - "type": "gulp", - "task": "electron", + "type": "npm", + "script": "electron", "label": "Download electron" }, { @@ -82,6 +85,24 @@ "task": "hygiene", "problemMatcher": [] }, - + { + "type": "shell", + "command": "yarn web -- --no-launch", + "label": "Run web", + "isBackground": true, + // This section to make error go away when launching the debug config + "problemMatcher": { + "pattern": { + "regexp": "" + }, + "background": { + "beginsPattern": ".*node .*", + "endsPattern": "Web UI available at .*" + } + }, + "presentation": { + "reveal": "never" + } + }, ] } diff --git a/.yarnrc b/.yarnrc index e49da7f447d..4c8b70bf6f6 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "6.0.9" +target "6.1.2" runtime "electron" diff --git a/README.md b/README.md index 5743ba55e8d..5d39d7e40c6 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ please see the document [How to Contribute](https://github.com/Microsoft/vscode/ * [The development workflow, including debugging and running tests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#debugging) * [Coding guidelines](https://github.com/Microsoft/vscode/wiki/Coding-Guidelines) * [Submitting pull requests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#pull-requests) +* [Finding an issue to work on](https://github.com/microsoft/vscode/wiki/How-to-Contribute#where-to-contribute) * [Contributing to translations](https://aka.ms/vscodeloc) ## Feedback diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index aa56c32d53d..440edf6844b 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -27,13 +27,13 @@ This project incorporates components from the projects listed below. The origina 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.12.11 (https://github.com/jeff-hykin/cpp-textmate-grammar) -23. jeff-hykin/cpp-textmate-grammar version 1.13.2 (https://github.com/jeff-hykin/cpp-textmate-grammar) +23. jeff-hykin/cpp-textmate-grammar version 1.14.9 (https://github.com/jeff-hykin/cpp-textmate-grammar) 24. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) 25. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) 26. language-docker (https://github.com/moby/moby) 27. language-go version 0.44.3 (https://github.com/atom/language-go) 28. language-less version 0.34.2 (https://github.com/atom/language-less) -29. language-php version 0.44.1 (https://github.com/atom/language-php) +29. language-php version 0.44.2 (https://github.com/atom/language-php) 30. language-rust version 0.4.12 (https://github.com/zargony/atom-language-rust) 31. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) 32. marked version 0.6.2 (https://github.com/markedjs/marked) @@ -42,32 +42,31 @@ This project incorporates components from the projects listed below. The origina 35. Microsoft/vscode-JSON.tmLanguage (https://github.com/Microsoft/vscode-JSON.tmLanguage) 36. Microsoft/vscode-mssql version 1.6.0 (https://github.com/Microsoft/vscode-mssql) 37. mmims/language-batchfile version 0.7.5 (https://github.com/mmims/language-batchfile) -38. octicons version 8.3.0 (https://github.com/primer/octicons) -39. octref/language-css version 0.42.11 (https://github.com/octref/language-css) -40. PowerShell/EditorSyntax version 1.0.0 (https://github.com/PowerShell/EditorSyntax) -41. promise-polyfill version 8.0.0 (https://github.com/taylorhakes/promise-polyfill) -42. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) -43. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) -44. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) -45. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) -46. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) -47. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) -48. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) -49. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) -50. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) -51. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) -52. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) -53. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) -54. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) -55. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) -56. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) -57. TypeScript-TmLanguage version 0.1.8 (https://github.com/Microsoft/TypeScript-TmLanguage) -58. TypeScript-TmLanguage version 1.0.0 (https://github.com/Microsoft/TypeScript-TmLanguage) -59. Unicode version 12.0.0 (http://www.unicode.org/) -60. vscode-logfile-highlighter version 2.4.1 (https://github.com/emilast/vscode-logfile-highlighter) -61. vscode-octicons-font version 1.3.1 (https://github.com/Microsoft/vscode-octicons-font) -62. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) -63. Web Background Synchronization (https://github.com/WICG/BackgroundSync) +38. octref/language-css version 0.42.11 (https://github.com/octref/language-css) +39. PowerShell/EditorSyntax version 1.0.0 (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) +42. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) +43. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) +44. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) +45. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) +46. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) +47. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) +48. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) +49. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) +50. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) +51. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) +52. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) +53. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) +54. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) +55. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) +56. TypeScript-TmLanguage version 0.1.8 (https://github.com/Microsoft/TypeScript-TmLanguage) +57. TypeScript-TmLanguage version 1.0.0 (https://github.com/Microsoft/TypeScript-TmLanguage) +58. Unicode version 12.0.0 (http://www.unicode.org/) +59. vscode-codicons version 0.0.1 (https://github.com/microsoft/vscode-codicons) +60. vscode-logfile-highlighter version 2.5.0 (https://github.com/emilast/vscode-logfile-highlighter) +61. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) +62. Web Background Synchronization (https://github.com/WICG/BackgroundSync) %% atom/language-clojure NOTICES AND INFORMATION BEGIN HERE @@ -1726,32 +1725,6 @@ THE SOFTWARE. ========================================= END OF mmims/language-batchfile NOTICES AND INFORMATION -%% octicons NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - -Copyright (c) 2019 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. -========================================= -END OF octicons NOTICES AND INFORMATION - %% octref/language-css NOTICES AND INFORMATION BEGIN HERE ========================================= The MIT License (MIT) @@ -2230,6 +2203,406 @@ written authorization of the copyright holder. ========================================= END OF Unicode NOTICES AND INFORMATION +%% vscode-codicons NOTICES AND INFORMATION BEGIN HERE +========================================= +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the "Licensor." The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. +========================================= +END OF vscode-codicons NOTICES AND INFORMATION + %% vscode-logfile-highlighter NOTICES AND INFORMATION BEGIN HERE ========================================= The MIT License (MIT) @@ -2256,32 +2629,6 @@ SOFTWARE. ========================================= END OF vscode-logfile-highlighter NOTICES AND INFORMATION -%% vscode-octicons-font NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - - Copyright (c) Microsoft Corporation. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE -========================================= -END OF vscode-octicons-font NOTICES AND INFORMATION - %% vscode-swift NOTICES AND INFORMATION BEGIN HERE ========================================= The MIT License (MIT) diff --git a/build/azure-pipelines/darwin/continuous-build-darwin.yml b/build/azure-pipelines/darwin/continuous-build-darwin.yml index ef636f91e90..018b09c48ce 100644 --- a/build/azure-pipelines/darwin/continuous-build-darwin.yml +++ b/build/azure-pipelines/darwin/continuous-build-darwin.yml @@ -11,7 +11,7 @@ steps: inputs: versionSpec: "1.x" - script: | - yarn --frozen-lockfile + CHILD_CONCURRENCY=1 yarn --frozen-lockfile displayName: Install Dependencies condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 @@ -21,7 +21,7 @@ steps: vstsFeed: '$(ArtifactFeed)' condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - script: | - yarn gulp electron-x64 + yarn electron x64 displayName: Download Electron - script: | yarn gulp hygiene --skip-tslint diff --git a/build/azure-pipelines/linux/continuous-build-linux.yml b/build/azure-pipelines/linux/continuous-build-linux.yml index d71ab286b15..7ca5db331a2 100644 --- a/build/azure-pipelines/linux/continuous-build-linux.yml +++ b/build/azure-pipelines/linux/continuous-build-linux.yml @@ -19,7 +19,7 @@ steps: inputs: versionSpec: "1.x" - script: | - yarn --frozen-lockfile + CHILD_CONCURRENCY=1 yarn --frozen-lockfile displayName: Install Dependencies condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 @@ -29,7 +29,7 @@ steps: vstsFeed: '$(ArtifactFeed)' condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - script: | - yarn gulp electron-x64 + yarn electron x64 displayName: Download Electron - script: | yarn gulp hygiene --skip-tslint diff --git a/build/azure-pipelines/publish-types/check-version.ts b/build/azure-pipelines/publish-types/check-version.ts index 2c730889112..137e535353a 100644 --- a/build/azure-pipelines/publish-types/check-version.ts +++ b/build/azure-pipelines/publish-types/check-version.ts @@ -35,9 +35,9 @@ function isValidTag(t: string) { return false; } - if (parseInt(major, 10) === NaN || parseInt(minor, 10) === NaN) { + if (isNaN(parseInt(major, 10)) || isNaN(parseInt(minor, 10))) { return false; } return true; -} \ 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 f9b1130d244..f0316915b25 100644 --- a/build/azure-pipelines/win32/continuous-build-win32.yml +++ b/build/azure-pipelines/win32/continuous-build-win32.yml @@ -16,6 +16,8 @@ steps: vstsFeed: '$(ArtifactFeed)' - powershell: | yarn --frozen-lockfile + env: + CHILD_CONCURRENCY: "1" displayName: Install Dependencies condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 @@ -25,7 +27,7 @@ steps: vstsFeed: '$(ArtifactFeed)' condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - powershell: | - yarn gulp electron + yarn electron - script: | yarn gulp hygiene --skip-tslint displayName: Run Hygiene Checks diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index ae36c8cbe84..3c95d012879 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -107,7 +107,7 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { yarn gulp "electron-$(VSCODE_ARCH)" } + exec { yarn electron $(VSCODE_ARCH) } exec { .\scripts\test.bat --build --tfs "Unit Tests" } displayName: Run unit tests condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 76a1e1e51fc..9fef20218ff 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -1,7 +1,7 @@ [ { "name": "ms-vscode.node-debug", - "version": "1.38.8", + "version": "1.40.1", "repo": "https://github.com/Microsoft/vscode-node-debug", "metadata": { "id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6", @@ -16,7 +16,7 @@ }, { "name": "ms-vscode.node-debug2", - "version": "1.39.0", + "version": "1.39.3", "repo": "https://github.com/Microsoft/vscode-node-debug2", "metadata": { "id": "36d19e17-7569-4841-a001-947eb18602b2", diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 64cf089d440..6734a820cf1 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -84,12 +84,10 @@ const extractEditorSrcTask = task.define('extract-editor-src', () => { `lib.dom.d.ts`, `lib.webworker.importscripts.d.ts` ], - redirects: { - 'vs/base/browser/ui/octiconLabel/octiconLabel': 'vs/base/browser/ui/octiconLabel/octiconLabel.mock', - }, shakeLevel: 2, // 0-Files, 1-InnerFile, 2-ClassMembers importIgnorePattern: /(^vs\/css!)|(promise-polyfill\/polyfill)/, - destRoot: path.join(root, 'out-editor-src') + destRoot: path.join(root, 'out-editor-src'), + redirects: [] }); }); diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 30c98f95d06..a8bb8898c90 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -71,7 +71,6 @@ const indentationFilter = [ '!**/yarn-error.log', // except multiple specific folders - '!**/octicons/**', '!**/codicon/**', '!**/fixtures/**', '!**/lib/**', @@ -115,6 +114,7 @@ const copyrightFilter = [ '!**/*.opts', '!**/*.disabled', '!**/*.code-workspace', + '!**/*.js.map', '!**/promise-polyfill/polyfill.js', '!build/**/*.init', '!resources/linux/snap/snapcraft.yaml', @@ -125,6 +125,7 @@ const copyrightFilter = [ '!extensions/html-language-features/server/src/modes/typescript/*', '!extensions/*/server/bin/*', '!src/vs/editor/test/node/classification/typescript-test.ts', + '!scripts/code-web.js' ]; const eslintFilter = [ diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 9a63fcec936..93a943aba0b 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -30,7 +30,7 @@ const product = require('../product.json'); const crypto = require('crypto'); const i18n = require('./lib/i18n'); const deps = require('./dependencies'); -const getElectronVersion = require('./lib/electron').getElectronVersion; +const { config } = require('./lib/electron'); const createAsar = require('./lib/asar').createAsar; const minimist = require('minimist'); const { compileBuildTask } = require('./gulpfile.compile'); @@ -67,7 +67,6 @@ const vscodeResources = [ 'out-build/vs/base/common/performance.js', 'out-build/vs/base/node/languagePacks.js', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}', - 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/base/browser/ui/codiconLabel/codicon/**', 'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/contrib/debug/**/*.json', @@ -113,99 +112,6 @@ const minifyVSCodeTask = task.define('minify-vscode', task.series( )); gulp.task(minifyVSCodeTask); -// Package - -// @ts-ignore JSON checking: darwinCredits is optional -const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); - -function darwinBundleDocumentType(extensions, icon) { - return { - name: product.nameLong + ' document', - role: 'Editor', - ostypes: ["TEXT", "utxt", "TUTX", "****"], - extensions: extensions, - iconFile: icon - }; -} - -const config = { - version: getElectronVersion(), - productAppName: product.nameLong, - companyName: 'Microsoft Corporation', - copyright: 'Copyright (C) 2019 Microsoft. All rights reserved', - darwinIcon: 'resources/darwin/code.icns', - darwinBundleIdentifier: product.darwinBundleIdentifier, - darwinApplicationCategoryType: 'public.app-category.developer-tools', - darwinHelpBookFolder: 'VS Code HelpBook', - darwinHelpBookName: 'VS Code HelpBook', - darwinBundleDocumentTypes: [ - darwinBundleDocumentType(["bat", "cmd"], 'resources/darwin/bat.icns'), - darwinBundleDocumentType(["bowerrc"], 'resources/darwin/bower.icns'), - darwinBundleDocumentType(["c", "h"], 'resources/darwin/c.icns'), - darwinBundleDocumentType(["config", "editorconfig", "gitattributes", "gitconfig", "gitignore", "ini"], 'resources/darwin/config.icns'), - darwinBundleDocumentType(["cc", "cpp", "cxx", "hh", "hpp", "hxx"], 'resources/darwin/cpp.icns'), - darwinBundleDocumentType(["cs", "csx"], 'resources/darwin/csharp.icns'), - darwinBundleDocumentType(["css"], 'resources/darwin/css.icns'), - darwinBundleDocumentType(["go"], 'resources/darwin/go.icns'), - darwinBundleDocumentType(["asp", "aspx", "cshtml", "htm", "html", "jshtm", "jsp", "phtml", "shtml"], 'resources/darwin/html.icns'), - darwinBundleDocumentType(["jade"], 'resources/darwin/jade.icns'), - darwinBundleDocumentType(["jav", "java"], 'resources/darwin/java.icns'), - darwinBundleDocumentType(["js", "jscsrc", "jshintrc", "mjs"], 'resources/darwin/javascript.icns'), - darwinBundleDocumentType(["json"], 'resources/darwin/json.icns'), - darwinBundleDocumentType(["less"], 'resources/darwin/less.icns'), - darwinBundleDocumentType(["markdown", "md", "mdoc", "mdown", "mdtext", "mdtxt", "mdwn", "mkd", "mkdn"], 'resources/darwin/markdown.icns'), - darwinBundleDocumentType(["php"], 'resources/darwin/php.icns'), - darwinBundleDocumentType(["ps1", "psd1", "psm1"], 'resources/darwin/powershell.icns'), - darwinBundleDocumentType(["py"], 'resources/darwin/python.icns'), - darwinBundleDocumentType(["gemspec", "rb"], 'resources/darwin/ruby.icns'), - darwinBundleDocumentType(["scss"], 'resources/darwin/sass.icns'), - darwinBundleDocumentType(["bash", "bash_login", "bash_logout", "bash_profile", "bashrc", "profile", "rhistory", "rprofile", "sh", "zlogin", "zlogout", "zprofile", "zsh", "zshenv", "zshrc"], 'resources/darwin/shell.icns'), - darwinBundleDocumentType(["sql"], 'resources/darwin/sql.icns'), - darwinBundleDocumentType(["ts"], 'resources/darwin/typescript.icns'), - darwinBundleDocumentType(["tsx", "jsx"], 'resources/darwin/react.icns'), - darwinBundleDocumentType(["vue"], 'resources/darwin/vue.icns'), - darwinBundleDocumentType(["ascx", "csproj", "dtd", "wxi", "wxl", "wxs", "xml", "xaml"], 'resources/darwin/xml.icns'), - darwinBundleDocumentType(["eyaml", "eyml", "yaml", "yml"], 'resources/darwin/yaml.icns'), - darwinBundleDocumentType(["clj", "cljs", "cljx", "clojure", "code-workspace", "coffee", "ctp", "dockerfile", "dot", "edn", "fs", "fsi", "fsscript", "fsx", "handlebars", "hbs", "lua", "m", "makefile", "ml", "mli", "pl", "pl6", "pm", "pm6", "pod", "pp", "properties", "psgi", "pug", "r", "rs", "rt", "svg", "svgz", "t", "txt", "vb", "xcodeproj", "xcworkspace"], 'resources/darwin/default.icns') - ], - darwinBundleURLTypes: [{ - role: 'Viewer', - name: product.nameLong, - urlSchemes: [product.urlProtocol] - }], - darwinForceDarkModeSupport: true, - darwinCredits: darwinCreditsTemplate ? Buffer.from(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : undefined, - linuxExecutableName: product.applicationName, - winIcon: 'resources/win32/code.ico', - token: process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || undefined, - - // @ts-ignore JSON checking: electronRepository is optional - repo: product.electronRepository || undefined -}; - -function getElectron(arch) { - return () => { - const electronOpts = _.extend({}, config, { - platform: process.platform, - arch, - ffmpegChromium: true, - keepDefaultApp: true - }); - - return gulp.src('package.json') - .pipe(json({ name: product.nameShort })) - .pipe(electron(electronOpts)) - .pipe(filter(['**', '!**/app/package.json'])) - .pipe(vfs.dest('.build/electron')); - }; -} - -gulp.task(task.define('electron', task.series(util.rimraf('.build/electron'), getElectron(process.arch)))); -gulp.task(task.define('electron-ia32', task.series(util.rimraf('.build/electron'), getElectron('ia32')))); -gulp.task(task.define('electron-x64', task.series(util.rimraf('.build/electron'), getElectron('x64')))); -gulp.task(task.define('electron-arm', task.series(util.rimraf('.build/electron'), getElectron('armv7l')))); -gulp.task(task.define('electron-arm64', task.series(util.rimraf('.build/electron'), getElectron('arm64')))); - /** * Compute checksums for some files. * @@ -627,4 +533,3 @@ function getSettingsSearchBuildId(packageJson) { throw new Error('Could not determine build number: ' + e.toString()); } } - diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 7cbda83c0d8..9d3a7caa07e 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -43,7 +43,7 @@ function prepareDebPackage(arch) { .pipe(replace('@@NAME_SHORT@@', product.nameShort)) .pipe(replace('@@NAME@@', product.applicationName)) .pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`)) - .pipe(replace('@@ICON@@', product.linuxIconName)) + .pipe(replace('@@ICON@@', `/usr/share/pixmaps/${product.linuxIconName}.png`)) .pipe(replace('@@URLPROTOCOL@@', product.urlProtocol)); const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' }) diff --git a/build/lib/electron.js b/build/lib/electron.js index 63e867a98fe..c7c4cd9a693 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -2,29 +2,115 @@ * 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 fs = require('fs'); -const path = require('path'); +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = require("fs"); +const path = require("path"); +const vfs = require("vinyl-fs"); +const filter = require("gulp-filter"); +const json = require("gulp-json-editor"); +const _ = require("underscore"); +const util = require("./util"); +const electron = require('gulp-atom-electron'); const root = path.dirname(path.dirname(__dirname)); - +const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); +const commit = util.getVersion(root); function getElectronVersion() { - const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); - // @ts-ignore - const target = /^target "(.*)"$/m.exec(yarnrc)[1]; - - return target; + const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); + const target = /^target "(.*)"$/m.exec(yarnrc)[1]; + return target; +} +exports.getElectronVersion = getElectronVersion; +const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); +function darwinBundleDocumentType(extensions, icon) { + return { + name: product.nameLong + ' document', + role: 'Editor', + ostypes: ["TEXT", "utxt", "TUTX", "****"], + extensions: extensions, + iconFile: icon + }; +} +exports.config = { + version: getElectronVersion(), + productAppName: product.nameLong, + companyName: 'Microsoft Corporation', + copyright: 'Copyright (C) 2019 Microsoft. All rights reserved', + darwinIcon: 'resources/darwin/code.icns', + darwinBundleIdentifier: product.darwinBundleIdentifier, + darwinApplicationCategoryType: 'public.app-category.developer-tools', + darwinHelpBookFolder: 'VS Code HelpBook', + darwinHelpBookName: 'VS Code HelpBook', + darwinBundleDocumentTypes: [ + darwinBundleDocumentType(["bat", "cmd"], 'resources/darwin/bat.icns'), + darwinBundleDocumentType(["bowerrc"], 'resources/darwin/bower.icns'), + darwinBundleDocumentType(["c", "h"], 'resources/darwin/c.icns'), + darwinBundleDocumentType(["config", "editorconfig", "gitattributes", "gitconfig", "gitignore", "ini"], 'resources/darwin/config.icns'), + darwinBundleDocumentType(["cc", "cpp", "cxx", "hh", "hpp", "hxx"], 'resources/darwin/cpp.icns'), + darwinBundleDocumentType(["cs", "csx"], 'resources/darwin/csharp.icns'), + darwinBundleDocumentType(["css"], 'resources/darwin/css.icns'), + darwinBundleDocumentType(["go"], 'resources/darwin/go.icns'), + darwinBundleDocumentType(["asp", "aspx", "cshtml", "htm", "html", "jshtm", "jsp", "phtml", "shtml"], 'resources/darwin/html.icns'), + darwinBundleDocumentType(["jade"], 'resources/darwin/jade.icns'), + darwinBundleDocumentType(["jav", "java"], 'resources/darwin/java.icns'), + darwinBundleDocumentType(["js", "jscsrc", "jshintrc", "mjs"], 'resources/darwin/javascript.icns'), + darwinBundleDocumentType(["json"], 'resources/darwin/json.icns'), + darwinBundleDocumentType(["less"], 'resources/darwin/less.icns'), + darwinBundleDocumentType(["markdown", "md", "mdoc", "mdown", "mdtext", "mdtxt", "mdwn", "mkd", "mkdn"], 'resources/darwin/markdown.icns'), + darwinBundleDocumentType(["php"], 'resources/darwin/php.icns'), + darwinBundleDocumentType(["ps1", "psd1", "psm1"], 'resources/darwin/powershell.icns'), + darwinBundleDocumentType(["py"], 'resources/darwin/python.icns'), + darwinBundleDocumentType(["gemspec", "rb"], 'resources/darwin/ruby.icns'), + darwinBundleDocumentType(["scss"], 'resources/darwin/sass.icns'), + darwinBundleDocumentType(["bash", "bash_login", "bash_logout", "bash_profile", "bashrc", "profile", "rhistory", "rprofile", "sh", "zlogin", "zlogout", "zprofile", "zsh", "zshenv", "zshrc"], 'resources/darwin/shell.icns'), + darwinBundleDocumentType(["sql"], 'resources/darwin/sql.icns'), + darwinBundleDocumentType(["ts"], 'resources/darwin/typescript.icns'), + darwinBundleDocumentType(["tsx", "jsx"], 'resources/darwin/react.icns'), + darwinBundleDocumentType(["vue"], 'resources/darwin/vue.icns'), + darwinBundleDocumentType(["ascx", "csproj", "dtd", "wxi", "wxl", "wxs", "xml", "xaml"], 'resources/darwin/xml.icns'), + darwinBundleDocumentType(["eyaml", "eyml", "yaml", "yml"], 'resources/darwin/yaml.icns'), + darwinBundleDocumentType(["clj", "cljs", "cljx", "clojure", "code-workspace", "coffee", "ctp", "dockerfile", "dot", "edn", "fs", "fsi", "fsscript", "fsx", "handlebars", "hbs", "lua", "m", "makefile", "ml", "mli", "pl", "pl6", "pm", "pm6", "pod", "pp", "properties", "psgi", "pug", "r", "rs", "rt", "svg", "svgz", "t", "txt", "vb", "xcodeproj", "xcworkspace"], 'resources/darwin/default.icns') + ], + darwinBundleURLTypes: [{ + role: 'Viewer', + name: product.nameLong, + urlSchemes: [product.urlProtocol] + }], + darwinForceDarkModeSupport: true, + darwinCredits: darwinCreditsTemplate ? Buffer.from(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : undefined, + linuxExecutableName: product.applicationName, + winIcon: 'resources/win32/code.ico', + token: process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || undefined, + repo: product.electronRepository || undefined +}; +function getElectron(arch) { + return () => { + const electronOpts = _.extend({}, exports.config, { + platform: process.platform, + arch, + ffmpegChromium: true, + keepDefaultApp: true + }); + return vfs.src('package.json') + .pipe(json({ name: product.nameShort })) + .pipe(electron(electronOpts)) + .pipe(filter(['**', '!**/app/package.json'])) + .pipe(vfs.dest('.build/electron')); + }; +} +async function main(arch = process.arch) { + const version = getElectronVersion(); + const electronPath = path.join(root, '.build', 'electron'); + const versionFile = path.join(electronPath, 'version'); + const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; + if (!isUpToDate) { + await util.rimraf(electronPath)(); + await util.streamToPromise(getElectron(arch)()); + } } - -module.exports.getElectronVersion = getElectronVersion; - -// returns 0 if the right version of electron is in .build/electron -// @ts-ignore if (require.main === module) { - const version = getElectronVersion(); - const versionFile = path.join(root, '.build', 'electron', 'version'); - const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; - - process.exit(isUpToDate ? 0 : 1); + main(process.argv[2]).catch(err => { + console.error(err); + process.exit(1); + }); } diff --git a/build/lib/electron.ts b/build/lib/electron.ts new file mode 100644 index 00000000000..90a25f4cac8 --- /dev/null +++ b/build/lib/electron.ts @@ -0,0 +1,127 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as fs from 'fs'; +import * as path from 'path'; +import * as vfs from 'vinyl-fs'; +import * as filter from 'gulp-filter'; +import * as json from 'gulp-json-editor'; +import * as _ from 'underscore'; +import * as util from './util'; + +const electron = require('gulp-atom-electron'); + +const root = path.dirname(path.dirname(__dirname)); +const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); +const commit = util.getVersion(root); + +export function getElectronVersion(): string { + const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); + const target = /^target "(.*)"$/m.exec(yarnrc)![1]; + return target; +} + +const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); + +function darwinBundleDocumentType(extensions: string[], icon: string) { + return { + name: product.nameLong + ' document', + role: 'Editor', + ostypes: ["TEXT", "utxt", "TUTX", "****"], + extensions: extensions, + iconFile: icon + }; +} + +export const config = { + version: getElectronVersion(), + productAppName: product.nameLong, + companyName: 'Microsoft Corporation', + copyright: 'Copyright (C) 2019 Microsoft. All rights reserved', + darwinIcon: 'resources/darwin/code.icns', + darwinBundleIdentifier: product.darwinBundleIdentifier, + darwinApplicationCategoryType: 'public.app-category.developer-tools', + darwinHelpBookFolder: 'VS Code HelpBook', + darwinHelpBookName: 'VS Code HelpBook', + darwinBundleDocumentTypes: [ + darwinBundleDocumentType(["bat", "cmd"], 'resources/darwin/bat.icns'), + darwinBundleDocumentType(["bowerrc"], 'resources/darwin/bower.icns'), + darwinBundleDocumentType(["c", "h"], 'resources/darwin/c.icns'), + darwinBundleDocumentType(["config", "editorconfig", "gitattributes", "gitconfig", "gitignore", "ini"], 'resources/darwin/config.icns'), + darwinBundleDocumentType(["cc", "cpp", "cxx", "hh", "hpp", "hxx"], 'resources/darwin/cpp.icns'), + darwinBundleDocumentType(["cs", "csx"], 'resources/darwin/csharp.icns'), + darwinBundleDocumentType(["css"], 'resources/darwin/css.icns'), + darwinBundleDocumentType(["go"], 'resources/darwin/go.icns'), + darwinBundleDocumentType(["asp", "aspx", "cshtml", "htm", "html", "jshtm", "jsp", "phtml", "shtml"], 'resources/darwin/html.icns'), + darwinBundleDocumentType(["jade"], 'resources/darwin/jade.icns'), + darwinBundleDocumentType(["jav", "java"], 'resources/darwin/java.icns'), + darwinBundleDocumentType(["js", "jscsrc", "jshintrc", "mjs"], 'resources/darwin/javascript.icns'), + darwinBundleDocumentType(["json"], 'resources/darwin/json.icns'), + darwinBundleDocumentType(["less"], 'resources/darwin/less.icns'), + darwinBundleDocumentType(["markdown", "md", "mdoc", "mdown", "mdtext", "mdtxt", "mdwn", "mkd", "mkdn"], 'resources/darwin/markdown.icns'), + darwinBundleDocumentType(["php"], 'resources/darwin/php.icns'), + darwinBundleDocumentType(["ps1", "psd1", "psm1"], 'resources/darwin/powershell.icns'), + darwinBundleDocumentType(["py"], 'resources/darwin/python.icns'), + darwinBundleDocumentType(["gemspec", "rb"], 'resources/darwin/ruby.icns'), + darwinBundleDocumentType(["scss"], 'resources/darwin/sass.icns'), + darwinBundleDocumentType(["bash", "bash_login", "bash_logout", "bash_profile", "bashrc", "profile", "rhistory", "rprofile", "sh", "zlogin", "zlogout", "zprofile", "zsh", "zshenv", "zshrc"], 'resources/darwin/shell.icns'), + darwinBundleDocumentType(["sql"], 'resources/darwin/sql.icns'), + darwinBundleDocumentType(["ts"], 'resources/darwin/typescript.icns'), + darwinBundleDocumentType(["tsx", "jsx"], 'resources/darwin/react.icns'), + darwinBundleDocumentType(["vue"], 'resources/darwin/vue.icns'), + darwinBundleDocumentType(["ascx", "csproj", "dtd", "wxi", "wxl", "wxs", "xml", "xaml"], 'resources/darwin/xml.icns'), + darwinBundleDocumentType(["eyaml", "eyml", "yaml", "yml"], 'resources/darwin/yaml.icns'), + darwinBundleDocumentType(["clj", "cljs", "cljx", "clojure", "code-workspace", "coffee", "ctp", "dockerfile", "dot", "edn", "fs", "fsi", "fsscript", "fsx", "handlebars", "hbs", "lua", "m", "makefile", "ml", "mli", "pl", "pl6", "pm", "pm6", "pod", "pp", "properties", "psgi", "pug", "r", "rs", "rt", "svg", "svgz", "t", "txt", "vb", "xcodeproj", "xcworkspace"], 'resources/darwin/default.icns') + ], + darwinBundleURLTypes: [{ + role: 'Viewer', + name: product.nameLong, + urlSchemes: [product.urlProtocol] + }], + darwinForceDarkModeSupport: true, + darwinCredits: darwinCreditsTemplate ? Buffer.from(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : undefined, + linuxExecutableName: product.applicationName, + winIcon: 'resources/win32/code.ico', + token: process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || undefined, + repo: product.electronRepository || undefined +}; + +function getElectron(arch: string): () => NodeJS.ReadWriteStream { + return () => { + const electronOpts = _.extend({}, config, { + platform: process.platform, + arch, + ffmpegChromium: true, + keepDefaultApp: true + }); + + return vfs.src('package.json') + .pipe(json({ name: product.nameShort })) + .pipe(electron(electronOpts)) + .pipe(filter(['**', '!**/app/package.json'])) + .pipe(vfs.dest('.build/electron')); + }; +} + +async function main(arch = process.arch): Promise { + const version = getElectronVersion(); + const electronPath = path.join(root, '.build', 'electron'); + const versionFile = path.join(electronPath, 'version'); + const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; + + if (!isUpToDate) { + await util.rimraf(electronPath)(); + await util.streamToPromise(getElectron(arch)()); + } +} + +if (require.main === module) { + main(process.argv[2]).catch(err => { + console.error(err); + process.exit(1); + }); +} diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 1987d5ca9c0..3f8c3cec51f 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -242,6 +242,10 @@ "name": "vs/workbench/services/keybinding", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/lifecycle", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/mode", "project": "vscode-workbench" @@ -267,7 +271,7 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/services/workspace", + "name": "vs/workbench/services/workspaces", "project": "vscode-workbench" }, { diff --git a/build/lib/util.js b/build/lib/util.js index 6acb7ab574f..1888bfed2e4 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -166,20 +166,23 @@ function stripSourceMappingURL() { } exports.stripSourceMappingURL = stripSourceMappingURL; function rimraf(dir) { - let retries = 0; - const retry = (cb) => { - _rimraf(dir, { maxBusyTries: 1 }, (err) => { - if (!err) { - return cb(); - } - if (err.code === 'ENOTEMPTY' && ++retries < 5) { - return setTimeout(() => retry(cb), 10); - } - return cb(err); - }); - }; - retry.taskName = `clean-${path.basename(dir).toLowerCase()}`; - return retry; + const result = () => new Promise((c, e) => { + let retries = 0; + const retry = () => { + _rimraf(dir, { maxBusyTries: 1 }, (err) => { + if (!err) { + return c(); + } + if (err.code === 'ENOTEMPTY' && ++retries < 5) { + return setTimeout(() => retry(), 10); + } + return e(err); + }); + }; + retry(); + }); + result.taskName = `clean-${path.basename(dir).toLowerCase()}`; + return result; } exports.rimraf = rimraf; function getVersion(root) { @@ -219,3 +222,10 @@ function versionStringToNumber(versionStr) { return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10); } exports.versionStringToNumber = versionStringToNumber; +function streamToPromise(stream) { + return new Promise((c, e) => { + stream.on('error', err => e(err)); + stream.on('end', () => c()); + }); +} +exports.streamToPromise = streamToPromise; diff --git a/build/lib/util.ts b/build/lib/util.ts index 6a82295ae26..ae598d5f2cf 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -218,24 +218,29 @@ export function stripSourceMappingURL(): NodeJS.ReadWriteStream { return es.duplex(input, output); } -export function rimraf(dir: string): (cb: any) => void { - let retries = 0; +export function rimraf(dir: string): () => Promise { + const result = () => new Promise((c, e) => { + let retries = 0; - const retry = (cb: (err?: any) => void) => { - _rimraf(dir, { maxBusyTries: 1 }, (err: any) => { - if (!err) { - return cb(); - } + const retry = () => { + _rimraf(dir, { maxBusyTries: 1 }, (err: any) => { + if (!err) { + return c(); + } - if (err.code === 'ENOTEMPTY' && ++retries < 5) { - return setTimeout(() => retry(cb), 10); - } + if (err.code === 'ENOTEMPTY' && ++retries < 5) { + return setTimeout(() => retry(), 10); + } - return cb(err); - }); - }; - retry.taskName = `clean-${path.basename(dir).toLowerCase()}`; - return retry; + return e(err); + }); + }; + + retry(); + }); + + result.taskName = `clean-${path.basename(dir).toLowerCase()}`; + return result; } export function getVersion(root: string): string | undefined { @@ -281,3 +286,10 @@ export function versionStringToNumber(versionStr: string) { return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10); } + +export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise { + return new Promise((c, e) => { + stream.on('error', err => e(err)); + stream.on('end', () => c()); + }); +} diff --git a/build/monaco/api.js b/build/monaco/api.js index 93fea1558b9..a429cd66cde 100644 --- a/build/monaco/api.js +++ b/build/monaco/api.js @@ -516,7 +516,7 @@ class DeclarationResolver { 'file.ts': fileContents }; const service = ts.createLanguageService(new TypeScriptLanguageServiceHost({}, fileMap, {})); - const text = service.getEmitOutput('file.ts', true).outputFiles[0].text; + const text = service.getEmitOutput('file.ts', true, true).outputFiles[0].text; return new CacheEntry(ts.createSourceFile(fileName, text, ts.ScriptTarget.ES5), mtime); } } diff --git a/build/monaco/api.ts b/build/monaco/api.ts index 1cd4e49b733..ae058292344 100644 --- a/build/monaco/api.ts +++ b/build/monaco/api.ts @@ -617,7 +617,7 @@ export class DeclarationResolver { 'file.ts': fileContents }; const service = ts.createLanguageService(new TypeScriptLanguageServiceHost({}, fileMap, {})); - const text = service.getEmitOutput('file.ts', true).outputFiles[0].text; + const text = service.getEmitOutput('file.ts', true, true).outputFiles[0].text; return new CacheEntry( ts.createSourceFile(fileName, text, ts.ScriptTarget.ES5), mtime diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index 4a80dae41aa..900b1bcce60 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -48,7 +48,7 @@ declare namespace monaco.editor { #include(vs/editor/standalone/common/standaloneThemeService): BuiltinTheme, IStandaloneThemeData, IColors #include(vs/editor/common/modes/supports/tokenization): ITokenThemeRule #include(vs/editor/common/services/webWorker): MonacoWebWorker, IWebWorkerOptions -#include(vs/editor/standalone/browser/standaloneCodeEditor): IActionDescriptor, IEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor +#include(vs/editor/standalone/browser/standaloneCodeEditor): IActionDescriptor, IStandaloneEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor export interface ICommandHandler { (...args: any[]): void; } diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index 87eeb860e0e..e89344d9139 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -80,41 +80,3 @@ if (fs.existsSync(processTreeDts)) { console.log('Removing windows-process-tree.d.ts'); fs.unlinkSync(processTreeDts); } - -function getInstalledVersion(packageName, cwd) { - const opts = {}; - if (cwd) { - opts.cwd = cwd; - } - - const result = cp.spawnSync(yarn, ['list', '--pattern', packageName], opts); - const stdout = result.stdout.toString(); - const match = stdout.match(new RegExp(packageName + '@(\\S+)')); - if (!match || !match[1]) { - throw new Error('Unexpected output from yarn list: ' + stdout); - } - - return match[1]; -} - -function assertSameVersionsBetweenFolders(packageName, otherFolder) { - const baseVersion = getInstalledVersion(packageName); - const otherVersion = getInstalledVersion(packageName, otherFolder); - - if (baseVersion !== otherVersion) { - throw new Error(`Mismatched versions installed for ${packageName}: root has ${baseVersion}, ./${otherFolder} has ${otherVersion}. These should be the same!`); - } -} - -// Check that modules in both the base package.json and remote/ have the same version installed -const requireSameVersionsInRemote = [ - 'xterm', - 'xterm-addon-search', - 'xterm-addon-web-links', - 'node-pty', - 'vscode-ripgrep' -]; - -requireSameVersionsInRemote.forEach(packageName => { - assertSameVersionsBetweenFolders(packageName, 'remote'); -}); diff --git a/build/package.json b/build/package.json index bf3ec5ce3f9..f91279c6345 100644 --- a/build/package.json +++ b/build/package.json @@ -40,9 +40,9 @@ "mime": "^1.3.4", "minimist": "^1.2.0", "request": "^2.85.0", - "terser": "4.3.1", + "terser": "4.3.8", "tslint": "^5.9.1", - "typescript": "3.6.2", + "typescript": "3.7.1-rc", "vsce": "1.48.0", "vscode-telemetry-extractor": "^1.5.4", "xml2js": "^0.4.17" diff --git a/build/win32/Cargo.lock b/build/win32/Cargo.lock index 3c95fb34cdf..e27f58bf455 100644 --- a/build/win32/Cargo.lock +++ b/build/win32/Cargo.lock @@ -29,7 +29,7 @@ dependencies = [ [[package]] name = "inno_updater" -version = "0.8.0" +version = "0.8.2" 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/inno_updater.exe b/build/win32/inno_updater.exe index baca28361d1..8c532b9eb5e 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 937eb1daa43..b4c924d705e 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -2178,10 +2178,10 @@ terser@*: source-map "~0.6.1" source-map-support "~0.5.12" -terser@4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.1.tgz#09820bcb3398299c4b48d9a86aefc65127d0ed65" - integrity sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg== +terser@4.3.8: + version "4.3.8" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.8.tgz#707f05f3f4c1c70c840e626addfdb1c158a17136" + integrity sha512-otmIRlRVmLChAWsnSFNO0Bfk6YySuBp6G9qrHiJwlLDd4mxe2ta4sjI7TzIR+W1nBMjilzrMcPOz9pSusgx3hQ== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -2297,10 +2297,10 @@ typed-rest-client@^0.9.0: tunnel "0.0.4" underscore "1.8.3" -typescript@3.6.2: - version "3.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.2.tgz#105b0f1934119dde543ac8eb71af3a91009efe54" - integrity sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw== +typescript@3.7.1-rc: + version "3.7.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.1-rc.tgz#2054b872d67f8dc732e36c1df397f9327f37ada0" + integrity sha512-2rMtWppLsaPvmpXsoIAXWDBQVnJMw1ITGGSnidMuayLj9iCmMRT69ncKZw/Mk5rXfJkilApKucWQZxproALoRw== typescript@^3.0.1: version "3.5.3" diff --git a/cgmanifest.json b/cgmanifest.json index 8e8fc3484ff..53dab5356a2 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "407747b48c47cdeed156a73dde1c47609470c95a" + "commitHash": "dabaa7557a165cc107f89fd7c3e3c3210f9b5758" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "6.0.9" + "version": "6.1.2" }, { "component": { @@ -96,25 +96,13 @@ "component": { "type": "git", "git": { - "name": "vscode-octicons-font", - "repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font", - "commitHash": "415cd5b42ab699b6b46c0bf011ada0a2ae50bfb4" + "name": "vscode-codicons", + "repositoryUrl": "https://github.com/microsoft/vscode-codicons", + "commitHash": "1f8534396cda86d3fa199b0e45ce110b55d794d0" } }, - "license": "MIT", - "version": "1.3.1" - }, - { - "component": { - "type": "git", - "git": { - "name": "octicons", - "repositoryUrl": "https://github.com/primer/octicons", - "commitHash": "d120bf97bc9a12fb415f69fedaf31fe58427ca56" - } - }, - "license": "MIT", - "version": "8.3.0" + "license": "MIT and Creative Commons Attribution 4.0", + "version": "0.0.1" }, { "component": { diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index e6658a6d425..5defc86cf5d 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -37,7 +37,9 @@ "launch.json", "tasks.json", "keybindings.json", - "extensions.json" + "extensions.json", + "argv.json", + "profiles.json" ] } ], @@ -71,8 +73,8 @@ "url": "vscode://schemas/workspaceConfig" }, { - "fileMatch": "%APP_SETTINGS_HOME%/locale.json", - "url": "vscode://schemas/locale" + "fileMatch": "**/argv.json", + "url": "vscode://schemas/argv" }, { "fileMatch": "/.vscode/settings.json", @@ -105,10 +107,14 @@ { "fileMatch": "/.devcontainer.json", "url": "./schemas/devContainer.schema.json" + }, + { + "fileMatch": "%APP_SETTINGS_HOME%/globalStorage/ms-vscode-remote.remote-containers/imageConfigs/*.json", + "url": "./schemas/attachContainer.schema.json" } ] }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" } } diff --git a/extensions/configuration-editing/schemas/attachContainer.schema.json b/extensions/configuration-editing/schemas/attachContainer.schema.json new file mode 100644 index 00000000000..5f3d28abb89 --- /dev/null +++ b/extensions/configuration-editing/schemas/attachContainer.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/schema#", + "description": "Configures an attached to container", + "allowComments": true, + "type": "object", + "definitions": { + "attachContainer": { + "type": "object", + "properties": { + "workspaceFolder": { + "type": "string", + "description": "The path of the workspace folder inside the container." + }, + "forwardPorts": { + "type": "array", + "description": "Ports that are forwarded from the container to the local machine.", + "items": { + "type": "integer" + } + }, + "extensions": { + "type": "array", + "description": "An array of extensions that should be installed into the container.", + "items": { + "type": "string" + } + } + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/attachContainer" + } + ] +} diff --git a/extensions/configuration-editing/schemas/devContainer.schema.json b/extensions/configuration-editing/schemas/devContainer.schema.json index c24857720e6..1358c74f2d2 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.json @@ -68,7 +68,7 @@ "none", "stopContainer" ], - "description": "Action to take when VS Code is shutting down. The default is to stop the container." + "description": "Action to take when the VS Code window is closed. The default is to stop the container." }, "overrideCommand": { "type": "boolean", @@ -146,7 +146,7 @@ "none", "stopCompose" ], - "description": "Action to take when VS Code is shutting down. The default is to stop the containers." + "description": "Action to take when the VS Code window is closed. The default is to stop the containers." } }, "required": [ diff --git a/extensions/configuration-editing/src/extension.ts b/extensions/configuration-editing/src/extension.ts index aff533d86d9..72e2fcf627f 100644 --- a/extensions/configuration-editing/src/extension.ts +++ b/extensions/configuration-editing/src/extension.ts @@ -75,7 +75,8 @@ function registerVariableCompletions(pattern: string): vscode.Disposable { { 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") } + { label: 'fileBasenameNoExtension', detail: localize('fileBasenameNoExtension', "The current opened file's basename with no file extension") }, + { label: 'defaultBuildTask', detail: localize('defaultBuildTask', "The name of the default build task. If there is not a single default build task then a quick pick is shown to choose the build task.") }, ].map(variable => ({ label: '${' + variable.label + '}', range: new vscode.Range(startPosition, position), diff --git a/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock index 39ad2337314..d5aafed1189 100644 --- a/extensions/configuration-editing/yarn.lock +++ b/extensions/configuration-editing/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== jsonc-parser@^2.1.1: version "2.1.1" diff --git a/extensions/cpp/cgmanifest.json b/extensions/cpp/cgmanifest.json index 1ee3eb1b31c..3dc984e58c2 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": "dd94b6a93799f2bce7e29b2515d96553e34574b0" + "commitHash": "d937b80a19706d518e5fe52357d7c50d34a26e60" } }, "license": "MIT", - "version": "1.14.6", + "version": "1.14.11", "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." }, { @@ -42,4 +42,4 @@ } ], "version": 1 -} +} \ No newline at end of file diff --git a/extensions/cpp/syntaxes/c.tmLanguage.json b/extensions/cpp/syntaxes/c.tmLanguage.json index 1e266e28c71..d8c4dca256b 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/dd94b6a93799f2bce7e29b2515d96553e34574b0", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/d937b80a19706d518e5fe52357d7c50d34a26e60", "name": "C", "scopeName": "source.c", "patterns": [ @@ -363,7 +363,7 @@ }, { "name": "meta.function.c", - "begin": "(?(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", - "captures": { - "1": { - "name": "comment.block.c punctuation.definition.comment.begin.c" - }, - "2": { - "name": "comment.block.c" - }, - "3": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.c punctuation.definition.comment.end.c" - }, - { - "match": "\\*", - "name": "comment.block.c" - } - ] - } - } - }, - "default_statement": { - "name": "meta.conditional.case.c", - "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?))((?:(?:[a-zA-Z_][a-zA-Z_0-9]*)\\s*(?:(?:\\.)|(?:->)))*)\\s*([a-zA-Z_][a-zA-Z_0-9]*)(\\()", "beginCaptures": { "1": { - "patterns": [ - { - "include": "#inline_comment" - } - ] + "name": "variable.object.c" }, "2": { - "name": "comment.block.c punctuation.definition.comment.begin.c" + "name": "punctuation.separator.dot-access.c" }, "3": { - "name": "comment.block.c" + "name": "punctuation.separator.pointer-access.c" }, "4": { "patterns": [ { - "match": "\\*\\/", - "name": "comment.block.c punctuation.definition.comment.end.c" + "match": "\\.", + "name": "punctuation.separator.dot-access.c" }, { - "match": "\\*", - "name": "comment.block.c" + "match": "->", + "name": "punctuation.separator.pointer-access.c" + }, + { + "match": "[a-zA-Z_][a-zA-Z_0-9]*", + "name": "variable.object.c" + }, + { + "name": "everything.else.c", + "match": ".+" } ] }, "5": { - "name": "keyword.control.default.c" + "name": "entity.name.function.member.c" + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.c" } }, - "end": "(:)", + "end": "\\)", "endCaptures": { - "1": { - "name": "punctuation.separator.colon.case.default.c" + "0": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.c" } }, "patterns": [ { - "include": "#evaluation_context" + "include": "#function-call-innards" + } + ] + }, + "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" + }, + "block": { + "patterns": [ + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.c" + } + }, + "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.c" + } + }, + "name": "meta.block.c", + "patterns": [ + { + "include": "#block_innards" + } + ] + } + ] + }, + "block_innards": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled-block" }, { - "include": "#c_conditional_context" + "include": "#preprocessor-rule-disabled-block" + }, + { + "include": "#preprocessor-rule-conditional-block" + }, + { + "include": "#method_access" + }, + { + "include": "#member_access" + }, + { + "include": "#c_function_call" + }, + { + "name": "meta.initialization.c", + "begin": "(?x)\n(?:\n (?:\n\t(?=\\s)(?=+!]+ | \\(\\) | \\[\\]))\n)\n\\s*(\\() # opening bracket", + "beginCaptures": { + "1": { + "name": "variable.other.c" + }, + "2": { + "name": "punctuation.section.parens.begin.bracket.round.initialization.c" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.initialization.c" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.c" + } + }, + "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.c" + } + }, + "patterns": [ + { + "include": "#block_innards" + } + ] + }, + { + "include": "#parens-block" + }, + { + "include": "$base" + } + ] + }, + "c_conditional_context": { + "patterns": [ + { + "include": "$self" + }, + { + "include": "#block_innards" + } + ] + }, + "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.c", + "patterns": [ + { + "include": "#function-call-innards" } ] }, @@ -530,101 +629,324 @@ } ] }, - "switch_statement": { - "name": "meta.block.switch.c", - "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=[;>\\[\\]=]))", + "comments": { "patterns": [ { - "name": "meta.head.switch.c", - "begin": "\\G ?", - "end": "((?:\\{|<%|\\?\\?<|(?=;)))", - "endCaptures": { + "name": "comment.line.double-slash.documentation.c", + "begin": "(?:^)(?>\\s*)(\\/\\/[!\\/]+)", + "beginCaptures": { "1": { - "name": "punctuation.section.block.begin.bracket.curly.switch.c" + "name": "punctuation.definition.comment.documentation.c" } }, + "end": "(?<=\\n)(?|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.italic.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.bold.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.inline.raw.string.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "variable.parameter.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc" } ] }, { - "name": "meta.body.switch.c", - "begin": "(?<=\\{|<%|\\?\\?<)", - "end": "(\\}|%>|\\?\\?>)", + "match": "(\\/\\*[!*]+(?=\\s))(.+)([!*]*\\*\\/)", + "captures": { + "1": { + "name": "punctuation.definition.comment.begin.documentation.c" + }, + "2": { + "patterns": [ + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.italic.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.bold.doxygen.c" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.inline.raw.string.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "variable.parameter.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc" + } + ] + }, + "3": { + "name": "punctuation.definition.comment.end.documentation.c" + } + }, + "name": "comment.block.documentation.c" + }, + { + "name": "comment.block.documentation.c", + "begin": "((?>\\s*)\\/\\*[!*]+(?:(?:\\n|$)|(?=\\s)))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.documentation.c" + } + }, + "end": "([!*]*\\*\\/)", "endCaptures": { "1": { - "name": "punctuation.section.block.end.bracket.curly.switch.c" + "name": "punctuation.definition.comment.end.documentation.c" } }, "patterns": [ { - "include": "#default_statement" + "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" }, { - "include": "#case_statement" + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.italic.doxygen.c" + } + } }, { - "include": "$self" + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.bold.doxygen.c" + } + } }, { - "include": "#block_innards" + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "markup.inline.raw.string.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.c" + }, + "2": { + "name": "variable.parameter.c" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.c" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc" } ] }, { - "name": "meta.tail.switch.c", - "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", + "match": "^\\/\\* =(\\s*.*?)\\s*= \\*\\/$\\n?", + "captures": { + "1": { + "name": "meta.toc-list.banner.block.c" + } + }, + "name": "comment.block.banner.c" + }, + { + "name": "comment.block.c", + "begin": "(\\/\\*)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.c" + } + }, + "end": "(\\*\\/)", + "endCaptures": { + "1": { + "name": "punctuation.definition.comment.end.c" + } + } + }, + { + "match": "^\\/\\/ =(\\s*.*?)\\s*=$\\n?", + "captures": { + "1": { + "name": "meta.toc-list.banner.line.c" + } + }, + "name": "comment.line.banner.c" + }, + { + "begin": "((?:^[ \\t]+)?)(?=\\/\\/)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.c" + } + }, + "end": "(?!\\G)", "patterns": [ { - "include": "$self" + "name": "comment.line.double-slash.c", + "begin": "(\\/\\/)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.c" + } + }, + "end": "(?=\\n)", + "patterns": [ + { + "include": "#line_continuation_character" + } + ] } ] } ] }, - "switch_conditional_parentheses": { - "name": "meta.conditional.switch.c", - "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "default_statement": { + "name": "meta.conditional.case.c", + "begin": "((?:(?:(?>\\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.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" - } - }, + "disabled": { + "begin": "^\\s*#\\s*if(n?def)?\\b.*$", + "end": "^\\s*#\\s*endif\\b", "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": "#disabled" }, { - "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": "$self" - }, - { - "include": "#block_innards" + "include": "#pragma-mark" } ] }, @@ -781,8 +1014,170 @@ } ] }, + "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.c" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.c" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.c" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.c" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.c" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "include": "#block_innards" + } + ] + }, + "function-innards": { + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#storage_types" + }, + { + "include": "#operators" + }, + { + "include": "#vararg_ellipses" + }, + { + "name": "meta.function.definition.parameters.c", + "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.c" + }, + "2": { + "name": "punctuation.section.parameters.begin.bracket.round.c" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parameters.end.bracket.round.c" + } + }, + "patterns": [ + { + "include": "#probably_a_parameter" + }, + { + "include": "#function-innards" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.c" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.c" + } + }, + "patterns": [ + { + "include": "#function-innards" + } + ] + }, + { + "include": "$base" + } + ] + }, + "inline_comment": { + "match": "(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", + "captures": { + "1": { + "name": "comment.block.c punctuation.definition.comment.begin.c" + }, + "2": { + "name": "comment.block.c" + }, + "3": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.c punctuation.definition.comment.end.c" + }, + { + "match": "\\*", + "name": "comment.block.c" + } + ] + } + } + }, + "line_continuation_character": { + "patterns": [ + { + "match": "(\\\\)\\n", + "captures": { + "1": { + "name": "constant.character.escape.line-continuation.c" + } + } + } + ] + }, "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(?!\\())", + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:atomic_uint_least64_t|atomic_uint_least16_t|atomic_uint_least32_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_fast64_t|atomic_uint_fast32_t|atomic_int_least64_t|atomic_int_least32_t|pthread_rwlockattr_t|atomic_uint_fast16_t|pthread_mutexattr_t|atomic_int_fast16_t|atomic_uint_fast8_t|atomic_int_fast64_t|atomic_int_least8_t|atomic_int_fast32_t|atomic_int_fast8_t|pthread_condattr_t|atomic_uintptr_t|atomic_ptrdiff_t|pthread_rwlock_t|atomic_uintmax_t|pthread_mutex_t|atomic_intmax_t|atomic_intptr_t|atomic_char32_t|atomic_char16_t|pthread_attr_t|atomic_wchar_t|uint_least64_t|uint_least32_t|uint_least16_t|pthread_cond_t|pthread_once_t|uint_fast64_t|uint_fast16_t|atomic_size_t|uint_least8_t|int_least64_t|int_least32_t|int_least16_t|pthread_key_t|atomic_ullong|atomic_ushort|uint_fast32_t|atomic_schar|atomic_short|uint_fast8_t|int_fast64_t|int_fast32_t|int_fast16_t|atomic_ulong|atomic_llong|int_least8_t|atomic_uchar|memory_order|suseconds_t|int_fast8_t|atomic_bool|atomic_char|atomic_uint|atomic_long|atomic_int|useconds_t|_Imaginary|uintptr_t|pthread_t|in_addr_t|blksize_t|in_port_t|uintmax_t|uintmax_t|blkcnt_t|uint16_t|unsigned|_Complex|uint32_t|intptr_t|intmax_t|intmax_t|uint64_t|u_quad_t|int64_t|int32_t|ssize_t|caddr_t|clock_t|uint8_t|u_short|swblk_t|segsz_t|int16_t|fixpt_t|daddr_t|nlink_t|qaddr_t|size_t|time_t|mode_t|signed|quad_t|ushort|u_long|u_char|double|int8_t|ino_t|uid_t|pid_t|_Bool|float|dev_t|div_t|short|gid_t|off_t|u_int|key_t|id_t|uint|long|void|char|bool|id_t|int)\\b)[a-zA-Z_]\\w*\\b(?!\\())", "captures": { "1": { "name": "variable.other.object.access.c" @@ -878,22 +1273,6 @@ } ] }, - "predefined_macros": { - "patterns": [ - { - "match": "\\b(__cplusplus|__DATE__|__FILE__|__LINE__|__STDC__|__STDC_HOSTED__|__STDC_NO_COMPLEX__|__STDC_VERSION__|__STDCPP_THREADS__|__TIME__|NDEBUG|__OBJC__|__ASSEMBLER__|__ATOM__|__AVX__|__AVX2__|_CHAR_UNSIGNED|__CLR_VER|_CONTROL_FLOW_GUARD|__COUNTER__|__cplusplus_cli|__cplusplus_winrt|_CPPRTTI|_CPPUNWIND|_DEBUG|_DLL|__FUNCDNAME__|__FUNCSIG__|__FUNCTION__|_INTEGRAL_MAX_BITS|__INTELLISENSE__|_ISO_VOLATILE|_KERNEL_MODE|_M_AMD64|_M_ARM|_M_ARM_ARMV7VE|_M_ARM_FP|_M_ARM64|_M_CEE|_M_CEE_PURE|_M_CEE_SAFE|_M_FP_EXCEPT|_M_FP_FAST|_M_FP_PRECISE|_M_FP_STRICT|_M_IX86|_M_IX86_FP|_M_X64|_MANAGED|_MSC_BUILD|_MSC_EXTENSIONS|_MSC_FULL_VER|_MSC_VER|_MSVC_LANG|__MSVC_RUNTIME_CHECKS|_MT|_NATIVE_WCHAR_T_DEFINED|_OPENMP|_PREFAST|__TIMESTAMP__|_VC_NO_DEFAULTLIB|_WCHAR_T_DEFINED|_WIN32|_WIN64|_WINRT_DLL|_ATL_VER|_MFC_VER|__GFORTRAN__|__GNUC__|__GNUC_MINOR__|__GNUC_PATCHLEVEL__|__GNUG__|__STRICT_ANSI__|__BASE_FILE__|__INCLUDE_LEVEL__|__ELF__|__VERSION__|__OPTIMIZE__|__OPTIMIZE_SIZE__|__NO_INLINE__|__GNUC_STDC_INLINE__|__CHAR_UNSIGNED__|__WCHAR_UNSIGNED__|__REGISTER_PREFIX__|__REGISTER_PREFIX__|__SIZE_TYPE__|__PTRDIFF_TYPE__|__WCHAR_TYPE__|__WINT_TYPE__|__INTMAX_TYPE__|__UINTMAX_TYPE__|__SIG_ATOMIC_TYPE__|__INT8_TYPE__|__INT16_TYPE__|__INT32_TYPE__|__INT64_TYPE__|__UINT8_TYPE__|__UINT16_TYPE__|__UINT32_TYPE__|__UINT64_TYPE__|__INT_LEAST8_TYPE__|__INT_LEAST16_TYPE__|__INT_LEAST32_TYPE__|__INT_LEAST64_TYPE__|__UINT_LEAST8_TYPE__|__UINT_LEAST16_TYPE__|__UINT_LEAST32_TYPE__|__UINT_LEAST64_TYPE__|__INT_FAST8_TYPE__|__INT_FAST16_TYPE__|__INT_FAST32_TYPE__|__INT_FAST64_TYPE__|__UINT_FAST8_TYPE__|__UINT_FAST16_TYPE__|__UINT_FAST32_TYPE__|__UINT_FAST64_TYPE__|__INTPTR_TYPE__|__UINTPTR_TYPE__|__CHAR_BIT__|__SCHAR_MAX__|__WCHAR_MAX__|__SHRT_MAX__|__INT_MAX__|__LONG_MAX__|__LONG_LONG_MAX__|__WINT_MAX__|__SIZE_MAX__|__PTRDIFF_MAX__|__INTMAX_MAX__|__UINTMAX_MAX__|__SIG_ATOMIC_MAX__|__INT8_MAX__|__INT16_MAX__|__INT32_MAX__|__INT64_MAX__|__UINT8_MAX__|__UINT16_MAX__|__UINT32_MAX__|__UINT64_MAX__|__INT_LEAST8_MAX__|__INT_LEAST16_MAX__|__INT_LEAST32_MAX__|__INT_LEAST64_MAX__|__UINT_LEAST8_MAX__|__UINT_LEAST16_MAX__|__UINT_LEAST32_MAX__|__UINT_LEAST64_MAX__|__INT_FAST8_MAX__|__INT_FAST16_MAX__|__INT_FAST32_MAX__|__INT_FAST64_MAX__|__UINT_FAST8_MAX__|__UINT_FAST16_MAX__|__UINT_FAST32_MAX__|__UINT_FAST64_MAX__|__INTPTR_MAX__|__UINTPTR_MAX__|__WCHAR_MIN__|__WINT_MIN__|__SIG_ATOMIC_MIN__|__SCHAR_WIDTH__|__SHRT_WIDTH__|__INT_WIDTH__|__LONG_WIDTH__|__LONG_LONG_WIDTH__|__PTRDIFF_WIDTH__|__SIG_ATOMIC_WIDTH__|__SIZE_WIDTH__|__WCHAR_WIDTH__|__WINT_WIDTH__|__INT_LEAST8_WIDTH__|__INT_LEAST16_WIDTH__|__INT_LEAST32_WIDTH__|__INT_LEAST64_WIDTH__|__INT_FAST8_WIDTH__|__INT_FAST16_WIDTH__|__INT_FAST32_WIDTH__|__INT_FAST64_WIDTH__|__INTPTR_WIDTH__|__INTMAX_WIDTH__|__SIZEOF_INT__|__SIZEOF_LONG__|__SIZEOF_LONG_LONG__|__SIZEOF_SHORT__|__SIZEOF_POINTER__|__SIZEOF_FLOAT__|__SIZEOF_DOUBLE__|__SIZEOF_LONG_DOUBLE__|__SIZEOF_SIZE_T__|__SIZEOF_WCHAR_T__|__SIZEOF_WINT_T__|__SIZEOF_PTRDIFF_T__|__BYTE_ORDER__|__ORDER_LITTLE_ENDIAN__|__ORDER_BIG_ENDIAN__|__ORDER_PDP_ENDIAN__|__FLOAT_WORD_ORDER__|__DEPRECATED|__EXCEPTIONS|__GXX_RTTI|__USING_SJLJ_EXCEPTIONS__|__GXX_EXPERIMENTAL_CXX0X__|__GXX_WEAK__|__NEXT_RUNTIME__|__LP64__|_LP64|__SSP__|__SSP_ALL__|__SSP_STRONG__|__SSP_EXPLICIT__|__SANITIZE_ADDRESS__|__SANITIZE_THREAD__|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16|__HAVE_SPECULATION_SAFE_VALUE|__GCC_HAVE_DWARF2_CFI_ASM|__FP_FAST_FMA|__FP_FAST_FMAF|__FP_FAST_FMAL|__FP_FAST_FMAF16|__FP_FAST_FMAF32|__FP_FAST_FMAF64|__FP_FAST_FMAF128|__FP_FAST_FMAF32X|__FP_FAST_FMAF64X|__FP_FAST_FMAF128X|__GCC_IEC_559|__GCC_IEC_559_COMPLEX|__NO_MATH_ERRNO__|__has_builtin|__has_feature|__has_extension|__has_cpp_attribute|__has_c_attribute|__has_attribute|__has_declspec_attribute|__is_identifier|__has_include|__has_include_next|__has_warning|__BASE_FILE__|__FILE_NAME__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__fp16|_Float16)\\b", - "captures": { - "1": { - "name": "entity.name.other.preprocessor.macro.predefined.$1.c" - } - } - }, - { - "match": "\\b__([A-Z_]+)__\\b", - "name": "entity.name.other.preprocessor.macro.predefined.probably.$1.c" - } - ] - }, "numbers": { "match": "(?\\s*)(\\/\\/[!\\/]+)(.*)", - "captures": { - "1": { - "name": "punctuation.definition.comment.documentation.c" - }, - "2": { - "patterns": [ - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.italic.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.bold.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.inline.raw.string.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "variable.parameter.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.c" - } - ] - } - }, - "name": "comment.line.double-slash.documentation.c" - }, - { - "match": "(\\/\\*[!*]+(?=\\s))(.+)([!*]*\\*\\/)", - "captures": { - "1": { - "name": "punctuation.definition.comment.begin.documentation.c" - }, - "2": { - "patterns": [ - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.italic.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.bold.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.inline.raw.string.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "variable.parameter.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.c" - } - ] - }, - "3": { - "name": "punctuation.definition.comment.end.documentation.c" - } - }, - "name": "comment.block.documentation.c" - }, - { - "name": "comment.block.documentation.c", - "begin": "((?>\\s*)\\/\\*[!*]+(?:(?:\\n|$)|(?=\\s)))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.begin.documentation.c" - } - }, - "end": "([!*]*\\*\\/)", - "endCaptures": { - "1": { - "name": "punctuation.definition.comment.end.documentation.c" - } - }, - "patterns": [ - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.italic.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.bold.doxygen.c" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "markup.inline.raw.string.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.c" - }, - "2": { - "name": "variable.parameter.c" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.c" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.c" - } - ] - }, - { - "match": "^\\/\\* =(\\s*.*?)\\s*= \\*\\/$\\n?", - "captures": { - "1": { - "name": "meta.toc-list.banner.block.c" - } - }, - "name": "comment.block.banner.c" - }, - { - "name": "comment.block.c", - "begin": "(\\/\\*)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.begin.c" - } - }, - "end": "(\\*\\/)", - "endCaptures": { - "1": { - "name": "punctuation.definition.comment.end.c" - } - } - }, - { - "match": "^\\/\\/ =(\\s*.*?)\\s*=$\\n?", - "captures": { - "1": { - "name": "meta.toc-list.banner.line.c" - } - }, - "name": "comment.line.banner.c" - }, - { - "begin": "((?:^[ \\t]+)?)(?=\\/\\/)", - "beginCaptures": { - "1": { - "name": "punctuation.whitespace.comment.leading.c" - } - }, - "end": "(?!\\G)", - "patterns": [ - { - "name": "comment.line.double-slash.c", - "begin": "(\\/\\/)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.c" - } - }, - "end": "(?=\\n)", - "patterns": [ - { - "include": "#line_continuation_character" - } - ] - } - ] - } - ] - }, - "probably_a_parameter": { - "match": "(?<=(?:[a-zA-Z_0-9] |[&*>\\]\\)]))\\s*([a-zA-Z_]\\w*)\\s*(?=(?:\\[\\]\\s*)?(?:,|\\)))", - "captures": { - "1": { - "name": "variable.parameter.probably.c" - } - } - }, - "access-method": { - "name": "meta.function-call.member.c", - "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.c" - }, - "2": { - "name": "punctuation.separator.dot-access.c" - }, - "3": { - "name": "punctuation.separator.pointer-access.c" - }, - "4": { - "patterns": [ - { - "match": "\\.", - "name": "punctuation.separator.dot-access.c" - }, - { - "match": "->", - "name": "punctuation.separator.pointer-access.c" - }, - { - "match": "[a-zA-Z_][a-zA-Z_0-9]*", - "name": "variable.object.c" - }, - { - "name": "everything.else.c", - "match": ".+" - } - ] - }, - "5": { - "name": "entity.name.function.member.c" - }, - "6": { - "name": "punctuation.section.arguments.begin.bracket.round.function.member.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.arguments.end.bracket.round.function.member.c" - } - }, - "patterns": [ - { - "include": "#function-call-innards" - } - ] - }, - "block": { - "patterns": [ - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.section.block.begin.bracket.curly.c" - } - }, - "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", - "endCaptures": { - "0": { - "name": "punctuation.section.block.end.bracket.curly.c" - } - }, - "name": "meta.block.c", - "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.c", - "begin": "(?x)\n(?:\n (?:\n\t(?=\\s)(?=+!]+ | \\(\\) | \\[\\]))\n)\n\\s*(\\() # opening bracket", - "beginCaptures": { - "1": { - "name": "variable.other.c" - }, - "2": { - "name": "punctuation.section.parens.begin.bracket.round.initialization.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.initialization.c" - } - }, - "patterns": [ - { - "include": "#function-call-innards" - } - ] - }, - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.section.block.begin.bracket.curly.c" - } - }, - "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", - "endCaptures": { - "0": { - "name": "punctuation.section.block.end.bracket.curly.c" - } - }, - "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.c", - "patterns": [ - { - "include": "#function-call-innards" - } - ] - }, - "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.c" - } - } - } - ] - }, - "parens": { - "name": "meta.parens.c", - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.section.parens.begin.bracket.round.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.c" - } - }, - "patterns": [ - { - "include": "$base" - } - ] - }, - "parens-block": { - "name": "meta.parens.block.c", - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.section.parens.begin.bracket.round.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.c" - } - }, - "patterns": [ - { - "include": "#block_innards" - }, - { - "match": "(?-mix:(?=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", + "end": "(?<=\\))(?!\\w)|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.c" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.c" + } + }, + "end": "(\\))|(?\\]\\)]))\\s*([a-zA-Z_]\\w*)\\s*(?=(?:\\[\\]\\s*)?(?:,|\\)))", + "captures": { + "1": { + "name": "variable.parameter.probably.c" + } + } + }, + "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": [ { - "include": "#vararg_ellipses" - }, - { - "begin": "{", + "name": "meta.static_assert.message.c", + "begin": "(,)\\s*(?=(?:L|u8|u|U\\s*\\\")?)", "beginCaptures": { - "0": { - "name": "punctuation.section.block.begin.bracket.curly.c" + "1": { + "name": "punctuation.separator.delimiter.comma.c" } }, - "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)|(?=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", - "end": "(?<=\\))(?!\\w)|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { "patterns": [ { - "include": "#preprocessor-rule-define-line-blocks" - }, - { - "include": "#preprocessor-rule-define-line-contents" + "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": "#preprocessor-rule-define-line-contents" + "include": "#evaluation_context" + }, + { + "include": "#c_conditional_context" } ] }, - "preprocessor-rule-define-line-functions": { + "switch_statement": { + "name": "meta.block.switch.c", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=[;>\\[\\]=]))", "patterns": [ { - "include": "#comments" - }, - { - "include": "#storage_types" - }, - { - "include": "#vararg_ellipses" - }, - { - "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": { + "name": "meta.head.switch.c", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { "1": { - "name": "entity.name.function.c" + "name": "punctuation.section.block.begin.bracket.curly.switch.c" + } + }, + "patterns": [ + { + "include": "#switch_conditional_parentheses" }, - "2": { - "name": "punctuation.section.arguments.begin.bracket.round.c" - } - }, - "end": "(\\))|(?|\\?\\?>)", "endCaptures": { "1": { - "name": "punctuation.section.parens.end.bracket.round.c" + "name": "punctuation.section.block.end.bracket.curly.switch.c" } }, "patterns": [ { - "include": "#preprocessor-rule-define-line-functions" + "include": "#default_statement" + }, + { + "include": "#case_statement" + }, + { + "include": "$self" + }, + { + "include": "#block_innards" } ] }, { - "include": "#preprocessor-rule-define-line-contents" + "name": "meta.tail.switch.c", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$self" + } + ] } ] }, - "function-innards": { - "patterns": [ - { - "include": "#comments" - }, - { - "include": "#storage_types" - }, - { - "include": "#operators" - }, - { - "include": "#vararg_ellipses" - }, - { - "name": "meta.function.definition.parameters.c", - "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.c" - }, - "2": { - "name": "punctuation.section.parameters.begin.bracket.round.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parameters.end.bracket.round.c" - } - }, - "patterns": [ - { - "include": "#probably_a_parameter" - }, - { - "include": "#function-innards" - } - ] - }, - { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.section.parens.begin.bracket.round.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.c" - } - }, - "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.c" - }, - "2": { - "name": "punctuation.section.arguments.begin.bracket.round.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.arguments.end.bracket.round.c" - } - }, - "patterns": [ - { - "include": "#function-call-innards" - } - ] - }, - { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.section.parens.begin.bracket.round.c" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.c" - } - }, - "patterns": [ - { - "include": "#function-call-innards" - } - ] - }, - { - "include": "#block_innards" - } - ] + "vararg_ellipses": { + "match": "(?(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", + "access_control_keywords": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(((?:protected|private|public))\\s*(:))", "captures": { "1": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "2": { - "name": "comment.block.cpp" + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, "3": { + "name": "comment.block.cpp" + }, + "4": { "patterns": [ { "match": "\\*\\/", @@ -114,271 +121,83 @@ "name": "comment.block.cpp" } ] + }, + "5": { + "name": "storage.type.modifier.access.control.$6.cpp" + }, + "7": { + "name": "punctuation.separator.colon.access.control.cpp" } } }, - "macro_name": { - "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*pragma\\s+mark)\\s+(.*)", - "captures": { + "alignas_operator": { + "contentName": "meta.arguments.operator.alignas.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { "1": { - "name": "keyword.control.directive.pragma.pragma-mark.cpp" + "name": "keyword.operator.functionlike.cpp keyword.operator.alignas.cpp" }, "2": { "patterns": [ @@ -406,20 +225,2838 @@ ] }, "6": { - "name": "punctuation.definition.directive.cpp" - }, - "7": { - "name": "entity.name.tag.pragma-mark.cpp" + "name": "punctuation.section.arguments.begin.bracket.round.operator.alignas.cpp" } }, - "name": "meta.preprocessor.pragma.cpp" + "end": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*pragma\\b)", + "alignof_operator": { + "contentName": "meta.arguments.operator.alignof.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", "beginCaptures": { "1": { - "name": "keyword.control.directive.pragma.cpp" + "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": "(\\))|(?=(?\\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": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))|((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\))))|(?={))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(final)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)((?>[^{]*)))?))", + "beginCaptures": { + "1": { + "name": "meta.head.class.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "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": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "9": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "10": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "11": { + "name": "comment.block.cpp" + }, + "12": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "13": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "14": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "15": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "16": { + "name": "comment.block.cpp" + }, + "17": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "18": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "19": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "20": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "21": { + "name": "comment.block.cpp" + }, + "22": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "23": { + "name": "entity.name.type.$3.cpp" + }, + "24": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "25": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "26": { + "name": "comment.block.cpp" + }, + "27": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "28": { + "name": "storage.type.modifier.final.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" + } + ] + }, + "37": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "38": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\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(?!override\\W|override\\$|final\\W|final\\$)((?\\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" + } + ] + } + } + }, + "comma": { + "match": ",", + "name": "punctuation.separator.delimiter.comma.cpp" + }, + "comma_in_template_argument": { + "match": ",", + "name": "punctuation.separator.delimiter.comma.template.argument.cpp" + }, + "comments": { + "patterns": [ + { + "name": "comment.line.double-slash.documentation.cpp", + "begin": "(?:^)(?>\\s*)(\\/\\/[!\\/]+)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.documentation.cpp" + } + }, + "end": "(?<=\\n)(?|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.italic.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.bold.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.inline.raw.string.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "variable.parameter.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc.cpp" + } + ] + }, + { + "match": "(\\/\\*[!*]+(?=\\s))(.+)([!*]*\\*\\/)", + "captures": { + "1": { + "name": "punctuation.definition.comment.begin.documentation.cpp" + }, + "2": { + "patterns": [ + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.italic.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.bold.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.inline.raw.string.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "variable.parameter.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc.cpp" + } + ] + }, + "3": { + "name": "punctuation.definition.comment.end.documentation.cpp" + } + }, + "name": "comment.block.documentation.cpp" + }, + { + "name": "comment.block.documentation.cpp", + "begin": "((?>\\s*)\\/\\*[!*]+(?:(?:\\n|$)|(?=\\s)))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.documentation.cpp" + } + }, + "end": "([!*]*\\*\\/)|(?=(?|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.italic.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.bold.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.inline.raw.string.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "variable.parameter.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc.cpp" + } + ] + }, + { + "include": "#emacs_file_banner" + }, + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#invalid_comment_end" + } + ] + }, + "constructor_inline": { + "name": "meta.function.definition.special.constructor.cpp", + "begin": "(^((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:constexpr|explicit|mutable|virtual|inline|friend)((?:(?:(?>\\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)))(?:(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": "(?=\\{)|(?=(?(?:(?>[^<>]*)\\g<3>?)+)>)\\s*)?(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.call.initializer.cpp" + }, + "2": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "4": { + "name": "punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp" + } + }, + "end": "(\\))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\16((?:(?:(?>\\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": "(?=\\{)|(?=(?(?:(?>[^<>]*)\\g<3>?)+)>)\\s*)?(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.call.initializer.cpp" + }, + "2": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "4": { + "name": "punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp" + } + }, + "end": "(\\))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", + "beginCaptures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?\\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": [ + { + "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": "(\\))|(?=(?\\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": [ + { + "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": "(\\))|(?=(?\\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)))((?:(?:constexpr|explicit|mutable|virtual|inline|friend)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*)(~(?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?\\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": "(\\))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\16((?:(?:(?>\\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": "(\\))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?:error|warning)))\\b\\s*", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.diagnostic.$7.cpp" }, "2": { "patterns": [ @@ -452,26 +3089,2253 @@ }, "end": "(?[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*(?:\\n|$)))|(^\\s*((\\/\\*)\\s*?((?>[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*\\*\\/)))", + "captures": { + "1": { + "name": "meta.toc-list.banner.double-slash.cpp" + }, + "2": { + "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.banner.cpp" + }, + "7": { + "name": "punctuation.definition.comment.cpp" + }, + "8": { + "name": "meta.banner.character.cpp" + } + } + }, + "empty_square_brackets": { + "name": "storage.modifier.array.bracket.square.cpp", + "match": "(?-mix:(?-mix:(?(?:(?>[^<>]*)\\g<15>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?(::))?\\s*((?|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\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(?!override\\W|override\\$|final\\W|final\\$)((?\\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" + } + ] + } + } + }, + "enumerator_list": { + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\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*(;)|(;))|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?(?:(?>[^<>]*)\\g<12>?)+)>)\\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)))(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_call_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.function.call.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": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "13": { + "name": "punctuation.section.arguments.begin.bracket.round.function.call.cpp" + } + }, + "end": "(\\))|(?=(?))((?:(?:(?>\\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)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\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)))((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\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": { + "patterns": [ + { + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))", + "captures": { + "1": { + "name": "storage.modifier.$1.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" + } + ] + } + } + } + ] + }, + "12": { + "name": "storage.modifier.$1.cpp" + }, + "13": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "14": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "15": { + "name": "comment.block.cpp" + }, + "16": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "17": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "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" + } + ] + }, + "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": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "54": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "55": { + "name": "comment.block.cpp" + }, + "56": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "57": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "58": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "59": { + "name": "comment.block.cpp" + }, + "60": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "61": { + "name": "storage.type.modifier.calling-convention.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": "#scope_resolution_function_definition_inner_generated" + } + ] + }, + "67": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" + }, + "69": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "71": { + "name": "entity.name.function.definition.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" + } + ] + } + }, + "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" + } + ] + }, + "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" + } + ] + }, + "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": { + "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" + }, + "42": { + "name": "punctuation.definition.function.pointer.dereference.cpp" + }, + "43": { + "name": "variable.other.definition.pointer.function.cpp" + }, + "44": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "45": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "46": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "47": { + "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" + }, + "48": { + "name": "punctuation.section.parameters.begin.bracket.round.function.pointer.cpp" + } + }, + "end": "(\\))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" + } + ] + }, + "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" + } + ] + }, + "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": { + "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" + }, + "42": { + "name": "punctuation.definition.function.pointer.dereference.cpp" + }, + "43": { + "name": "variable.parameter.pointer.function.cpp" + }, + "44": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "45": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "46": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "47": { + "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" + }, + "48": { + "name": "punctuation.section.parameters.begin.bracket.round.function.pointer.cpp" + } + }, + "end": "(\\))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()|(?=(?\\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": "keyword.control.goto.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.label.call.cpp" + } + } + }, "include": { - "match": "(?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((#)\\s*((?:(?:include|include_next)|import))\\b)\\s*(?:(?:(?:((<)[^>]*(>?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/)))|((\\\")[^\\\"]*(\\\"?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/))))|((?:[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|$)|(?=\\/\\/))))|((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/)))", + "match": "(?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((#)\\s*((?:include|include_next))\\b)\\s*(?:(?:(?:((<)[^>]*(>?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/)))|((\\\")[^\\\"]*(\\\"?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/))))|(((?:(?:(?>\\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+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=(?:\\/\\/|;)))))|((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=(?:\\/\\/|;))))", "captures": { "1": { "patterns": [ @@ -624,10 +5488,435 @@ "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" + } + ] } }, "name": "meta.preprocessor.include.cpp" }, + "inheritance_context": { + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.comma.inheritance.cpp" + }, + { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))", + "captures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", + "captures": { + "1": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "2": { + "name": "comment.block.cpp" + }, + "3": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "invalid_comment_end": { + "match": "\\*\\/", + "name": "invalid.illegal.unexpected.punctuation.definition.comment.end.cpp" + }, + "label": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\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": "entity.name.label.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.separator.label.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": "(?<=})|(?=(?)((?:.+?(?=\\{|$))?)", + "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": "(\\})|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*line\\b)", @@ -677,203 +5966,24 @@ } ] }, - "diagnostic": { - "name": "meta.preprocessor.diagnostic.$reference(directive).cpp", - "begin": "((?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?:error|warning)))\\b\\s*", + "line_comment": { + "name": "comment.line.double-slash.cpp", + "begin": "\\s*+(\\/\\/)", "beginCaptures": { "1": { - "name": "keyword.control.directive.diagnostic.$7.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.definition.directive.cpp" + "name": "punctuation.definition.comment.cpp" } }, - "end": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*undef\\b)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))#define.*(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?:(?:ifndef|ifdef)|if)))", - "beginCaptures": { + "macro_context": { + "patterns": [ + { + "include": "source.cpp.embedded.macro" + } + ] + }, + "macro_name": { + "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(?!uint_least64_t[^(?-mix:\\w)]|uint_least16_t[^(?-mix:\\w)]|uint_least32_t[^(?-mix:\\w)]|int_least16_t[^(?-mix:\\w)]|uint_fast64_t[^(?-mix:\\w)]|uint_fast32_t[^(?-mix:\\w)]|uint_fast16_t[^(?-mix:\\w)]|uint_least8_t[^(?-mix:\\w)]|int_least64_t[^(?-mix:\\w)]|int_least32_t[^(?-mix:\\w)]|int_fast32_t[^(?-mix:\\w)]|int_fast16_t[^(?-mix:\\w)]|int_least8_t[^(?-mix:\\w)]|uint_fast8_t[^(?-mix:\\w)]|int_fast64_t[^(?-mix:\\w)]|int_fast8_t[^(?-mix:\\w)]|suseconds_t[^(?-mix:\\w)]|useconds_t[^(?-mix:\\w)]|in_addr_t[^(?-mix:\\w)]|uintmax_t[^(?-mix:\\w)]|uintmax_t[^(?-mix:\\w)]|uintptr_t[^(?-mix:\\w)]|blksize_t[^(?-mix:\\w)]|in_port_t[^(?-mix:\\w)]|intmax_t[^(?-mix:\\w)]|unsigned[^(?-mix:\\w)]|blkcnt_t[^(?-mix:\\w)]|uint32_t[^(?-mix:\\w)]|u_quad_t[^(?-mix:\\w)]|uint16_t[^(?-mix:\\w)]|intmax_t[^(?-mix:\\w)]|uint64_t[^(?-mix:\\w)]|intptr_t[^(?-mix:\\w)]|swblk_t[^(?-mix:\\w)]|wchar_t[^(?-mix:\\w)]|u_short[^(?-mix:\\w)]|qaddr_t[^(?-mix:\\w)]|caddr_t[^(?-mix:\\w)]|daddr_t[^(?-mix:\\w)]|fixpt_t[^(?-mix:\\w)]|nlink_t[^(?-mix:\\w)]|segsz_t[^(?-mix:\\w)]|clock_t[^(?-mix:\\w)]|ssize_t[^(?-mix:\\w)]|int16_t[^(?-mix:\\w)]|int32_t[^(?-mix:\\w)]|int64_t[^(?-mix:\\w)]|uint8_t[^(?-mix:\\w)]|int8_t[^(?-mix:\\w)]|mode_t[^(?-mix:\\w)]|quad_t[^(?-mix:\\w)]|ushort[^(?-mix:\\w)]|u_long[^(?-mix:\\w)]|u_char[^(?-mix:\\w)]|double[^(?-mix:\\w)]|size_t[^(?-mix:\\w)]|signed[^(?-mix:\\w)]|time_t[^(?-mix:\\w)]|key_t[^(?-mix:\\w)]|ino_t[^(?-mix:\\w)]|gid_t[^(?-mix:\\w)]|dev_t[^(?-mix:\\w)]|div_t[^(?-mix:\\w)]|float[^(?-mix:\\w)]|u_int[^(?-mix:\\w)]|uid_t[^(?-mix:\\w)]|short[^(?-mix:\\w)]|off_t[^(?-mix:\\w)]|pid_t[^(?-mix:\\w)]|id_t[^(?-mix:\\w)]|bool[^(?-mix:\\w)]|char[^(?-mix:\\w)]|id_t[^(?-mix:\\w)]|uint[^(?-mix:\\w)]|void[^(?-mix:\\w)]|long[^(?-mix:\\w)]|auto[^(?-mix:\\w)]|int[^(?-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": { - "name": "keyword.control.directive.conditional.$7.cpp" - }, - "2": { "patterns": [ { "include": "#inline_comment" } ] }, - "3": { + "2": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "4": { + "3": { "name": "comment.block.cpp" }, - "5": { + "4": { "patterns": [ { "match": "\\*\\/", @@ -991,97 +6109,321 @@ } ] }, + "5": { + "name": "variable.language.this.cpp" + }, "6": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?:^)(?!\\s*+#\\s*(?:else|endif))|(?=(?|->\\*))\\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" } ] }, - { - "include": "$self" + "10": { + "name": "variable.other.property.cpp" } - ] + } }, - "preprocessor_conditional_context": { - "patterns": [ - { - "include": "#preprocessor_conditional_defined" - }, - { - "include": "#comments" - }, - { - "include": "#language_constants" - }, - { - "include": "#string_context_c" - }, - { - "include": "#preprocessor_number_literal" - }, - { - "include": "#operators" - }, - { - "include": "#predefined_macros" - }, - { - "include": "#macro_name" - }, - { - "include": "#line_continuation_character" - } - ] - }, - "preprocessor_conditional_defined": { - "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(delete)\\s*(\\[\\])|(delete))|(new))(?!\\w))", + "captures": { "1": { - "name": "keyword.control.directive.conditional.defined.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "2": { - "name": "punctuation.section.parens.control.defined.cpp" + "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.operator.wordlike.cpp" + }, + "6": { + "name": "keyword.operator.delete.array.cpp" + }, + "7": { + "name": "keyword.operator.delete.array.bracket.cpp" + }, + "8": { + "name": "keyword.operator.delete.cpp" + }, + "9": { + "name": "keyword.operator.new.cpp" } - }, - "end": "((?:\\)|(?\\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": { - "name": "punctuation.section.parens.begin.bracket.round.cpp" + "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": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((import))\\s*(?:(?:(?:((<)[^>]*(>?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/)))|((\\\")[^\\\"]*(\\\"?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/))))|(((?:(?:(?>\\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+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=(?:\\/\\/|;)))))|((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=(?:\\/\\/|;))))\\s*(;?)", "captures": { "1": { "patterns": [ @@ -1109,674 +6451,434 @@ ] }, "5": { - "name": "punctuation.definition.directive.cpp" + "name": "keyword.control.directive.import.cpp" + }, + "7": { + "name": "string.quoted.other.lt-gt.include.cpp" + }, + "8": { + "name": "punctuation.definition.string.begin.cpp" + }, + "9": { + "name": "punctuation.definition.string.end.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": "string.quoted.double.include.cpp" + }, + "15": { + "name": "punctuation.definition.string.begin.cpp" + }, + "16": { + "name": "punctuation.definition.string.end.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.other.preprocessor.macro.include.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.terminator.statement.cpp" } }, - "name": "keyword.control.directive.$6.cpp" + "name": "meta.preprocessor.import.cpp" }, - "semicolon": { - "match": ";", - "name": "punctuation.terminator.statement.cpp" - }, - "comma": { - "match": ",", - "name": "punctuation.separator.delimiter.comma.cpp" - }, - "assignment_operator": { - "match": "\\=", - "name": "keyword.operator.assignment.cpp" - }, - "ever_present_context": { - "patterns": [ - { - "include": "#pragma_mark" - }, - { - "include": "#pragma" - }, - { - "include": "#include" - }, - { - "include": "#line" - }, - { - "include": "#diagnostic" - }, - { - "include": "#undef" - }, - { - "include": "#preprocessor_conditional_range" - }, - { - "include": "#single_line_macro" - }, - { - "include": "#macro" - }, - { - "include": "#preprocessor_conditional_standalone" - }, - { - "include": "#macro_argument" - }, - { - "include": "#comments" - }, - { - "include": "#line_continuation_character" + "ms_attributes": { + "name": "support.other.attribute.cpp", + "begin": "(__declspec\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.attribute.begin.cpp" } - ] - }, - "function_body_context": { - "patterns": [ - { - "include": "#ever_present_context" - }, - { - "include": "#using_namespace" - }, - { - "include": "#type_alias" - }, - { - "include": "#using_name" - }, - { - "include": "#namespace_alias" - }, - { - "include": "#typedef_class" - }, - { - "include": "#typedef_struct" - }, - { - "include": "#typedef_union" - }, - { - "include": "#typedef_keyword" - }, - { - "include": "#standard_declares" - }, - { - "include": "#class_block" - }, - { - "include": "#struct_block" - }, - { - "include": "#union_block" - }, - { - "include": "#enum_block" - }, - { - "include": "#access_control_keywords" - }, - { - "include": "#block" - }, - { - "include": "#static_assert" - }, - { - "include": "#assembly" - }, - { - "include": "#function_pointer" - }, - { - "include": "#switch_statement" - }, - { - "include": "#goto_statement" - }, - { - "include": "#evaluation_context" - }, - { - "include": "#label" + }, + "end": "(\\))|(?=(?(?:(?>[^<>]*)\\g<9>?)+)>)\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:(?>[^<>]*)\\g<5>?)+)>)\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\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": "(\\))|(?=(?[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*(?:\\n|$)))|(^\\s*((\\/\\*)\\s*?((?>[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*\\*\\/)))", + "non_primitive_types": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s*)(\\/\\/[!\\/]+)(.*)", - "captures": { - "1": { - "name": "punctuation.definition.comment.documentation.cpp" - }, - "2": { - "patterns": [ - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.italic.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.bold.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.inline.raw.string.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "variable.parameter.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc.cpp" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.cpp" - } - ] - } - }, - "name": "comment.line.double-slash.documentation.cpp" - }, - { - "match": "(\\/\\*[!*]+(?=\\s))(.+)([!*]*\\*\\/)", - "captures": { - "1": { - "name": "punctuation.definition.comment.begin.documentation.cpp" - }, - "2": { - "patterns": [ - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.italic.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.bold.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.inline.raw.string.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "variable.parameter.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc.cpp" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.cpp" - } - ] - }, - "3": { - "name": "punctuation.definition.comment.end.documentation.cpp" - } - }, - "name": "comment.block.documentation.cpp" - }, - { - "name": "comment.block.documentation.cpp", - "begin": "((?>\\s*)\\/\\*[!*]+(?:(?:\\n|$)|(?=\\s)))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.begin.documentation.cpp" - } - }, - "end": "([!*]*\\*\\/)|(?=(?|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.italic.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.bold.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.inline.raw.string.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "variable.parameter.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc.cpp" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.cpp" + "include": "#inline_comment" } ] }, - { - "include": "#emacs_file_banner" + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - { - "include": "#block_comment" + "3": { + "name": "comment.block.cpp" }, - { - "include": "#line_comment" + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] }, - { - "include": "#invalid_comment_end" + "5": { + "name": "storage.type.cpp storage.type.built-in.cpp" } - ] + } }, "number_literal": { "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\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": [ - { - "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": "(\\))|(?=(?\\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": [ - { - "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": "(\\))|(?=(?\\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)))(((?:private|protected|public))\\s*(:))", - "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": "storage.type.modifier.access.control.$6.cpp" - }, - "7": { - "name": "punctuation.separator.colon.access.control.cpp" - } - } - }, - "exception_keywords": { - "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)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(delete)\\s*(\\[\\])|(delete))|(new))(?!\\w))", - "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": "keyword.operator.wordlike.cpp" - }, - "6": { - "name": "keyword.operator.delete.array.cpp" - }, - "7": { - "name": "keyword.operator.delete.array.bracket.cpp" - }, - "8": { - "name": "keyword.operator.delete.cpp" - }, - "9": { - "name": "keyword.operator.new.cpp" - } - } - }, - "control_flow_keywords": { - "match": "((?:(?:(?>\\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}))*)", - "captures": { - "1": { - "name": "keyword.control.goto.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.label.call.cpp" - } - } - }, - "label": { - "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\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": "entity.name.label.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.separator.label.cpp" - } - } - }, - "default_statement": { - "name": "meta.conditional.case.cpp", - "begin": "((?:(?:(?>\\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": { - "name": "punctuation.section.parens.begin.bracket.round.conditional.switch.cpp" - } - }, - "end": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?(?:(?>[^<>]*)\\g<1>?)+)>)\\s*", - "captures": { - "0": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "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*$)", - "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": "#template_definition_context" - } - ] - }, - "4": { - "name": "punctuation.section.angle-brackets.end.template.definition.cpp" - } - } - }, - "template_definition": { - "name": "meta.template.definition.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": [ - { - "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": [ - { - "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" - } - ] - }, - "7": { - "name": "entity.name.type.template.cpp" - }, - "8": { - "name": "storage.type.template.cpp" - }, - "9": { - "name": "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": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" - } - } - }, - "scope_resolution_template_call": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_template_call_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_template_call_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_template_call_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.template.call.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" - } - } - }, - "scope_resolution_template_definition": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_template_definition_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_template_definition_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_template_definition_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.template.definition.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" - } - } - }, - "scope_resolution_function_call": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_function_call_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_function_call_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_function_call_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.function.call.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" - } - } - }, - "scope_resolution_function_definition": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_function_definition_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.function.definition.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" - } - } - }, - "scope_resolution_namespace_alias": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_namespace_alias_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_namespace_alias_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_namespace_alias_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.namespace.alias.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" - } - } - }, - "scope_resolution_namespace_using": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_namespace_using_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_namespace_using_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_namespace_using_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.namespace.using.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" - } - } - }, - "scope_resolution_namespace_block": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_namespace_block_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_namespace_block_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_namespace_block_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.namespace.block.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" - } - } - }, - "scope_resolution_parameter": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_parameter_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_parameter_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_parameter_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.parameter.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" - } - } - }, - "scope_resolution_function_definition_operator_overload": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_operator_overload_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_function_definition_operator_overload_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_operator_overload_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.function.definition.operator-overload.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" - } - } - }, - "qualified_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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(?![\\w<:.])", - "captures": { - "0": { - "name": "meta.qualified_type.cpp", - "patterns": [ - { - "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", - "captures": { - "1": { - "name": "meta.qualified_type.cpp", - "patterns": [ - { - "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" - } - ] - }, - "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" - } - ] - } - } - }, - "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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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": "(?\\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" - } - ] - }, - "61": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "62": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "63": { - "name": "comment.block.cpp" - }, - "64": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "65": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "66": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "67": { - "name": "comment.block.cpp" - }, - "68": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "69": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "70": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "71": { - "name": "comment.block.cpp" - }, - "72": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "73": { - "name": "punctuation.definition.begin.bracket.square.cpp" - }, - "74": { - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "75": { - "name": "punctuation.definition.end.bracket.square.cpp" - }, - "76": { - "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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\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": "(?))((?:(?:(?>\\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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<69>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<69>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<69>?)+)>)\\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)))((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<69>?)+)>)\\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": "(?\\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" - } - ] - }, - "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": [ - { - "include": "#inline_comment" - } - ] - }, - "49": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "50": { - "name": "comment.block.cpp" - }, - "51": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "52": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "53": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "54": { - "name": "comment.block.cpp" - }, - "55": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "56": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "57": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "58": { - "name": "comment.block.cpp" - }, - "59": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "60": { - "name": "storage.type.modifier.calling-convention.cpp" - }, - "61": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "62": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "63": { - "name": "comment.block.cpp" - }, - "64": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "65": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_inner_generated" - } - ] - }, - "66": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" - }, - "68": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "70": { - "name": "entity.name.function.definition.cpp" - }, - "71": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "72": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "73": { - "name": "comment.block.cpp" - }, - "74": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - } - }, - "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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)))((?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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)))(?=\\<|\\())", + "begin": "((?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(?:(?:((?:delete\\[\\]|delete|new\\[\\]|<=>|<<=|new|>>=|\\->\\*|\\/=|%=|&=|>=|\\|=|\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|<<|>>|\\-\\-|<=|\\^=|==|!=|&&|\\|\\||\\+=|\\-=|\\*=|,|\\+|\\-|!|~|\\*|&|\\*|\\/|%|\\+|\\-|<|>|&|\\^|\\||=))|((?\\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" @@ -5681,7 +7162,7 @@ "name": "meta.qualified_type.cpp", "patterns": [ { - "match": "(?\\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": "(\\))|(?=(?(?:(?>[^<>]*)\\g<12>?)+)>)\\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)))(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?(\\()", - "beginCaptures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_function_call_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.function.call.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": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "13": { - "name": "punctuation.section.arguments.begin.bracket.round.function.call.cpp" - } - }, - "end": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", - "beginCaptures": { - "1": { - "name": "meta.qualified_type.cpp", - "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)))((?\\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": "(\\))|(?=(?\\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)))((?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?\\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": "(?=\\{)|(?=(?(?:(?>[^<>]*)\\g<3>?)+)>)\\s*)?(\\()", - "beginCaptures": { - "1": { - "name": "entity.name.function.call.initializer.cpp" - }, - "2": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "4": { - "name": "punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp" - } - }, - "end": "(\\))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\16((?:(?:(?>\\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": "(?=\\{)|(?=(?(?:(?>[^<>]*)\\g<3>?)+)>)\\s*)?(\\()", - "beginCaptures": { - "1": { - "name": "entity.name.function.call.initializer.cpp" - }, - "2": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "4": { - "name": "punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp" - } - }, - "end": "(\\))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?\\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))))*)(~(?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?\\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": "(\\))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\16((?:(?:(?>\\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": "(\\))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?\\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": "(\\))|(?=(?\\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": "(\\))|(?=(?\\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": "(\\))|(?=(?\\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": "(\\))|(?=(?\\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": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", - "beginCaptures": { - "1": { - "name": "keyword.operator.functionlike.cpp keyword.operator.sizeof.variadic.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.variadic.cpp" - } - }, - "end": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" - } - ] - }, - "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" - } - ] - }, - "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": { - "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" - }, - "42": { - "name": "punctuation.definition.function.pointer.dereference.cpp" - }, - "43": { - "name": "variable.other.definition.pointer.function.cpp" - }, - "44": { - "name": "punctuation.definition.begin.bracket.square.cpp" - }, - "45": { - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "46": { - "name": "punctuation.definition.end.bracket.square.cpp" - }, - "47": { - "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" - }, - "48": { - "name": "punctuation.section.parameters.begin.bracket.round.function.pointer.cpp" - } - }, - "end": "(\\))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" - } - ] - }, - "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" - } - ] - }, - "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": { - "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" - }, - "42": { - "name": "punctuation.definition.function.pointer.dereference.cpp" - }, - "43": { - "name": "variable.parameter.pointer.function.cpp" - }, - "44": { - "name": "punctuation.definition.begin.bracket.square.cpp" - }, - "45": { - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "46": { - "name": "punctuation.definition.end.bracket.square.cpp" - }, - "47": { - "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" - }, - "48": { - "name": "punctuation.section.parameters.begin.bracket.round.function.pointer.cpp" - } - }, - "end": "(\\))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" - } - ] - }, - "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" - } - ] - }, - "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": { - "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" - }, - "42": { - "name": "punctuation.definition.function.pointer.dereference.cpp" - }, - "43": { - "name": "entity.name.type.alias.cpp entity.name.type.pointer.function.cpp" - }, - "44": { - "name": "punctuation.definition.begin.bracket.square.cpp" - }, - "45": { - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "46": { - "name": "punctuation.definition.end.bracket.square.cpp" - }, - "47": { - "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" - }, - "48": { - "name": "punctuation.section.parameters.begin.bracket.round.function.pointer.cpp" - } - }, - "end": "(\\))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()|(?=(?\\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": "(?:(?=\\))|(,))|(?=(?\\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": "(?:(?=\\))|(,))|(?=(?\\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": "(\\])|(?=(?\\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" + "include": "#parameter_class" } ] }, @@ -10186,7 +7983,7 @@ "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)))(?=,|\\)|=)", + "match": "((?:((?:volatile|register|restrict|static|extern|const))((?:(?:(?>\\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": [ @@ -10422,7 +8219,7 @@ "include": "#scope_resolution_parameter_inner_generated" }, { - "match": "(?:class|struct|union|enum)", + "match": "(?:struct|class|union|enum)", "name": "storage.type.$0.cpp" }, { @@ -10524,7 +8321,7 @@ ] }, { - "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)))((?\\*|->)))((?:(?:[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(?!\\())", + "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" } ] }, - "2": { + "3": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "3": { + "4": { "name": "comment.block.cpp" }, - "4": { + "5": { "patterns": [ { "match": "\\*\\/", @@ -10658,134 +8458,23 @@ } ] }, - "5": { - "name": "variable.language.this.cpp" - }, "6": { - "name": "variable.other.object.access.cpp" + "name": "entity.name.type.class.parameter.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": { + "8": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "3": { + "9": { "name": "comment.block.cpp" }, - "4": { + "10": { "patterns": [ { "match": "\\*\\/", @@ -10797,22 +8486,14 @@ } ] }, - "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": { + "11": { "patterns": [ { - "match": "(?<=(?:\\.\\*|\\.|->|->\\*))\\s*(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))", + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", "captures": { "1": { "patterns": [ @@ -10838,614 +8519,498 @@ "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" } - } + }, + "name": "invalid.illegal.reference-type.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" + "match": "\\&", + "name": "storage.modifier.reference.cpp" } ] }, - "10": { - "name": "entity.name.function.member.cpp" - }, - "11": { - "name": "punctuation.section.arguments.begin.bracket.round.function.member.cpp" - } - }, - "end": "(\\))|(?=(?(?:(?>[^<>]*)\\g<7>?)+)>)\\s*)?::)*\\s*+)?((?(?:(?>[^<>]*)\\g<9>?)+)>)\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?(?:(?>[^<>]*)\\g<5>?)+)>)\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?])|(?<=\\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": "(?<=})|(?=(?)((?:.+?(?=\\{|$))?)", - "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": "(\\})|(?=(?(?:(?>[^<>]*)\\g<15>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?(::))?\\s*((?|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?=(?\\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": "punctuation.terminator.statement.cpp" + "name": "storage.type.enum.parameter.cpp" }, "2": { - "name": "punctuation.terminator.statement.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": "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_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" + } + ] } }, - "patterns": [ - { - "name": "meta.head.enum.cpp", - "begin": "\\G ?", - "end": "((?:\\{|<%|\\?\\?<|(?=;)))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))", + "include": "#curly_initializer" + }, + { + "include": "#decltype" + }, + { + "include": "#vararg_ellipses" + }, + { + "match": "((?:((?:volatile|register|restrict|static|extern|const))((?:(?:(?>\\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": { - "name": "meta.qualified_type.cpp", "patterns": [ - { - "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": "(\\])|(?=(?\\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" } ] }, - "class_block": { - "name": "meta.block.class.cpp", - "begin": "((((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))|((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\))))|(?={))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(final)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)((?>[^{]*)))?))", - "beginCaptures": { + "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": "meta.head.class.cpp" + "name": "storage.type.struct.parameter.cpp" }, - "3": { - "name": "storage.type.$3.cpp" - }, - "4": { + "2": { "patterns": [ { "include": "#inline_comment" } ] }, - "5": { + "3": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "6": { + "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": [ { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" + "include": "#inline_comment" } ] }, "8": { - "patterns": [ - { - "include": "#attributes_context" - }, - { - "include": "#number_literal" - } - ] - }, - "9": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "10": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "11": { + "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": [ { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" + "include": "#inline_comment" } ] }, "13": { - "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" - }, - "14": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "15": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "16": { + "14": { "name": "comment.block.cpp" }, - "17": { + "15": { "patterns": [ { "match": "\\*\\/", @@ -11667,58 +9574,45 @@ } ] }, - "18": { + "16": { "patterns": [ { - "include": "#attributes_context" - }, - { - "include": "#number_literal" + "include": "#inline_comment" } ] }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, "19": { "patterns": [ { - "include": "#inline_comment" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } ] }, "20": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "21": { - "name": "comment.block.cpp" - }, - "22": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "23": { - "name": "entity.name.type.$3.cpp" - }, - "24": { "patterns": [ { "include": "#inline_comment" } ] }, - "25": { + "21": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "26": { + "22": { "name": "comment.block.cpp" }, - "27": { + "23": { "patterns": [ { "match": "\\*\\/", @@ -11730,8 +9624,33 @@ } ] }, + "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": { - "name": "storage.type.modifier.final.cpp" + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] }, "29": { "patterns": [ @@ -11782,85 +9701,2456 @@ "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" }, - "37": { - "name": "punctuation.separator.colon.inheritance.cpp" - }, - "38": { + "2": { "patterns": [ { - "include": "#inheritance_context" + "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" } ] } + } + }, + "parentheses": { + "name": "meta.parens.cpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parens.begin.bracket.round.cpp" + } }, - "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*pragma\\b)", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.pragma.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.definition.directive.cpp" + } + }, + "end": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*pragma\\s+mark)\\s+(.*)", + "captures": { + "1": { + "name": "keyword.control.directive.pragma.pragma-mark.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.definition.directive.cpp" + }, + "7": { + "name": "entity.name.tag.pragma-mark.cpp" + } + }, + "name": "meta.preprocessor.pragma.cpp" + }, + "predefined_macros": { + "patterns": [ + { + "match": "\\b(__cplusplus|__DATE__|__FILE__|__LINE__|__STDC__|__STDC_HOSTED__|__STDC_NO_COMPLEX__|__STDC_VERSION__|__STDCPP_THREADS__|__TIME__|NDEBUG|__OBJC__|__ASSEMBLER__|__ATOM__|__AVX__|__AVX2__|_CHAR_UNSIGNED|__CLR_VER|_CONTROL_FLOW_GUARD|__COUNTER__|__cplusplus_cli|__cplusplus_winrt|_CPPRTTI|_CPPUNWIND|_DEBUG|_DLL|__FUNCDNAME__|__FUNCSIG__|__FUNCTION__|_INTEGRAL_MAX_BITS|__INTELLISENSE__|_ISO_VOLATILE|_KERNEL_MODE|_M_AMD64|_M_ARM|_M_ARM_ARMV7VE|_M_ARM_FP|_M_ARM64|_M_CEE|_M_CEE_PURE|_M_CEE_SAFE|_M_FP_EXCEPT|_M_FP_FAST|_M_FP_PRECISE|_M_FP_STRICT|_M_IX86|_M_IX86_FP|_M_X64|_MANAGED|_MSC_BUILD|_MSC_EXTENSIONS|_MSC_FULL_VER|_MSC_VER|_MSVC_LANG|__MSVC_RUNTIME_CHECKS|_MT|_NATIVE_WCHAR_T_DEFINED|_OPENMP|_PREFAST|__TIMESTAMP__|_VC_NO_DEFAULTLIB|_WCHAR_T_DEFINED|_WIN32|_WIN64|_WINRT_DLL|_ATL_VER|_MFC_VER|__GFORTRAN__|__GNUC__|__GNUC_MINOR__|__GNUC_PATCHLEVEL__|__GNUG__|__STRICT_ANSI__|__BASE_FILE__|__INCLUDE_LEVEL__|__ELF__|__VERSION__|__OPTIMIZE__|__OPTIMIZE_SIZE__|__NO_INLINE__|__GNUC_STDC_INLINE__|__CHAR_UNSIGNED__|__WCHAR_UNSIGNED__|__REGISTER_PREFIX__|__REGISTER_PREFIX__|__SIZE_TYPE__|__PTRDIFF_TYPE__|__WCHAR_TYPE__|__WINT_TYPE__|__INTMAX_TYPE__|__UINTMAX_TYPE__|__SIG_ATOMIC_TYPE__|__INT8_TYPE__|__INT16_TYPE__|__INT32_TYPE__|__INT64_TYPE__|__UINT8_TYPE__|__UINT16_TYPE__|__UINT32_TYPE__|__UINT64_TYPE__|__INT_LEAST8_TYPE__|__INT_LEAST16_TYPE__|__INT_LEAST32_TYPE__|__INT_LEAST64_TYPE__|__UINT_LEAST8_TYPE__|__UINT_LEAST16_TYPE__|__UINT_LEAST32_TYPE__|__UINT_LEAST64_TYPE__|__INT_FAST8_TYPE__|__INT_FAST16_TYPE__|__INT_FAST32_TYPE__|__INT_FAST64_TYPE__|__UINT_FAST8_TYPE__|__UINT_FAST16_TYPE__|__UINT_FAST32_TYPE__|__UINT_FAST64_TYPE__|__INTPTR_TYPE__|__UINTPTR_TYPE__|__CHAR_BIT__|__SCHAR_MAX__|__WCHAR_MAX__|__SHRT_MAX__|__INT_MAX__|__LONG_MAX__|__LONG_LONG_MAX__|__WINT_MAX__|__SIZE_MAX__|__PTRDIFF_MAX__|__INTMAX_MAX__|__UINTMAX_MAX__|__SIG_ATOMIC_MAX__|__INT8_MAX__|__INT16_MAX__|__INT32_MAX__|__INT64_MAX__|__UINT8_MAX__|__UINT16_MAX__|__UINT32_MAX__|__UINT64_MAX__|__INT_LEAST8_MAX__|__INT_LEAST16_MAX__|__INT_LEAST32_MAX__|__INT_LEAST64_MAX__|__UINT_LEAST8_MAX__|__UINT_LEAST16_MAX__|__UINT_LEAST32_MAX__|__UINT_LEAST64_MAX__|__INT_FAST8_MAX__|__INT_FAST16_MAX__|__INT_FAST32_MAX__|__INT_FAST64_MAX__|__UINT_FAST8_MAX__|__UINT_FAST16_MAX__|__UINT_FAST32_MAX__|__UINT_FAST64_MAX__|__INTPTR_MAX__|__UINTPTR_MAX__|__WCHAR_MIN__|__WINT_MIN__|__SIG_ATOMIC_MIN__|__SCHAR_WIDTH__|__SHRT_WIDTH__|__INT_WIDTH__|__LONG_WIDTH__|__LONG_LONG_WIDTH__|__PTRDIFF_WIDTH__|__SIG_ATOMIC_WIDTH__|__SIZE_WIDTH__|__WCHAR_WIDTH__|__WINT_WIDTH__|__INT_LEAST8_WIDTH__|__INT_LEAST16_WIDTH__|__INT_LEAST32_WIDTH__|__INT_LEAST64_WIDTH__|__INT_FAST8_WIDTH__|__INT_FAST16_WIDTH__|__INT_FAST32_WIDTH__|__INT_FAST64_WIDTH__|__INTPTR_WIDTH__|__INTMAX_WIDTH__|__SIZEOF_INT__|__SIZEOF_LONG__|__SIZEOF_LONG_LONG__|__SIZEOF_SHORT__|__SIZEOF_POINTER__|__SIZEOF_FLOAT__|__SIZEOF_DOUBLE__|__SIZEOF_LONG_DOUBLE__|__SIZEOF_SIZE_T__|__SIZEOF_WCHAR_T__|__SIZEOF_WINT_T__|__SIZEOF_PTRDIFF_T__|__BYTE_ORDER__|__ORDER_LITTLE_ENDIAN__|__ORDER_BIG_ENDIAN__|__ORDER_PDP_ENDIAN__|__FLOAT_WORD_ORDER__|__DEPRECATED|__EXCEPTIONS|__GXX_RTTI|__USING_SJLJ_EXCEPTIONS__|__GXX_EXPERIMENTAL_CXX0X__|__GXX_WEAK__|__NEXT_RUNTIME__|__LP64__|_LP64|__SSP__|__SSP_ALL__|__SSP_STRONG__|__SSP_EXPLICIT__|__SANITIZE_ADDRESS__|__SANITIZE_THREAD__|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16|__HAVE_SPECULATION_SAFE_VALUE|__GCC_HAVE_DWARF2_CFI_ASM|__FP_FAST_FMA|__FP_FAST_FMAF|__FP_FAST_FMAL|__FP_FAST_FMAF16|__FP_FAST_FMAF32|__FP_FAST_FMAF64|__FP_FAST_FMAF128|__FP_FAST_FMAF32X|__FP_FAST_FMAF64X|__FP_FAST_FMAF128X|__GCC_IEC_559|__GCC_IEC_559_COMPLEX|__NO_MATH_ERRNO__|__has_builtin|__has_feature|__has_extension|__has_cpp_attribute|__has_c_attribute|__has_attribute|__has_declspec_attribute|__is_identifier|__has_include|__has_include_next|__has_warning|__BASE_FILE__|__FILE_NAME__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__fp16|_Float16)\\b", + "captures": { + "1": { + "name": "entity.name.other.preprocessor.macro.predefined.$1.cpp" + } + } + }, + { + "match": "\\b__([A-Z_]+)__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.probably.$1.cpp" + } + ] + }, + "preprocessor_conditional_context": { + "patterns": [ + { + "include": "#preprocessor_conditional_defined" + }, + { + "include": "#comments" + }, + { + "include": "#language_constants" + }, + { + "include": "#string_context_c" + }, + { + "include": "#preprocessor_number_literal" + }, + { + "include": "#operators" + }, + { + "include": "#predefined_macros" + }, + { + "include": "#macro_name" + }, + { + "include": "#line_continuation_character" + } + ] + }, + "preprocessor_conditional_defined": { + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?:(?:ifndef|ifdef)|if)))", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.conditional.$7.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.definition.directive.cpp" + } + }, + "end": "(?:^)(?!\\s*+#\\s*(?:else|endif))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(?![\\w<:.])", + "captures": { + "0": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?|\\?\\?>)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_function_call": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_function_call_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_function_call_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_call_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.function.call.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" + } + } + }, + "scope_resolution_function_definition": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_function_definition_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.function.definition.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" + } + } + }, + "scope_resolution_function_definition_operator_overload": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_operator_overload_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_function_definition_operator_overload_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_operator_overload_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.function.definition.operator-overload.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" + } + } + }, + "scope_resolution_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + } + } + }, + "scope_resolution_namespace_alias": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_namespace_alias_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_namespace_alias_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_namespace_alias_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.namespace.alias.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" + } + } + }, + "scope_resolution_namespace_block": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_namespace_block_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_namespace_block_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_namespace_block_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.namespace.block.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" + } + } + }, + "scope_resolution_namespace_using": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_namespace_using_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_namespace_using_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_namespace_using_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.namespace.using.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" + } + } + }, + "scope_resolution_parameter": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_parameter_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_parameter_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_parameter_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.parameter.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" + } + } + }, + "scope_resolution_template_call": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_template_call_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_template_call_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_template_call_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.template.call.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" + } + } + }, + "scope_resolution_template_definition": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_template_definition_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_template_definition_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_template_definition_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.template.definition.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" + } + } + }, + "semicolon": { + "match": ";", + "name": "punctuation.terminator.statement.cpp" + }, + "simple_type": { + "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", + "captures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "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" + } + ] + }, + "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" + } + ] + } + } + }, + "single_line_macro": { + "match": "^((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))#define.*(?\\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": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.functionlike.cpp keyword.operator.sizeof.variadic.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.variadic.cpp" + } + }, + "end": "(\\))|(?=(?\\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": "(\\))|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))|((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\))))|(?={))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(final)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)((?>[^{]*)))?))", - "beginCaptures": { + "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(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "captures": { "1": { - "name": "meta.head.union.cpp" + "name": "storage.type.struct.declare.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "3": { - "name": "storage.type.$3.cpp" + "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" + } + ] + } + } + }, + "switch_conditional_parentheses": { + "name": "meta.conditional.switch.cpp", + "begin": "((?:(?:(?>\\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": "punctuation.section.parens.begin.bracket.round.conditional.switch.cpp" + } + }, + "end": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?(?:(?>[^<>]*)\\g<1>?)+)>)\\s*", + "captures": { + "0": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "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+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\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": [ + { + "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": [ + { + "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" + } + ] + }, + "7": { + "name": "entity.name.type.template.cpp" + }, + "8": { + "name": "storage.type.template.cpp" + }, + "9": { + "name": "punctuation.vararg-ellipses.template.definition.cpp" + }, + "10": { + "name": "entity.name.type.template.cpp" + }, + "11": { + "name": "punctuation.separator.delimiter.comma.template.argument.cpp" + } + } + }, + "template_definition_context": { + "patterns": [ + { + "include": "#scope_resolution_template_definition_inner_generated" + }, + { + "include": "#template_definition_argument" + }, + { + "include": "#template_argument_defaulted" + }, + { + "include": "#template_call_innards" + }, + { + "include": "#evaluation_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": "#template_definition_context" + } + ] + }, + "4": { + "name": "punctuation.section.angle-brackets.end.template.definition.cpp" + } + } + }, + "ternary_operator": { + "applyEndPatternLast": true, + "begin": "(\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.cpp" + } + }, + "end": "(:)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))\\s*(\\=)\\s*((?:typename)?)\\s*((?:(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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": "(?|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(extern)(?=\\s*\\\"))", - "beginCaptures": { - "1": { - "name": "meta.head.extern.cpp" + "51": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" }, - "2": { + "52": { "patterns": [ { "include": "#inline_comment" } ] }, - "3": { + "53": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "4": { + "54": { "name": "comment.block.cpp" }, - "5": { + "55": { "patterns": [ { "match": "\\*\\/", @@ -12486,64 +13463,194 @@ } ] }, - "6": { - "name": "storage.type.extern.cpp" + "56": { + "name": "entity.name.type.cpp" + }, + "57": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "59": { + "name": "meta.declaration.type.alias.value.unknown.cpp", + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "60": { + "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" + } + ] + }, + "61": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "62": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "63": { + "name": "comment.block.cpp" + }, + "64": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "65": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "66": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "67": { + "name": "comment.block.cpp" + }, + "68": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "69": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "70": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "71": { + "name": "comment.block.cpp" + }, + "72": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "73": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "74": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "75": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "76": { + "name": "punctuation.terminator.statement.cpp" } }, - "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" + } + ] + }, + "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" + } + ] + }, + "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": { + "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" + }, + "42": { + "name": "punctuation.definition.function.pointer.dereference.cpp" + }, + "43": { + "name": "entity.name.type.alias.cpp entity.name.type.pointer.function.cpp" + }, + "44": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "45": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "46": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "47": { + "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" + }, + "48": { + "name": "punctuation.section.parameters.begin.bracket.round.function.pointer.cpp" + } + }, + "end": "(\\))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()|(?=(?\\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)))\\b(?!final\\W|final\\$|override\\W|override\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", - "captures": { + "typeid_operator": { + "contentName": "meta.arguments.operator.typeid.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { "1": { - "name": "storage.type.struct.declare.cpp" + "name": "keyword.operator.functionlike.cpp keyword.operator.typeid.cpp" }, "2": { "patterns": [ @@ -13873,65 +15377,41 @@ ] }, "6": { - "name": "entity.name.type.struct.cpp" + "name": "punctuation.section.arguments.begin.bracket.round.operator.typeid.cpp" + } + }, + "end": "(\\))|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(?![\\w<:.]))", + "captures": { + "1": { + "name": "storage.modifier.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": { + "2": { "patterns": [ { "include": "#inline_comment" } ] }, - "9": { + "3": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "10": { + "4": { "name": "comment.block.cpp" }, - "11": { + "5": { "patterns": [ { "match": "\\*\\/", @@ -13943,6 +15423,78 @@ } ] }, + "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": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*undef\\b)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))|((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\))))|(?={))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(final)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)((?>[^{]*)))?))", + "beginCaptures": { + "1": { + "name": "meta.head.union.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "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": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "9": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "10": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "11": { + "name": "comment.block.cpp" + }, + "12": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "13": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "14": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "15": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "16": { + "name": "comment.block.cpp" + }, + "17": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "18": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "19": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "20": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "21": { + "name": "comment.block.cpp" + }, + "22": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "23": { + "name": "entity.name.type.$3.cpp" + }, + "24": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "25": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "26": { + "name": "comment.block.cpp" + }, + "27": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "28": { + "name": "storage.type.modifier.final.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" + } + ] + }, + "37": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "38": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?=(?|\\?\\?>)|(?=(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)|(?=(?\\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)(?![:{])", + "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(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.union.declare.cpp" @@ -14205,1776 +16157,62 @@ } } }, - "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)(?![:{])", + "using_name": { + "match": "(using)\\s+(?!namespace\\b)", "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" - } - ] + "name": "keyword.other.using.directive.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" - } - ] - }, - "assembly": { - "name": "meta.asm.cpp", - "begin": "(\\b(?:__asm__|asm)\\b)\\s*((?:volatile)?)\\s*(\\()", + "using_namespace": { + "name": "meta.using-namespace.cpp", + "begin": "(?(?:(?>[^<>]*)\\g<7>?)+)>)\\s*)?::)*\\s*+)?((?(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", + "access_control_keywords": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(((?:protected|private|public))\\s*(:))", "captures": { "1": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "2": { - "name": "comment.block.cpp" + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, "3": { + "name": "comment.block.cpp" + }, + "4": { "patterns": [ { "match": "\\*\\/", @@ -114,271 +121,83 @@ "name": "comment.block.cpp" } ] + }, + "5": { + "name": "storage.type.modifier.access.control.$6.cpp" + }, + "7": { + "name": "punctuation.separator.colon.access.control.cpp" } } }, - "macro_name": { - "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*pragma\\s+mark)\\s+(.*)", - "captures": { + "alignas_operator": { + "contentName": "meta.arguments.operator.alignas.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { "1": { - "name": "keyword.control.directive.pragma.pragma-mark.cpp" + "name": "keyword.operator.functionlike.cpp keyword.operator.alignas.cpp" }, "2": { "patterns": [ @@ -406,20 +225,2838 @@ ] }, "6": { - "name": "punctuation.definition.directive.cpp" - }, - "7": { - "name": "entity.name.tag.pragma-mark.cpp" + "name": "punctuation.section.arguments.begin.bracket.round.operator.alignas.cpp" } }, - "name": "meta.preprocessor.pragma.cpp" + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.operator.alignas.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] }, - "pragma": { - "name": "meta.preprocessor.pragma.cpp", - "begin": "((?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*pragma\\b)", + "alignof_operator": { + "contentName": "meta.arguments.operator.alignof.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", "beginCaptures": { "1": { - "name": "keyword.control.directive.pragma.cpp" + "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" + } + ] + }, + "assembly": { + "name": "meta.asm.cpp", + "begin": "(\\b(?:__asm__|asm)\\b)\\s*((?:volatile)?)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "storage.type.asm.cpp" + }, + "2": { + "name": "storage.modifier.cpp" + }, + "3": { + "name": "punctuation.section.parens.begin.bracket.round.assembly.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parens.end.bracket.round.assembly.cpp" + } + }, + "patterns": [ + { + "name": "string.quoted.double.cpp", + "contentName": "meta.embedded.assembly.cpp", + "begin": "(R?)(\")", + "beginCaptures": { + "1": { + "name": "meta.encoding.cpp" + }, + "2": { + "name": "punctuation.definition.string.begin.assembly.cpp" + } + }, + "end": "(\")", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.assembly.cpp" + } + }, + "patterns": [ + { + "include": "source.asm" + }, + { + "include": "source.x86" + }, + { + "include": "source.x86_64" + }, + { + "include": "source.arm" + }, + { + "include": "#backslash_escapes" + }, + { + "include": "#string_escaped_char" + }, + { + "match": "(?=not)possible" + } + ] + }, + { + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parens.begin.bracket.round.assembly.inner.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parens.end.bracket.round.assembly.inner.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + { + "match": ":", + "name": "punctuation.separator.delimiter.colon.assembly.cpp" + }, + { + "include": "#comments_context" + }, + { + "include": "#comments" + } + ] + }, + "assignment_operator": { + "match": "\\=", + "name": "keyword.operator.assignment.cpp" + }, + "attributes_context": { + "patterns": [ + { + "include": "#cpp_attributes" + }, + { + "include": "#gcc_attributes" + }, + { + "include": "#ms_attributes" + }, + { + "include": "#alignas_attribute" + } + ] + }, + "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.cpp" + }, + "block": { + "name": "meta.block.cpp", + "begin": "({)", + "beginCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.cpp" + } + }, + "end": "(}|(?=\\s*#\\s*(?:elif|else|endif)\\b))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + "block_comment": { + "name": "comment.block.cpp", + "begin": "\\s*+(\\/\\*)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.cpp" + } + }, + "end": "(\\*\\/)", + "endCaptures": { + "1": { + "name": "punctuation.definition.comment.end.cpp" + } + } + }, + "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" + } + ] + }, + "case_statement": { + "name": "meta.conditional.case.cpp", + "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))|((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\))))|(?={))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(final)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)((?>[^{]*)))?))", + "beginCaptures": { + "1": { + "name": "meta.head.class.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "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": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "9": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "10": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "11": { + "name": "comment.block.cpp" + }, + "12": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "13": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "14": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "15": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "16": { + "name": "comment.block.cpp" + }, + "17": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "18": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "19": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "20": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "21": { + "name": "comment.block.cpp" + }, + "22": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "23": { + "name": "entity.name.type.$3.cpp" + }, + "24": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "25": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "26": { + "name": "comment.block.cpp" + }, + "27": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "28": { + "name": "storage.type.modifier.final.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" + } + ] + }, + "37": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "38": { + "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": "$self" + } + ] + }, + { + "name": "meta.tail.class.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "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(?!override\\W|override\\$|final\\W|final\\$)((?\\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" + } + ] + } + } + }, + "comma": { + "match": ",", + "name": "punctuation.separator.delimiter.comma.cpp" + }, + "comma_in_template_argument": { + "match": ",", + "name": "punctuation.separator.delimiter.comma.template.argument.cpp" + }, + "comments": { + "patterns": [ + { + "name": "comment.line.double-slash.documentation.cpp", + "begin": "(?:^)(?>\\s*)(\\/\\/[!\\/]+)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.documentation.cpp" + } + }, + "end": "(?<=\\n)(?|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.italic.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.bold.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.inline.raw.string.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "variable.parameter.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc.cpp" + } + ] + }, + { + "match": "(\\/\\*[!*]+(?=\\s))(.+)([!*]*\\*\\/)", + "captures": { + "1": { + "name": "punctuation.definition.comment.begin.documentation.cpp" + }, + "2": { + "patterns": [ + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.italic.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.bold.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.inline.raw.string.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "variable.parameter.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc.cpp" + } + ] + }, + "3": { + "name": "punctuation.definition.comment.end.documentation.cpp" + } + }, + "name": "comment.block.documentation.cpp" + }, + { + "name": "comment.block.documentation.cpp", + "begin": "((?>\\s*)\\/\\*[!*]+(?:(?:\\n|$)|(?=\\s)))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.begin.documentation.cpp" + } + }, + "end": "([!*]*\\*\\/)", + "endCaptures": { + "1": { + "name": "punctuation.definition.comment.end.documentation.cpp" + } + }, + "patterns": [ + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.italic.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.bold.doxygen.cpp" + } + } + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "markup.inline.raw.string.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", + "captures": { + "1": { + "name": "storage.type.class.doxygen.cpp" + }, + "2": { + "name": "variable.parameter.cpp" + } + } + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", + "name": "storage.type.class.doxygen.cpp" + }, + { + "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", + "name": "storage.type.class.gtkdoc.cpp" + } + ] + }, + { + "include": "#emacs_file_banner" + }, + { + "include": "#block_comment" + }, + { + "include": "#line_comment" + }, + { + "include": "#invalid_comment_end" + } + ] + }, + "constructor_inline": { + "name": "meta.function.definition.special.constructor.cpp", + "begin": "(^((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:constexpr|explicit|mutable|virtual|inline|friend)((?:(?:(?>\\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": "((?(?:(?>[^<>]*)\\g<3>?)+)>)\\s*)?(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.call.initializer.cpp" + }, + "2": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "4": { + "name": "punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.function.call.initializer.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + { + "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": "$self" + } + ] + } + ] + }, + "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)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\16((?:(?:(?>\\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": "((?(?:(?>[^<>]*)\\g<3>?)+)>)\\s*)?(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.call.initializer.cpp" + }, + "2": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "4": { + "name": "punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.function.call.initializer.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + { + "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": "$self" + } + ] + } + ] + }, + "control_flow_keywords": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", + "beginCaptures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?\\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": [ + { + "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": "#evaluation_context" + } + ] + }, + "decltype_specifier": { + "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": [ + { + "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": "#evaluation_context" + } + ] + }, + "default_statement": { + "name": "meta.conditional.case.cpp", + "begin": "((?:(?:(?>\\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)))((?:(?:constexpr|explicit|mutable|virtual|inline|friend)((?:(?:(?>\\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": "$self" + } + ] + }, + { + "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": "$self" + } + ] + } + ] + }, + "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)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\16((?:(?:(?>\\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": "$self" + } + ] + }, + { + "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": "$self" + } + ] + } + ] + }, + "diagnostic": { + "name": "meta.preprocessor.diagnostic.$reference(directive).cpp", + "begin": "((?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?:error|warning)))\\b\\s*", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.diagnostic.$7.cpp" }, "2": { "patterns": [ @@ -452,26 +3089,2253 @@ }, "end": "(?[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*(?:\\n|$)))|(^\\s*((\\/\\*)\\s*?((?>[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*\\*\\/)))", + "captures": { + "1": { + "name": "meta.toc-list.banner.double-slash.cpp" + }, + "2": { + "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.banner.cpp" + }, + "7": { + "name": "punctuation.definition.comment.cpp" + }, + "8": { + "name": "meta.banner.character.cpp" + } + } + }, + "empty_square_brackets": { + "name": "storage.modifier.array.bracket.square.cpp", + "match": "(?-mix:(?-mix:(?(?:(?>[^<>]*)\\g<15>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\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": "$self" + } + ] + }, + { + "name": "meta.body.enum.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.enum.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#enumerator_list" + }, + { + "include": "#comments" + }, + { + "include": "#comma" + }, + { + "include": "#semicolon" + } + ] + }, + { + "name": "meta.tail.enum.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "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(?!override\\W|override\\$|final\\W|final\\$)((?\\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" + } + ] + } + } + }, + "enumerator_list": { + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\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": "$self" + } + ] + }, + { + "name": "meta.body.extern.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.extern.cpp" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "name": "meta.tail.extern.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "include": "$self" + } + ] + }, + "function_body_context": { + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#using_namespace" + }, + { + "include": "#type_alias" + }, + { + "include": "#using_name" + }, + { + "include": "#namespace_alias" + }, + { + "include": "#typedef_class" + }, + { + "include": "#typedef_struct" + }, + { + "include": "#typedef_union" + }, + { + "include": "#typedef_keyword" + }, + { + "include": "#standard_declares" + }, + { + "include": "#class_block" + }, + { + "include": "#struct_block" + }, + { + "include": "#union_block" + }, + { + "include": "#enum_block" + }, + { + "include": "#access_control_keywords" + }, + { + "include": "#block" + }, + { + "include": "#static_assert" + }, + { + "include": "#assembly" + }, + { + "include": "#function_pointer" + }, + { + "include": "#switch_statement" + }, + { + "include": "#goto_statement" + }, + { + "include": "#evaluation_context" + }, + { + "include": "#label" + } + ] + }, + "function_call": { + "begin": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\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)))(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_call_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.function.call.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": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "13": { + "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" + } + ] + }, + "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)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\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)))((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\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": { + "patterns": [ + { + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))", + "captures": { + "1": { + "name": "storage.modifier.$1.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" + } + ] + } + } + } + ] + }, + "12": { + "name": "storage.modifier.$1.cpp" + }, + "13": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "14": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "15": { + "name": "comment.block.cpp" + }, + "16": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "17": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "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" + } + ] + }, + "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": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "54": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "55": { + "name": "comment.block.cpp" + }, + "56": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "57": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "58": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "59": { + "name": "comment.block.cpp" + }, + "60": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "61": { + "name": "storage.type.modifier.calling-convention.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": "#scope_resolution_function_definition_inner_generated" + } + ] + }, + "67": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" + }, + "69": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "71": { + "name": "entity.name.function.definition.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" + } + ] + } + }, + "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": "$self" + } + ] + }, + { + "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": "$self" + } + ] + } + ] + }, + "function_parameter_context": { + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#parameter" + }, + { + "include": "#comma" + } + ] + }, + "function_pointer": { + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" + } + ] + }, + "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" + } + ] + }, + "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": { + "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" + }, + "42": { + "name": "punctuation.definition.function.pointer.dereference.cpp" + }, + "43": { + "name": "variable.other.definition.pointer.function.cpp" + }, + "44": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "45": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "46": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "47": { + "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" + }, + "48": { + "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)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" + } + ] + }, + "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" + } + ] + }, + "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": { + "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" + }, + "42": { + "name": "punctuation.definition.function.pointer.dereference.cpp" + }, + "43": { + "name": "variable.parameter.pointer.function.cpp" + }, + "44": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "45": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "46": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "47": { + "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" + }, + "48": { + "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" + } + ] + }, + "functional_specifiers_pre_parameters": { + "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}))*)", + "captures": { + "1": { + "name": "keyword.control.goto.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.label.call.cpp" + } + } + }, "include": { - "match": "(?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((#)\\s*((?:(?:include|include_next)|import))\\b)\\s*(?:(?:(?:((<)[^>]*(>?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/)))|((\\\")[^\\\"]*(\\\"?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/))))|((?:[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|$)|(?=\\/\\/))))|((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/)))", + "match": "(?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((#)\\s*((?:include|include_next))\\b)\\s*(?:(?:(?:((<)[^>]*(>?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/)))|((\\\")[^\\\"]*(\\\"?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/))))|(((?:(?:(?>\\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+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=(?:\\/\\/|;)))))|((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=(?:\\/\\/|;))))", "captures": { "1": { "patterns": [ @@ -624,10 +5488,435 @@ "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" + } + ] } }, "name": "meta.preprocessor.include.cpp" }, + "inheritance_context": { + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.comma.inheritance.cpp" + }, + { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))", + "captures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", + "captures": { + "1": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "2": { + "name": "comment.block.cpp" + }, + "3": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "invalid_comment_end": { + "match": "\\*\\/", + "name": "invalid.illegal.unexpected.punctuation.definition.comment.end.cpp" + }, + "label": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\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": "entity.name.label.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.separator.label.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": "$self" + } + ] + } + ] + }, + "language_constants": { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*line\\b)", @@ -677,203 +5966,24 @@ } ] }, - "diagnostic": { - "name": "meta.preprocessor.diagnostic.$reference(directive).cpp", - "begin": "((?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?:error|warning)))\\b\\s*", + "line_comment": { + "name": "comment.line.double-slash.cpp", + "begin": "\\s*+(\\/\\/)", "beginCaptures": { "1": { - "name": "keyword.control.directive.diagnostic.$7.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.definition.directive.cpp" + "name": "punctuation.definition.comment.cpp" } }, - "end": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*undef\\b)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))#define.*(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?:(?:ifndef|ifdef)|if)))", - "beginCaptures": { + "macro_context": { + "patterns": [ + { + "include": "source.cpp.embedded.macro" + } + ] + }, + "macro_name": { + "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(?!uint_least64_t[^(?-mix:\\w)]|uint_least16_t[^(?-mix:\\w)]|uint_least32_t[^(?-mix:\\w)]|int_least16_t[^(?-mix:\\w)]|uint_fast64_t[^(?-mix:\\w)]|uint_fast32_t[^(?-mix:\\w)]|uint_fast16_t[^(?-mix:\\w)]|uint_least8_t[^(?-mix:\\w)]|int_least64_t[^(?-mix:\\w)]|int_least32_t[^(?-mix:\\w)]|int_fast32_t[^(?-mix:\\w)]|int_fast16_t[^(?-mix:\\w)]|int_least8_t[^(?-mix:\\w)]|uint_fast8_t[^(?-mix:\\w)]|int_fast64_t[^(?-mix:\\w)]|int_fast8_t[^(?-mix:\\w)]|suseconds_t[^(?-mix:\\w)]|useconds_t[^(?-mix:\\w)]|in_addr_t[^(?-mix:\\w)]|uintmax_t[^(?-mix:\\w)]|uintmax_t[^(?-mix:\\w)]|uintptr_t[^(?-mix:\\w)]|blksize_t[^(?-mix:\\w)]|in_port_t[^(?-mix:\\w)]|intmax_t[^(?-mix:\\w)]|unsigned[^(?-mix:\\w)]|blkcnt_t[^(?-mix:\\w)]|uint32_t[^(?-mix:\\w)]|u_quad_t[^(?-mix:\\w)]|uint16_t[^(?-mix:\\w)]|intmax_t[^(?-mix:\\w)]|uint64_t[^(?-mix:\\w)]|intptr_t[^(?-mix:\\w)]|swblk_t[^(?-mix:\\w)]|wchar_t[^(?-mix:\\w)]|u_short[^(?-mix:\\w)]|qaddr_t[^(?-mix:\\w)]|caddr_t[^(?-mix:\\w)]|daddr_t[^(?-mix:\\w)]|fixpt_t[^(?-mix:\\w)]|nlink_t[^(?-mix:\\w)]|segsz_t[^(?-mix:\\w)]|clock_t[^(?-mix:\\w)]|ssize_t[^(?-mix:\\w)]|int16_t[^(?-mix:\\w)]|int32_t[^(?-mix:\\w)]|int64_t[^(?-mix:\\w)]|uint8_t[^(?-mix:\\w)]|int8_t[^(?-mix:\\w)]|mode_t[^(?-mix:\\w)]|quad_t[^(?-mix:\\w)]|ushort[^(?-mix:\\w)]|u_long[^(?-mix:\\w)]|u_char[^(?-mix:\\w)]|double[^(?-mix:\\w)]|size_t[^(?-mix:\\w)]|signed[^(?-mix:\\w)]|time_t[^(?-mix:\\w)]|key_t[^(?-mix:\\w)]|ino_t[^(?-mix:\\w)]|gid_t[^(?-mix:\\w)]|dev_t[^(?-mix:\\w)]|div_t[^(?-mix:\\w)]|float[^(?-mix:\\w)]|u_int[^(?-mix:\\w)]|uid_t[^(?-mix:\\w)]|short[^(?-mix:\\w)]|off_t[^(?-mix:\\w)]|pid_t[^(?-mix:\\w)]|id_t[^(?-mix:\\w)]|bool[^(?-mix:\\w)]|char[^(?-mix:\\w)]|id_t[^(?-mix:\\w)]|uint[^(?-mix:\\w)]|void[^(?-mix:\\w)]|long[^(?-mix:\\w)]|auto[^(?-mix:\\w)]|int[^(?-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": { - "name": "keyword.control.directive.conditional.$7.cpp" - }, - "2": { "patterns": [ { "include": "#inline_comment" } ] }, - "3": { + "2": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "4": { + "3": { "name": "comment.block.cpp" }, - "5": { + "4": { "patterns": [ { "match": "\\*\\/", @@ -991,97 +6109,321 @@ } ] }, + "5": { + "name": "variable.language.this.cpp" + }, "6": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?:^)(?!\\s*+#\\s*(?:else|endif))", - "patterns": [ - { - "name": "meta.preprocessor.conditional.cpp", - "begin": "\\G(?<=ifndef|ifdef|if)", - "end": "(?|->\\*))\\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" } ] }, - { - "include": "$self" + "10": { + "name": "variable.other.property.cpp" } - ] + } }, - "preprocessor_conditional_context": { - "patterns": [ - { - "include": "#preprocessor_conditional_defined" - }, - { - "include": "#comments" - }, - { - "include": "#language_constants" - }, - { - "include": "#string_context_c" - }, - { - "include": "#preprocessor_number_literal" - }, - { - "include": "#operators" - }, - { - "include": "#predefined_macros" - }, - { - "include": "#macro_name" - }, - { - "include": "#line_continuation_character" - } - ] - }, - "preprocessor_conditional_defined": { - "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(delete)\\s*(\\[\\])|(delete))|(new))(?!\\w))", + "captures": { "1": { - "name": "keyword.control.directive.conditional.defined.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "2": { - "name": "punctuation.section.parens.control.defined.cpp" + "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.operator.wordlike.cpp" + }, + "6": { + "name": "keyword.operator.delete.array.cpp" + }, + "7": { + "name": "keyword.operator.delete.array.bracket.cpp" + }, + "8": { + "name": "keyword.operator.delete.cpp" + }, + "9": { + "name": "keyword.operator.new.cpp" } - }, - "end": "((?:\\)|(?\\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": { - "name": "punctuation.section.parens.begin.bracket.round.cpp" + "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.parens.end.bracket.round.cpp" + "name": "punctuation.section.arguments.end.bracket.round.function.member.cpp" } - } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] }, - "preprocessor_conditional_standalone": { - "match": "(?:^)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((import))\\s*(?:(?:(?:((<)[^>]*(>?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/)))|((\\\")[^\\\"]*(\\\"?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=\\/\\/))))|(((?:(?:(?>\\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+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=(?:\\/\\/|;)))))|((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:\\n|$)|(?=(?:\\/\\/|;))))\\s*(;?)", "captures": { "1": { "patterns": [ @@ -1109,674 +6451,434 @@ ] }, "5": { - "name": "punctuation.definition.directive.cpp" + "name": "keyword.control.directive.import.cpp" + }, + "7": { + "name": "string.quoted.other.lt-gt.include.cpp" + }, + "8": { + "name": "punctuation.definition.string.begin.cpp" + }, + "9": { + "name": "punctuation.definition.string.end.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": "string.quoted.double.include.cpp" + }, + "15": { + "name": "punctuation.definition.string.begin.cpp" + }, + "16": { + "name": "punctuation.definition.string.end.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.other.preprocessor.macro.include.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.terminator.statement.cpp" } }, - "name": "keyword.control.directive.$6.cpp" + "name": "meta.preprocessor.import.cpp" }, - "semicolon": { - "match": ";", - "name": "punctuation.terminator.statement.cpp" - }, - "comma": { - "match": ",", - "name": "punctuation.separator.delimiter.comma.cpp" - }, - "assignment_operator": { - "match": "\\=", - "name": "keyword.operator.assignment.cpp" - }, - "ever_present_context": { - "patterns": [ - { - "include": "#pragma_mark" - }, - { - "include": "#pragma" - }, - { - "include": "#include" - }, - { - "include": "#line" - }, - { - "include": "#diagnostic" - }, - { - "include": "#undef" - }, - { - "include": "#preprocessor_conditional_range" - }, - { - "include": "#single_line_macro" - }, - { - "include": "#macro" - }, - { - "include": "#preprocessor_conditional_standalone" - }, - { - "include": "#macro_argument" - }, - { - "include": "#comments" - }, - { - "include": "#line_continuation_character" + "ms_attributes": { + "name": "support.other.attribute.cpp", + "begin": "(__declspec\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.attribute.begin.cpp" } - ] - }, - "function_body_context": { - "patterns": [ - { - "include": "#ever_present_context" - }, - { - "include": "#using_namespace" - }, - { - "include": "#type_alias" - }, - { - "include": "#using_name" - }, - { - "include": "#namespace_alias" - }, - { - "include": "#typedef_class" - }, - { - "include": "#typedef_struct" - }, - { - "include": "#typedef_union" - }, - { - "include": "#typedef_keyword" - }, - { - "include": "#standard_declares" - }, - { - "include": "#class_block" - }, - { - "include": "#struct_block" - }, - { - "include": "#union_block" - }, - { - "include": "#enum_block" - }, - { - "include": "#access_control_keywords" - }, - { - "include": "#block" - }, - { - "include": "#static_assert" - }, - { - "include": "#assembly" - }, - { - "include": "#function_pointer" - }, - { - "include": "#switch_statement" - }, - { - "include": "#goto_statement" - }, - { - "include": "#evaluation_context" - }, - { - "include": "#label" + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.attribute.end.cpp" } - ] - }, - "evaluation_context": { + }, "patterns": [ - { - "include": "#ever_present_context" - }, - { - "include": "#string_context" - }, - { - "include": "#number_literal" - }, - { - "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" + "begin": "\\(", + "end": "\\)", + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#string_context" + } + ] }, { - "include": "#function_call" + "match": "(using)\\s+((?(?:(?>[^<>]*)\\g<9>?)+)>)\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)|(?=[;>\\[\\]=]))", "patterns": [ { - "include": "#ever_present_context" + "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": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<5>?)+)>)\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.namespace.cpp" + } + }, + "patterns": [ + { + "include": "$self" + } + ] }, { - "include": "#comma" + "name": "meta.tail.namespace.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$self" + } + ] } ] }, - "template_definition_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": "#scope_resolution_template_definition_inner_generated" - }, - { - "include": "#template_definition_argument" - }, - { - "include": "#template_argument_defaulted" - }, - { - "include": "#template_call_innards" - }, { "include": "#evaluation_context" } ] }, - "template_call_context": { - "patterns": [ - { - "include": "#ever_present_context" - }, - { - "include": "#template_call_range" - }, - { - "include": "#storage_types" - }, - { - "include": "#language_constants" - }, - { - "include": "#scope_resolution_template_call_inner_generated" - }, - { - "include": "#operators" - }, - { - "include": "#number_literal" - }, - { - "include": "#string_context" - }, - { - "include": "#comma_in_template_argument" - }, - { - "include": "#qualified_type" - } - ] - }, - "attributes_context": { - "patterns": [ - { - "include": "#cpp_attributes" - }, - { - "include": "#gcc_attributes" - }, - { - "include": "#ms_attributes" - }, - { - "include": "#alignas_attribute" - } - ] - }, - "storage_types": { - "patterns": [ - { - "include": "#storage_specifiers" - }, - { - "include": "#primitive_types" - }, - { - "include": "#non_primitive_types" - }, - { - "include": "#pthread_types" - }, - { - "include": "#posix_reserved_types" - }, - { - "include": "#decltype" - }, - { - "include": "#typename" - } - ] - }, - "block_comment": { - "name": "comment.block.cpp", - "begin": "\\s*+(\\/\\*)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.begin.cpp" - } - }, - "end": "(\\*\\/)", - "endCaptures": { - "1": { - "name": "punctuation.definition.comment.end.cpp" - } - } - }, - "line_comment": { - "name": "comment.line.double-slash.cpp", - "begin": "\\s*+(\\/\\/)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.cpp" - } - }, - "end": "(?<=\\n)(?[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*(?:\\n|$)))|(^\\s*((\\/\\*)\\s*?((?>[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*\\*\\/)))", + "non_primitive_types": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s*)(\\/\\/[!\\/]+)(.*)", - "captures": { - "1": { - "name": "punctuation.definition.comment.documentation.cpp" - }, - "2": { - "patterns": [ - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.italic.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.bold.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.inline.raw.string.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "variable.parameter.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc.cpp" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.cpp" - } - ] - } - }, - "name": "comment.line.double-slash.documentation.cpp" - }, - { - "match": "(\\/\\*[!*]+(?=\\s))(.+)([!*]*\\*\\/)", - "captures": { - "1": { - "name": "punctuation.definition.comment.begin.documentation.cpp" - }, - "2": { - "patterns": [ - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.italic.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.bold.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.inline.raw.string.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "variable.parameter.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc.cpp" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.cpp" - } - ] - }, - "3": { - "name": "punctuation.definition.comment.end.documentation.cpp" - } - }, - "name": "comment.block.documentation.cpp" - }, - { - "name": "comment.block.documentation.cpp", - "begin": "((?>\\s*)\\/\\*[!*]+(?:(?:\\n|$)|(?=\\s)))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.comment.begin.documentation.cpp" - } - }, - "end": "([!*]*\\*\\/)", - "endCaptures": { - "1": { - "name": "punctuation.definition.comment.end.documentation.cpp" - } - }, "patterns": [ { - "match": "(?<=[\\s*!\\/])[\\\\@](?:callergraph|callgraph|else|endif|f\\$|f\\[|f\\]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|\\$|\\#|<|>|%|\"|\\.|=|::|\\||\\-\\-|\\-\\-\\-)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:a|em|e))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.italic.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]b)\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.bold.doxygen.cpp" - } - } - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@](?:c|p))\\s+(\\S+)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "markup.inline.raw.string.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:a|anchor|b|c|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|e|em|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "((?<=[\\s*!\\/])[\\\\@]param)\\s+(\\b\\w+\\b)", - "captures": { - "1": { - "name": "storage.type.class.doxygen.cpp" - }, - "2": { - "name": "variable.parameter.cpp" - } - } - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:arg|attention|author|authors|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remark|remarks|result|return|returns|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?<=[\\s*!\\/])[\\\\@](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\b(?:\\{[^}]*\\})?", - "name": "storage.type.class.doxygen.cpp" - }, - { - "match": "(?:\\b[A-Z]+:|@[a-z_]+:)", - "name": "storage.type.class.gtkdoc.cpp" - }, - { - "match": "[\\\\@]\\S++(?!(?:\\n|$))", - "name": "invalid.unknown.documentation.command.cpp" + "include": "#inline_comment" } ] }, - { - "include": "#emacs_file_banner" + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - { - "include": "#block_comment" + "3": { + "name": "comment.block.cpp" }, - { - "include": "#line_comment" + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] }, - { - "include": "#invalid_comment_end" + "5": { + "name": "storage.type.cpp storage.type.built-in.cpp" } - ] + } }, "number_literal": { "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\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": [ - { - "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": "#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": [ - { - "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": "#evaluation_context" - } - ] - }, - "pthread_types": { - "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)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(((?:private|protected|public))\\s*(:))", - "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": "storage.type.modifier.access.control.$6.cpp" - }, - "7": { - "name": "punctuation.separator.colon.access.control.cpp" - } - } - }, - "exception_keywords": { - "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)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(delete)\\s*(\\[\\])|(delete))|(new))(?!\\w))", - "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": "keyword.operator.wordlike.cpp" - }, - "6": { - "name": "keyword.operator.delete.array.cpp" - }, - "7": { - "name": "keyword.operator.delete.array.bracket.cpp" - }, - "8": { - "name": "keyword.operator.delete.cpp" - }, - "9": { - "name": "keyword.operator.new.cpp" - } - } - }, - "control_flow_keywords": { - "match": "((?:(?:(?>\\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}))*)", - "captures": { - "1": { - "name": "keyword.control.goto.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.label.call.cpp" - } - } - }, - "label": { - "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\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": "entity.name.label.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.separator.label.cpp" - } - } - }, - "default_statement": { - "name": "meta.conditional.case.cpp", - "begin": "((?:(?:(?>\\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": { - "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" - }, - { - "include": "#c_conditional_context" - } - ] - }, - "switch_statement": { - "name": "meta.block.switch.cpp", - "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=[;>\\[\\]=]))", - "patterns": [ - { - "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": "$self" - } - ] - }, - { - "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": "$self" - }, - { - "include": "#block_innards" - } - ] - }, - { - "name": "meta.tail.switch.cpp", - "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", - "patterns": [ - { - "include": "$self" - } - ] - } - ] - }, - "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": [ - { - "include": "#attributes_context" - }, - { - "begin": "\\(", - "end": "\\)", - "patterns": [ - { - "include": "#attributes_context" - }, - { - "include": "#string_context" - } - ] - }, - { - "match": "(using)\\s+((?(?:(?>[^<>]*)\\g<1>?)+)>)\\s*", - "captures": { - "0": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "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": "(>)", - "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" - }, - "3": { - "name": "meta.template.definition.cpp", - "patterns": [ - { - "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": [ - { - "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" - } - }, - "patterns": [ - { - "include": "#template_call_context" - } - ] - }, - { - "include": "#template_definition_context" - } - ] - }, - "template_argument_defaulted": { - "match": "(?<=<|,)\\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+)*)((?:[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": { - "name": "storage.type.template.cpp" - }, - "2": { - "name": "entity.name.type.template.cpp" - }, - "3": { - "name": "keyword.operator.assignment.cpp" - } - } - }, - "template_definition_argument": { - "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}))*)|((?:(?:[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": [ - { - "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": [ - { - "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" - } - ] - }, - "7": { - "name": "entity.name.type.template.cpp" - }, - "8": { - "name": "storage.type.template.cpp" - }, - "9": { - "name": "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": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" - } - } - }, - "scope_resolution_template_call": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_template_call_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_template_call_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_template_call_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.template.call.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" - } - } - }, - "scope_resolution_template_definition": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_template_definition_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_template_definition_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_template_definition_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.template.definition.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" - } - } - }, - "scope_resolution_function_call": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_function_call_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_function_call_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_function_call_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.function.call.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" - } - } - }, - "scope_resolution_function_definition": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_function_definition_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.function.definition.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" - } - } - }, - "scope_resolution_namespace_alias": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_namespace_alias_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_namespace_alias_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_namespace_alias_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.namespace.alias.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" - } - } - }, - "scope_resolution_namespace_using": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_namespace_using_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_namespace_using_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_namespace_using_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.namespace.using.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" - } - } - }, - "scope_resolution_namespace_block": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_namespace_block_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_namespace_block_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_namespace_block_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.namespace.block.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" - } - } - }, - "scope_resolution_parameter": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_parameter_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_parameter_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_parameter_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.parameter.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" - } - } - }, - "scope_resolution_function_definition_operator_overload": { - "match": "(::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", - "captures": { - "0": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_operator_overload_inner_generated" - } - ] - }, - "1": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" - }, - "3": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - } - } - }, - "scope_resolution_function_definition_operator_overload_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", - "captures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_operator_overload_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.scope-resolution.function.definition.operator-overload.cpp" - }, - "7": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "9": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" - } - } - }, - "qualified_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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(?![\\w<:.])", - "captures": { - "0": { - "name": "meta.qualified_type.cpp", - "patterns": [ - { - "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", - "captures": { - "1": { - "name": "meta.qualified_type.cpp", - "patterns": [ - { - "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" - } - ] - }, - "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" - } - ] - } - } - }, - "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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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": "(?\\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" - } - ] - }, - "61": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "62": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "63": { - "name": "comment.block.cpp" - }, - "64": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "65": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "66": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "67": { - "name": "comment.block.cpp" - }, - "68": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "69": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "70": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "71": { - "name": "comment.block.cpp" - }, - "72": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "73": { - "name": "punctuation.definition.begin.bracket.square.cpp" - }, - "74": { - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "75": { - "name": "punctuation.definition.end.bracket.square.cpp" - }, - "76": { - "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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\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": "(?))((?:(?:(?>\\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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<69>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<69>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<69>?)+)>)\\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)))((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<69>?)+)>)\\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": "(?\\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" - } - ] - }, - "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": [ - { - "include": "#inline_comment" - } - ] - }, - "49": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "50": { - "name": "comment.block.cpp" - }, - "51": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "52": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "53": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "54": { - "name": "comment.block.cpp" - }, - "55": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "56": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "57": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "58": { - "name": "comment.block.cpp" - }, - "59": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "60": { - "name": "storage.type.modifier.calling-convention.cpp" - }, - "61": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "62": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "63": { - "name": "comment.block.cpp" - }, - "64": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "65": { - "patterns": [ - { - "include": "#scope_resolution_function_definition_inner_generated" - } - ] - }, - "66": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" - }, - "68": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "70": { - "name": "entity.name.function.definition.cpp" - }, - "71": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "72": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "73": { - "name": "comment.block.cpp" - }, - "74": { - "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": "$self" - } - ] - }, - { - "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": "$self" - } - ] - } - ] - }, "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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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)))((?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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)))(?=\\<|\\())", + "begin": "((?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\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)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(?:(?:((?:delete\\[\\]|delete|new\\[\\]|<=>|<<=|new|>>=|\\->\\*|\\/=|%=|&=|>=|\\|=|\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|<<|>>|\\-\\-|<=|\\^=|==|!=|&&|\\|\\||\\+=|\\-=|\\*=|,|\\+|\\-|!|~|\\*|&|\\*|\\/|%|\\+|\\-|<|>|&|\\^|\\||=))|((?\\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" @@ -5681,7 +7162,7 @@ "name": "meta.qualified_type.cpp", "patterns": [ { - "match": "(?\\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": "#evaluation_context" - } - ] - }, - "function_call": { - "begin": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\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)))(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?(\\()", - "beginCaptures": { - "1": { - "patterns": [ - { - "include": "#scope_resolution_function_call_inner_generated" - } - ] - }, - "2": { - "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" - }, - "4": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "6": { - "name": "entity.name.function.call.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": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "13": { - "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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", - "beginCaptures": { - "1": { - "name": "meta.qualified_type.cpp", - "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)))((?\\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": "((?(?:(?>[^<>]*)\\g<3>?)+)>)\\s*)?(\\()", - "beginCaptures": { - "1": { - "name": "entity.name.function.call.initializer.cpp" - }, - "2": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "4": { - "name": "punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp" - } - }, - "end": "(\\))", - "endCaptures": { - "1": { - "name": "punctuation.section.arguments.end.bracket.round.function.call.initializer.cpp" - } - }, - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - { - "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": "$self" - } - ] - } - ] - }, - "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)))((?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\16((?:(?:(?>\\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": "((?(?:(?>[^<>]*)\\g<3>?)+)>)\\s*)?(\\()", - "beginCaptures": { - "1": { - "name": "entity.name.function.call.initializer.cpp" - }, - "2": { - "name": "meta.template.call.cpp", - "patterns": [ - { - "include": "#template_call_range" - } - ] - }, - "4": { - "name": "punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp" - } - }, - "end": "(\\))", - "endCaptures": { - "1": { - "name": "punctuation.section.arguments.end.bracket.round.function.call.initializer.cpp" - } - }, - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - { - "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": "$self" - } - ] - } - ] - }, - "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": "$self" - } - ] - }, - { - "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": "$self" - } - ] - } - ] - }, - "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)))((?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\16((?:(?:(?>\\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": "$self" - } - ] - }, - { - "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": "$self" - } - ] - } - ] - }, "operators": { "patterns": [ { @@ -8166,1973 +7917,19 @@ } ] }, - "wordlike_operators": { + "over_qualified_types": { "patterns": [ { - "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" - } - ] - }, - "sizeof_variadic_operator": { - "contentName": "meta.arguments.operator.sizeof.variadic.cpp", - "begin": "(\\bsizeof\\.\\.\\.)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", - "beginCaptures": { - "1": { - "name": "keyword.operator.functionlike.cpp keyword.operator.sizeof.variadic.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.variadic.cpp" - } - }, - "end": "(\\))", - "endCaptures": { - "1": { - "name": "punctuation.section.arguments.end.bracket.round.operator.sizeof.variadic.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": "#parameter_struct" }, { - "include": "#string_context" + "include": "#parameter_enum" }, { - "include": "#number_literal" + "include": "#parameter_union" }, { - "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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" - } - ] - }, - "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" - } - ] - }, - "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": { - "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" - }, - "42": { - "name": "punctuation.definition.function.pointer.dereference.cpp" - }, - "43": { - "name": "variable.other.definition.pointer.function.cpp" - }, - "44": { - "name": "punctuation.definition.begin.bracket.square.cpp" - }, - "45": { - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "46": { - "name": "punctuation.definition.end.bracket.square.cpp" - }, - "47": { - "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" - }, - "48": { - "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))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" - } - ] - }, - "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" - } - ] - }, - "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": { - "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" - }, - "42": { - "name": "punctuation.definition.function.pointer.dereference.cpp" - }, - "43": { - "name": "variable.parameter.pointer.function.cpp" - }, - "44": { - "name": "punctuation.definition.begin.bracket.square.cpp" - }, - "45": { - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "46": { - "name": "punctuation.definition.end.bracket.square.cpp" - }, - "47": { - "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" - }, - "48": { - "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" - } - ] - }, - "typedef_function_pointer": { - "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" - } - ] - }, - "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" - } - ] - }, - "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": { - "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" - }, - "42": { - "name": "punctuation.definition.function.pointer.dereference.cpp" - }, - "43": { - "name": "entity.name.type.alias.cpp entity.name.type.pointer.function.cpp" - }, - "44": { - "name": "punctuation.definition.begin.bracket.square.cpp" - }, - "45": { - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "46": { - "name": "punctuation.definition.end.bracket.square.cpp" - }, - "47": { - "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" - }, - "48": { - "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": "#function_pointer_parameter" - }, - { - "include": "#memory_operators" - }, - { - "include": "#builtin_storage_type_initilizer" - }, - { - "include": "#curly_initializer" - }, - { - "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" + "include": "#parameter_class" } ] }, @@ -10186,7 +7983,7 @@ "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)))(?=,|\\)|=)", + "match": "((?:((?:volatile|register|restrict|static|extern|const))((?:(?:(?>\\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": [ @@ -10422,7 +8219,7 @@ "include": "#scope_resolution_parameter_inner_generated" }, { - "match": "(?:class|struct|union|enum)", + "match": "(?:struct|class|union|enum)", "name": "storage.type.$0.cpp" }, { @@ -10524,7 +8321,7 @@ ] }, { - "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)))((?\\*|->)))((?:(?:[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(?!\\())", + "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" } ] }, - "2": { + "3": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "3": { + "4": { "name": "comment.block.cpp" }, - "4": { + "5": { "patterns": [ { "match": "\\*\\/", @@ -10658,134 +8458,23 @@ } ] }, - "5": { - "name": "variable.language.this.cpp" - }, "6": { - "name": "variable.other.object.access.cpp" + "name": "entity.name.type.class.parameter.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": { + "8": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "3": { + "9": { "name": "comment.block.cpp" }, - "4": { + "10": { "patterns": [ { "match": "\\*\\/", @@ -10797,22 +8486,14 @@ } ] }, - "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": { + "11": { "patterns": [ { - "match": "(?<=(?:\\.\\*|\\.|->|->\\*))\\s*(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))", + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", "captures": { "1": { "patterns": [ @@ -10838,614 +8519,498 @@ "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" } - } + }, + "name": "invalid.illegal.reference-type.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" + "match": "\\&", + "name": "storage.modifier.reference.cpp" } ] }, - "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": "(?(?:(?>[^<>]*)\\g<7>?)+)>)\\s*)?::)*\\s*+)?((?(?:(?>[^<>]*)\\g<9>?)+)>)\\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": "((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<5>?)+)>)\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.namespace.cpp" - } - }, - "patterns": [ - { - "include": "$self" - } - ] - }, - { - "name": "meta.tail.namespace.cpp", - "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", - "patterns": [ - { - "include": "$self" - } - ] - } - ] - }, - "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": "$self" - } - ] - } - ] - }, - "enumerator_list": { - "match": "((?(?:(?>[^<>]*)\\g<15>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?(::))?\\s*((?|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", - "endCaptures": { + } + }, + "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": "punctuation.terminator.statement.cpp" + "name": "storage.type.enum.parameter.cpp" }, "2": { - "name": "punctuation.terminator.statement.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": "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_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" + } + ] } }, - "patterns": [ - { - "name": "meta.head.enum.cpp", - "begin": "\\G ?", - "end": "((?:\\{|<%|\\?\\?<|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.enum.cpp" - } - }, - "patterns": [ - { - "include": "$self" - } - ] - }, - { - "name": "meta.body.enum.cpp", - "begin": "(?<=\\{|<%|\\?\\?<)", - "end": "(\\}|%>|\\?\\?>)", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.enum.cpp" - } - }, - "patterns": [ - { - "include": "#ever_present_context" - }, - { - "include": "#enumerator_list" - }, - { - "include": "#comments" - }, - { - "include": "#comma" - }, - { - "include": "#semicolon" - } - ] - }, - { - "name": "meta.tail.enum.cpp", - "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", - "patterns": [ - { - "include": "$self" - } - ] + "end": "(?:(?=\\))|(,))", + "endCaptures": { + "1": { + "name": "punctuation.separator.delimiter.comma.cpp" } - ] - }, - "inheritance_context": { + }, "patterns": [ { "include": "#ever_present_context" }, { - "match": ",", - "name": "punctuation.separator.delimiter.comma.inheritance.cpp" + "include": "#function_pointer_parameter" }, { - "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?: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|class|struct|union|enum|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|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)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))", + "include": "#curly_initializer" + }, + { + "include": "#decltype" + }, + { + "include": "#vararg_ellipses" + }, + { + "match": "((?:((?:volatile|register|restrict|static|extern|const))((?:(?:(?>\\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": { - "name": "meta.qualified_type.cpp", "patterns": [ - { - "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" } ] }, - "class_block": { - "name": "meta.block.class.cpp", - "begin": "((((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))|((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\))))|(?={))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(final)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)((?>[^{]*)))?))", - "beginCaptures": { + "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": "meta.head.class.cpp" + "name": "storage.type.struct.parameter.cpp" }, - "3": { - "name": "storage.type.$3.cpp" - }, - "4": { + "2": { "patterns": [ { "include": "#inline_comment" } ] }, - "5": { + "3": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "6": { + "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": [ { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" + "include": "#inline_comment" } ] }, "8": { - "patterns": [ - { - "include": "#attributes_context" - }, - { - "include": "#number_literal" - } - ] - }, - "9": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "10": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "11": { + "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": [ { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" + "include": "#inline_comment" } ] }, "13": { - "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" - }, - "14": { - "patterns": [ - { - "include": "#inline_comment" - } - ] - }, - "15": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "16": { + "14": { "name": "comment.block.cpp" }, - "17": { + "15": { "patterns": [ { "match": "\\*\\/", @@ -11667,58 +9574,45 @@ } ] }, - "18": { + "16": { "patterns": [ { - "include": "#attributes_context" - }, - { - "include": "#number_literal" + "include": "#inline_comment" } ] }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, "19": { "patterns": [ { - "include": "#inline_comment" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } ] }, "20": { - "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" - }, - "21": { - "name": "comment.block.cpp" - }, - "22": { - "patterns": [ - { - "match": "\\*\\/", - "name": "comment.block.cpp punctuation.definition.comment.end.cpp" - }, - { - "match": "\\*", - "name": "comment.block.cpp" - } - ] - }, - "23": { - "name": "entity.name.type.$3.cpp" - }, - "24": { "patterns": [ { "include": "#inline_comment" } ] }, - "25": { + "21": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "26": { + "22": { "name": "comment.block.cpp" }, - "27": { + "23": { "patterns": [ { "match": "\\*\\/", @@ -11730,8 +9624,33 @@ } ] }, + "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": { - "name": "storage.type.modifier.final.cpp" + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] }, "29": { "patterns": [ @@ -11782,85 +9701,2456 @@ "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" }, - "37": { - "name": "punctuation.separator.colon.inheritance.cpp" - }, - "38": { + "2": { "patterns": [ { - "include": "#inheritance_context" + "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" } ] } + } + }, + "parentheses": { + "name": "meta.parens.cpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parens.begin.bracket.round.cpp" + } }, - "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "end": "(\\))", "endCaptures": { "1": { - "name": "punctuation.terminator.statement.cpp" - }, - "2": { - "name": "punctuation.terminator.statement.cpp" + "name": "punctuation.section.parens.end.bracket.round.cpp" } }, "patterns": [ { - "name": "meta.head.class.cpp", - "begin": "\\G ?", - "end": "((?:\\{|<%|\\?\\?<|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.class.cpp" - } - }, + "include": "#over_qualified_types" + }, + { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*pragma\\b)", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.pragma.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.definition.directive.cpp" + } + }, + "end": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*pragma\\s+mark)\\s+(.*)", + "captures": { + "1": { + "name": "keyword.control.directive.pragma.pragma-mark.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.definition.directive.cpp" + }, + "7": { + "name": "entity.name.tag.pragma-mark.cpp" + } + }, + "name": "meta.preprocessor.pragma.cpp" + }, + "predefined_macros": { + "patterns": [ + { + "match": "\\b(__cplusplus|__DATE__|__FILE__|__LINE__|__STDC__|__STDC_HOSTED__|__STDC_NO_COMPLEX__|__STDC_VERSION__|__STDCPP_THREADS__|__TIME__|NDEBUG|__OBJC__|__ASSEMBLER__|__ATOM__|__AVX__|__AVX2__|_CHAR_UNSIGNED|__CLR_VER|_CONTROL_FLOW_GUARD|__COUNTER__|__cplusplus_cli|__cplusplus_winrt|_CPPRTTI|_CPPUNWIND|_DEBUG|_DLL|__FUNCDNAME__|__FUNCSIG__|__FUNCTION__|_INTEGRAL_MAX_BITS|__INTELLISENSE__|_ISO_VOLATILE|_KERNEL_MODE|_M_AMD64|_M_ARM|_M_ARM_ARMV7VE|_M_ARM_FP|_M_ARM64|_M_CEE|_M_CEE_PURE|_M_CEE_SAFE|_M_FP_EXCEPT|_M_FP_FAST|_M_FP_PRECISE|_M_FP_STRICT|_M_IX86|_M_IX86_FP|_M_X64|_MANAGED|_MSC_BUILD|_MSC_EXTENSIONS|_MSC_FULL_VER|_MSC_VER|_MSVC_LANG|__MSVC_RUNTIME_CHECKS|_MT|_NATIVE_WCHAR_T_DEFINED|_OPENMP|_PREFAST|__TIMESTAMP__|_VC_NO_DEFAULTLIB|_WCHAR_T_DEFINED|_WIN32|_WIN64|_WINRT_DLL|_ATL_VER|_MFC_VER|__GFORTRAN__|__GNUC__|__GNUC_MINOR__|__GNUC_PATCHLEVEL__|__GNUG__|__STRICT_ANSI__|__BASE_FILE__|__INCLUDE_LEVEL__|__ELF__|__VERSION__|__OPTIMIZE__|__OPTIMIZE_SIZE__|__NO_INLINE__|__GNUC_STDC_INLINE__|__CHAR_UNSIGNED__|__WCHAR_UNSIGNED__|__REGISTER_PREFIX__|__REGISTER_PREFIX__|__SIZE_TYPE__|__PTRDIFF_TYPE__|__WCHAR_TYPE__|__WINT_TYPE__|__INTMAX_TYPE__|__UINTMAX_TYPE__|__SIG_ATOMIC_TYPE__|__INT8_TYPE__|__INT16_TYPE__|__INT32_TYPE__|__INT64_TYPE__|__UINT8_TYPE__|__UINT16_TYPE__|__UINT32_TYPE__|__UINT64_TYPE__|__INT_LEAST8_TYPE__|__INT_LEAST16_TYPE__|__INT_LEAST32_TYPE__|__INT_LEAST64_TYPE__|__UINT_LEAST8_TYPE__|__UINT_LEAST16_TYPE__|__UINT_LEAST32_TYPE__|__UINT_LEAST64_TYPE__|__INT_FAST8_TYPE__|__INT_FAST16_TYPE__|__INT_FAST32_TYPE__|__INT_FAST64_TYPE__|__UINT_FAST8_TYPE__|__UINT_FAST16_TYPE__|__UINT_FAST32_TYPE__|__UINT_FAST64_TYPE__|__INTPTR_TYPE__|__UINTPTR_TYPE__|__CHAR_BIT__|__SCHAR_MAX__|__WCHAR_MAX__|__SHRT_MAX__|__INT_MAX__|__LONG_MAX__|__LONG_LONG_MAX__|__WINT_MAX__|__SIZE_MAX__|__PTRDIFF_MAX__|__INTMAX_MAX__|__UINTMAX_MAX__|__SIG_ATOMIC_MAX__|__INT8_MAX__|__INT16_MAX__|__INT32_MAX__|__INT64_MAX__|__UINT8_MAX__|__UINT16_MAX__|__UINT32_MAX__|__UINT64_MAX__|__INT_LEAST8_MAX__|__INT_LEAST16_MAX__|__INT_LEAST32_MAX__|__INT_LEAST64_MAX__|__UINT_LEAST8_MAX__|__UINT_LEAST16_MAX__|__UINT_LEAST32_MAX__|__UINT_LEAST64_MAX__|__INT_FAST8_MAX__|__INT_FAST16_MAX__|__INT_FAST32_MAX__|__INT_FAST64_MAX__|__UINT_FAST8_MAX__|__UINT_FAST16_MAX__|__UINT_FAST32_MAX__|__UINT_FAST64_MAX__|__INTPTR_MAX__|__UINTPTR_MAX__|__WCHAR_MIN__|__WINT_MIN__|__SIG_ATOMIC_MIN__|__SCHAR_WIDTH__|__SHRT_WIDTH__|__INT_WIDTH__|__LONG_WIDTH__|__LONG_LONG_WIDTH__|__PTRDIFF_WIDTH__|__SIG_ATOMIC_WIDTH__|__SIZE_WIDTH__|__WCHAR_WIDTH__|__WINT_WIDTH__|__INT_LEAST8_WIDTH__|__INT_LEAST16_WIDTH__|__INT_LEAST32_WIDTH__|__INT_LEAST64_WIDTH__|__INT_FAST8_WIDTH__|__INT_FAST16_WIDTH__|__INT_FAST32_WIDTH__|__INT_FAST64_WIDTH__|__INTPTR_WIDTH__|__INTMAX_WIDTH__|__SIZEOF_INT__|__SIZEOF_LONG__|__SIZEOF_LONG_LONG__|__SIZEOF_SHORT__|__SIZEOF_POINTER__|__SIZEOF_FLOAT__|__SIZEOF_DOUBLE__|__SIZEOF_LONG_DOUBLE__|__SIZEOF_SIZE_T__|__SIZEOF_WCHAR_T__|__SIZEOF_WINT_T__|__SIZEOF_PTRDIFF_T__|__BYTE_ORDER__|__ORDER_LITTLE_ENDIAN__|__ORDER_BIG_ENDIAN__|__ORDER_PDP_ENDIAN__|__FLOAT_WORD_ORDER__|__DEPRECATED|__EXCEPTIONS|__GXX_RTTI|__USING_SJLJ_EXCEPTIONS__|__GXX_EXPERIMENTAL_CXX0X__|__GXX_WEAK__|__NEXT_RUNTIME__|__LP64__|_LP64|__SSP__|__SSP_ALL__|__SSP_STRONG__|__SSP_EXPLICIT__|__SANITIZE_ADDRESS__|__SANITIZE_THREAD__|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8|__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16|__HAVE_SPECULATION_SAFE_VALUE|__GCC_HAVE_DWARF2_CFI_ASM|__FP_FAST_FMA|__FP_FAST_FMAF|__FP_FAST_FMAL|__FP_FAST_FMAF16|__FP_FAST_FMAF32|__FP_FAST_FMAF64|__FP_FAST_FMAF128|__FP_FAST_FMAF32X|__FP_FAST_FMAF64X|__FP_FAST_FMAF128X|__GCC_IEC_559|__GCC_IEC_559_COMPLEX|__NO_MATH_ERRNO__|__has_builtin|__has_feature|__has_extension|__has_cpp_attribute|__has_c_attribute|__has_attribute|__has_declspec_attribute|__is_identifier|__has_include|__has_include_next|__has_warning|__BASE_FILE__|__FILE_NAME__|__clang__|__clang_major__|__clang_minor__|__clang_patchlevel__|__clang_version__|__fp16|_Float16)\\b", + "captures": { + "1": { + "name": "entity.name.other.preprocessor.macro.predefined.$1.cpp" + } + } + }, + { + "match": "\\b__([A-Z_]+)__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.probably.$1.cpp" + } + ] + }, + "preprocessor_conditional_context": { + "patterns": [ + { + "include": "#preprocessor_conditional_defined" + }, + { + "include": "#comments" + }, + { + "include": "#language_constants" + }, + { + "include": "#string_context_c" + }, + { + "include": "#preprocessor_number_literal" + }, + { + "include": "#operators" + }, + { + "include": "#predefined_macros" + }, + { + "include": "#macro_name" + }, + { + "include": "#line_continuation_character" + } + ] + }, + "preprocessor_conditional_defined": { + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?:(?:ifndef|ifdef)|if)))", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.conditional.$7.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.definition.directive.cpp" + } + }, + "end": "(?:^)(?!\\s*+#\\s*(?:else|endif))", + "patterns": [ + { + "name": "meta.preprocessor.conditional.cpp", + "begin": "\\G(?<=ifndef|ifdef|if)", + "end": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(?![\\w<:.])", + "captures": { + "0": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?|\\?\\?>)", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.class.cpp" - } - }, + "16": { + "name": "entity.name.scope-resolution.cpp" + }, + "17": { + "name": "meta.template.call.cpp", "patterns": [ { - "include": "#function_pointer" + "include": "#template_call_range" + } + ] + }, + "19": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.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" }, { - "include": "#static_assert" + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "24": { + "name": "entity.name.type.cpp" + }, + "25": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "qualifiers_and_specifiers_post_parameters": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_function_call": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_function_call_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_function_call_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_call_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.function.call.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" + } + } + }, + "scope_resolution_function_definition": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_function_definition_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.function.definition.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" + } + } + }, + "scope_resolution_function_definition_operator_overload": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_operator_overload_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_function_definition_operator_overload_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_operator_overload_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.function.definition.operator-overload.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp" + } + } + }, + "scope_resolution_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + } + } + }, + "scope_resolution_namespace_alias": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_namespace_alias_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_namespace_alias_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_namespace_alias_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.namespace.alias.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" + } + } + }, + "scope_resolution_namespace_block": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_namespace_block_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_namespace_block_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_namespace_block_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.namespace.block.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" + } + } + }, + "scope_resolution_namespace_using": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_namespace_using_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_namespace_using_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_namespace_using_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.namespace.using.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" + } + } + }, + "scope_resolution_parameter": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_parameter_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_parameter_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_parameter_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.parameter.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp" + } + } + }, + "scope_resolution_template_call": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_template_call_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_template_call_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_template_call_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.template.call.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" + } + } + }, + "scope_resolution_template_definition": { + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_template_definition_inner_generated" + } + ] + }, + "1": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + } + } + }, + "scope_resolution_template_definition_inner_generated": { + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<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*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_template_definition_inner_generated" + } + ] + }, + "2": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" + }, + "4": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "6": { + "name": "entity.name.scope-resolution.template.definition.cpp" + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "9": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" + } + } + }, + "semicolon": { + "match": ";", + "name": "punctuation.terminator.statement.cpp" + }, + "simple_type": { + "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", + "captures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "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" + } + ] + }, + "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" + } + ] + } + } + }, + "single_line_macro": { + "match": "^((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))#define.*(?\\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" + } + ] + }, + "sizeof_variadic_operator": { + "contentName": "meta.arguments.operator.sizeof.variadic.cpp", + "begin": "(\\bsizeof\\.\\.\\.)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.functionlike.cpp keyword.operator.sizeof.variadic.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.variadic.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.operator.sizeof.variadic.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "square_brackets": { + "name": "meta.bracket.square.access.cpp", + "begin": "([a-zA-Z_][a-zA-Z_0-9]*|(?<=[\\]\\)]))?(\\[)(?!\\])", + "beginCaptures": { + "1": { + "name": "variable.other.object.cpp" + }, + "2": { + "name": "punctuation.definition.begin.bracket.square.cpp" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.end.bracket.square.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "standard_declares": { + "patterns": [ + { + "include": "#struct_declare" + }, + { + "include": "#union_declare" + }, + { + "include": "#enum_declare" + }, + { + "include": "#class_declare" + } + ] + }, + "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" } ] }, { - "name": "meta.tail.class.cpp", - "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", + "include": "#evaluation_context" + } + ] + }, + "storage_specifiers": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))|((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\))))|(?={))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(final)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)((?>[^{]*)))?))", - "beginCaptures": { + "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(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "captures": { "1": { - "name": "meta.head.union.cpp" + "name": "storage.type.struct.declare.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "3": { - "name": "storage.type.$3.cpp" + "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" + } + ] + } + } + }, + "switch_conditional_parentheses": { + "name": "meta.conditional.switch.cpp", + "begin": "((?:(?:(?>\\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": "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" + }, + { + "include": "#c_conditional_context" + } + ] + }, + "switch_statement": { + "name": "meta.block.switch.cpp", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "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": "$self" + } + ] + }, + { + "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": "$self" + }, + { + "include": "#block_innards" + } + ] + }, + { + "name": "meta.tail.switch.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + "template_argument_defaulted": { + "match": "(?<=<|,)\\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+)*)((?:[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": { + "name": "storage.type.template.cpp" + }, + "2": { + "name": "entity.name.type.template.cpp" + }, + "3": { + "name": "keyword.operator.assignment.cpp" + } + } + }, + "template_call_context": { + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#template_call_range" + }, + { + "include": "#storage_types" + }, + { + "include": "#language_constants" + }, + { + "include": "#scope_resolution_template_call_inner_generated" + }, + { + "include": "#operators" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context" + }, + { + "include": "#comma_in_template_argument" + }, + { + "include": "#qualified_type" + } + ] + }, + "template_call_innards": { + "match": "((?(?:(?>[^<>]*)\\g<1>?)+)>)\\s*", + "captures": { + "0": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "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": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.section.angle-brackets.end.template.call.cpp" + } + }, + "patterns": [ + { + "include": "#template_call_context" + } + ] + }, + "template_definition": { + "name": "meta.template.definition.cpp", + "begin": "(?)", + "endCaptures": { + "1": { + "name": "punctuation.section.angle-brackets.end.template.definition.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" + } + }, + "patterns": [ + { + "include": "#template_call_context" + } + ] + }, + { + "include": "#template_definition_context" + } + ] + }, + "template_definition_argument": { + "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}))*)|((?:(?:[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": [ + { + "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": [ + { + "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" + } + ] + }, + "7": { + "name": "entity.name.type.template.cpp" + }, + "8": { + "name": "storage.type.template.cpp" + }, + "9": { + "name": "punctuation.vararg-ellipses.template.definition.cpp" + }, + "10": { + "name": "entity.name.type.template.cpp" + }, + "11": { + "name": "punctuation.separator.delimiter.comma.template.argument.cpp" + } + } + }, + "template_definition_context": { + "patterns": [ + { + "include": "#scope_resolution_template_definition_inner_generated" + }, + { + "include": "#template_definition_argument" + }, + { + "include": "#template_argument_defaulted" + }, + { + "include": "#template_call_innards" + }, + { + "include": "#evaluation_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": "#template_definition_context" + } + ] + }, + "4": { + "name": "punctuation.section.angle-brackets.end.template.definition.cpp" + } + } + }, + "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": "#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" + } + ] + }, + "the_this_keyword": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))\\s*(\\=)\\s*((?:typename)?)\\s*((?:(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\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": "(?|\\?\\?>)\\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" - } - }, + "39": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "40": { + "name": "comment.block.cpp" + }, + "41": { "patterns": [ { - "include": "#ever_present_context" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" }, { - "include": "#inheritance_context" - }, + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "43": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "44": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "46": { + "name": "meta.template.call.cpp", + "patterns": [ { "include": "#template_call_range" } ] }, - { - "name": "meta.body.union.cpp", - "begin": "(?<=\\{|<%|\\?\\?<)", - "end": "(\\}|%>|\\?\\?>)", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.union.cpp" - } - }, + "48": { + "name": "entity.name.scope-resolution.cpp" + }, + "49": { + "name": "meta.template.call.cpp", "patterns": [ { - "include": "#function_pointer" - }, - { - "include": "#static_assert" - }, - { - "include": "#constructor_inline" - }, - { - "include": "#destructor_inline" - }, - { - "include": "$self" + "include": "#template_call_range" } ] }, - { - "name": "meta.tail.union.cpp", - "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", - "patterns": [ - { - "include": "$self" - } - ] - } - ] - }, - "extern_block": { - "name": "meta.block.extern.cpp", - "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(extern)(?=\\s*\\\"))", - "beginCaptures": { - "1": { - "name": "meta.head.extern.cpp" + "51": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" }, - "2": { + "52": { "patterns": [ { "include": "#inline_comment" } ] }, - "3": { + "53": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "4": { + "54": { "name": "comment.block.cpp" }, - "5": { + "55": { "patterns": [ { "match": "\\*\\/", @@ -12486,64 +13463,194 @@ } ] }, - "6": { - "name": "storage.type.extern.cpp" + "56": { + "name": "entity.name.type.cpp" + }, + "57": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "59": { + "name": "meta.declaration.type.alias.value.unknown.cpp", + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "60": { + "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" + } + ] + }, + "61": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "62": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "63": { + "name": "comment.block.cpp" + }, + "64": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "65": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "66": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "67": { + "name": "comment.block.cpp" + }, + "68": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "69": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "70": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "71": { + "name": "comment.block.cpp" + }, + "72": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "73": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "74": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "75": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "76": { + "name": "punctuation.terminator.statement.cpp" } }, - "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", - "endCaptures": { + "name": "meta.declaration.type.alias.cpp" + }, + "type_casting_operators": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.extern.cpp" - } - }, - "patterns": [ - { - "include": "$self" - } - ] - }, - { - "name": "meta.tail.extern.cpp", - "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", - "patterns": [ - { - "include": "$self" - } - ] - }, - { - "include": "$self" - } - ] + } }, "typedef_class": { "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\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": "(?\\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" + } + ] + }, + "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" + } + ] + }, + "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": { + "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" + }, + "42": { + "name": "punctuation.definition.function.pointer.dereference.cpp" + }, + "43": { + "name": "entity.name.type.alias.cpp entity.name.type.pointer.function.cpp" + }, + "44": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "45": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "46": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "47": { + "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" + }, + "48": { + "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" + } + ] + } + ] + }, + "typedef_keyword": { + "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))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!final\\W|final\\$|override\\W|override\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", - "captures": { + "typeid_operator": { + "contentName": "meta.arguments.operator.typeid.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { "1": { - "name": "storage.type.struct.declare.cpp" + "name": "keyword.operator.functionlike.cpp keyword.operator.typeid.cpp" }, "2": { "patterns": [ @@ -13873,65 +15377,41 @@ ] }, "6": { - "name": "entity.name.type.struct.cpp" + "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" + } + ] + }, + "typename": { + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\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}))*))\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\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*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\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(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(?![\\w<:.]))", + "captures": { + "1": { + "name": "storage.modifier.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": { + "2": { "patterns": [ { "include": "#inline_comment" } ] }, - "9": { + "3": { "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - "10": { + "4": { "name": "comment.block.cpp" }, - "11": { + "5": { "patterns": [ { "match": "\\*\\/", @@ -13943,6 +15423,78 @@ } ] }, + "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": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(#)\\s*undef\\b)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))|((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\))))|(?={))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(final)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)((?>[^{]*)))?))", + "beginCaptures": { + "1": { + "name": "meta.head.union.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "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": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "9": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "10": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "11": { + "name": "comment.block.cpp" + }, + "12": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "13": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "14": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "15": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "16": { + "name": "comment.block.cpp" + }, + "17": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "18": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "19": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "20": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "21": { + "name": "comment.block.cpp" + }, + "22": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "23": { + "name": "entity.name.type.$3.cpp" + }, + "24": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "25": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "26": { + "name": "comment.block.cpp" + }, + "27": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "28": { + "name": "storage.type.modifier.final.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" + } + ] + }, + "37": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "38": { + "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": "$self" + } + ] + }, + { + "name": "meta.tail.union.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, "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)(?![:{])", + "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(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.union.declare.cpp" @@ -14205,1776 +16157,62 @@ } } }, - "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)(?![:{])", + "using_name": { + "match": "(using)\\s+(?!namespace\\b)", "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" - } - ] + "name": "keyword.other.using.directive.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" - } - ] - }, - "assembly": { - "name": "meta.asm.cpp", - "begin": "(\\b(?:__asm__|asm)\\b)\\s*((?:volatile)?)\\s*(\\()", + "using_namespace": { + "name": "meta.using-namespace.cpp", + "begin": "(?(?:(?>[^<>]*)\\g<7>?)+)>)\\s*)?::)*\\s*+)?((? { - return { - ...r, - tags: (r as any).deprecated ? [CompletionItemTag.Deprecated] : undefined - }; - }); - } else { - return { - isIncomplete: result.isIncomplete, - items: result.items.map(r => { - return { - ...r, - tags: (r as any).deprecated ? [CompletionItemTag.Deprecated] : undefined - }; - }) - }; - } - } - return result; - } } }; diff --git a/extensions/css-language-features/client/src/customData.ts b/extensions/css-language-features/client/src/customData.ts index e5fbd4fc9cc..7054d0f1ba9 100644 --- a/extensions/css-language-features/client/src/customData.ts +++ b/extensions/css-language-features/client/src/customData.ts @@ -35,26 +35,6 @@ export function getCustomDataPathsInAllWorkspaces(workspaceFolders: WorkspaceFol } }); - workspaceFolders.forEach(wf => { - const allCssConfig = workspace.getConfiguration(undefined, wf.uri); - const wfCSSConfig = allCssConfig.inspect('css'); - if ( - wfCSSConfig && - wfCSSConfig.workspaceFolderValue && - wfCSSConfig.workspaceFolderValue.experimental && - wfCSSConfig.workspaceFolderValue.experimental.customData - ) { - const customData = wfCSSConfig.workspaceFolderValue.experimental.customData; - if (Array.isArray(customData)) { - customData.forEach(t => { - if (typeof t === 'string') { - dataPaths.push(path.resolve(wf.uri.fsPath, t)); - } - }); - } - } - }); - return dataPaths; } @@ -70,19 +50,6 @@ export function getCustomDataPathsFromAllExtensions(): string[] { dataPaths.push(path.resolve(extension.extensionPath, rp)); }); } - - if ( - contributes && - contributes.css && - contributes.experimental && - contributes.css.experimental.customData && - Array.isArray(contributes.css.experimental.customData) - ) { - const relativePaths: string[] = contributes.css.experimental.customData; - relativePaths.forEach(rp => { - dataPaths.push(path.resolve(extension.extensionPath, rp)); - }); - } } return dataPaths; diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index 1dbd7608495..168b4499655 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -43,16 +43,6 @@ }, "scope": "resource" }, - "css.experimental.customData": { - "type": "array", - "description": "A list of JSON file paths that define custom CSS data that loads custom properties, at directives, pseudo classes / elements.", - "default": [], - "items": { - "type": "string" - }, - "scope": "resource", - "deprecationMessage": "This setting is no longe experimental. Use `css.customData` instead." - }, "css.completion.triggerPropertyValueCompletion": { "type": "boolean", "scope": "resource", @@ -308,6 +298,18 @@ "order": 24, "title": "%scss.title%", "properties": { + "scss.completion.triggerPropertyValueCompletion": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "%scss.completion.triggerPropertyValueCompletion.desc%" + }, + "scss.completion.completePropertyWithSemicolon": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "%scss.completion.completePropertyWithSemicolon.desc%" + }, "scss.validate": { "type": "boolean", "scope": "resource", @@ -521,6 +523,17 @@ ], "default": "ignore", "description": "%scss.lint.idSelector.desc%" + }, + "scss.lint.unknownAtRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%scss.lint.unknownAtRules.desc%" } } }, @@ -530,6 +543,18 @@ "type": "object", "title": "%less.title%", "properties": { + "less.completion.triggerPropertyValueCompletion": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "%less.completion.triggerPropertyValueCompletion.desc%" + }, + "less.completion.completePropertyWithSemicolon": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "%less.completion.completePropertyWithSemicolon.desc%" + }, "less.validate": { "type": "boolean", "scope": "resource", @@ -743,6 +768,17 @@ ], "default": "ignore", "description": "%less.lint.idSelector.desc%" + }, + "less.lint.unknownAtRules": { + "type": "string", + "scope": "resource", + "enum": [ + "ignore", + "warning", + "error" + ], + "default": "warning", + "description": "%less.lint.unknownAtRules.desc%" } } } @@ -759,11 +795,11 @@ ] }, "dependencies": { - "vscode-languageclient": "^5.3.0-next.6", + "vscode-languageclient": "^6.0.0-next.1", "vscode-nls": "^4.1.1" }, "devDependencies": { - "@types/node": "^10.14.8", - "mocha": "^5.2.0" + "@types/node": "^12.11.7", + "mocha": "^6.1.4" } } diff --git a/extensions/css-language-features/package.nls.json b/extensions/css-language-features/package.nls.json index 550820976d7..1517384b652 100644 --- a/extensions/css-language-features/package.nls.json +++ b/extensions/css-language-features/package.nls.json @@ -4,7 +4,7 @@ "css.title": "CSS", "css.customData.desc": "A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/Microsoft/vscode-css-languageservice/blob/master/docs/customData.md).\n\nVS Code loads custom data on startup to enhance its CSS support for the custom CSS properties, at directives, pseudo classes and pseudo elements you specify in the JSON files.\n\nThe file paths are relative to workspace and only workspace folder settings are considered.", "css.completion.triggerPropertyValueCompletion.desc": "By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.", - "css.completion.completePropertyWithSemicolon.desc": "Insert semicolon at end when completing CSS properties", + "css.completion.completePropertyWithSemicolon.desc": "Insert semicolon at end of line when completing CSS properties", "css.lint.argumentsInColorFunction.desc": "Invalid number of parameters.", "css.lint.boxModel.desc": "Do not use `width` or `height` when using `padding` or `border`.", "css.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties.", @@ -29,6 +29,8 @@ "css.validate.title": "Controls CSS validation and problem severities.", "css.validate.desc": "Enables or disables all validations.", "less.title": "LESS", + "less.completion.triggerPropertyValueCompletion.desc": "By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.", + "less.completion.completePropertyWithSemicolon.desc": "Insert semicolon at end of line when completing CSS properties", "less.lint.argumentsInColorFunction.desc": "Invalid number of parameters.", "less.lint.boxModel.desc": "Do not use `width` or `height` when using `padding` or `border`.", "less.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties.", @@ -43,6 +45,7 @@ "less.lint.importStatement.desc": "Import statements do not load in parallel.", "less.lint.propertyIgnoredDueToDisplay.desc": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect.", "less.lint.universalSelector.desc": "The universal selector (`*`) is known to be slow.", + "less.lint.unknownAtRules.desc": "Unknown at-rule.", "less.lint.unknownProperties.desc": "Unknown property.", "less.lint.validProperties.desc": "A list of properties that are not validated against the `unknownProperties` rule.", "less.lint.unknownVendorSpecificProperties.desc": "Unknown vendor specific property.", @@ -51,6 +54,8 @@ "less.validate.title": "Controls LESS validation and problem severities.", "less.validate.desc": "Enables or disables all validations.", "scss.title": "SCSS (Sass)", + "scss.completion.triggerPropertyValueCompletion.desc": "By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.", + "scss.completion.completePropertyWithSemicolon.desc": "Insert semicolon at end of line when completing CSS properties", "scss.lint.argumentsInColorFunction.desc": "Invalid number of parameters.", "scss.lint.boxModel.desc": "Do not use `width` or `height` when using `padding` or `border`.", "scss.lint.compatibleVendorPrefixes.desc": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties.", @@ -65,6 +70,7 @@ "scss.lint.importStatement.desc": "Import statements do not load in parallel.", "scss.lint.propertyIgnoredDueToDisplay.desc": "Property is ignored due to the display. E.g. with `display: inline`, the `width`, `height`, `margin-top`, `margin-bottom`, and `float` properties have no effect.", "scss.lint.universalSelector.desc": "The universal selector (`*`) is known to be slow.", + "scss.lint.unknownAtRules.desc": "Unknown at-rule.", "scss.lint.unknownProperties.desc": "Unknown property.", "scss.lint.validProperties.desc": "A list of properties that are not validated against the `unknownProperties` rule.", "scss.lint.unknownVendorSpecificProperties.desc": "Unknown vendor specific property.", diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index def7def57c2..8cb26a30e5e 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.3-next.8", - "vscode-languageserver": "^5.3.0-next.8" + "vscode-css-languageservice": "^4.0.3-next.15", + "vscode-languageserver": "^6.0.0-next.1" }, "devDependencies": { "@types/mocha": "2.2.33", - "@types/node": "^10.14.8", + "@types/node": "^12.11.7", "glob": "^7.1.4", "mocha": "^6.1.4", - "mocha-junit-reporter": "^1.23.0", + "mocha-junit-reporter": "^1.23.1", "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 a1dee46c523..7cf07998b1e 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -6,7 +6,7 @@ import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, ConfigurationRequest, WorkspaceFolder } from 'vscode-languageserver'; -import URI from 'vscode-uri'; +import { URI } from 'vscode-uri'; import { TextDocument, CompletionList, Position } from 'vscode-languageserver-types'; import { stat as fsStat } from 'fs'; @@ -75,9 +75,9 @@ const fileSystemProvider: FileSystemProvider = { let type = FileType.Unknown; if (stats.isFile()) { type = FileType.File; - } else if (stats.isDirectory) { + } else if (stats.isDirectory()) { type = FileType.Directory; - } else if (stats.isSymbolicLink) { + } else if (stats.isSymbolicLink()) { type = FileType.SymbolicLink; } @@ -390,4 +390,4 @@ connection.onSelectionRanges((params, token) => { // Listen on the connection -connection.listen(); \ No newline at end of file +connection.listen(); diff --git a/extensions/css-language-features/server/src/pathCompletion.ts b/extensions/css-language-features/server/src/pathCompletion.ts index aafed82b513..6862f28e034 100644 --- a/extensions/css-language-features/server/src/pathCompletion.ts +++ b/extensions/css-language-features/server/src/pathCompletion.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import * as fs from 'fs'; -import URI from 'vscode-uri'; +import { URI } from 'vscode-uri'; import { TextDocument, CompletionList, CompletionItemKind, CompletionItem, TextEdit, Range, Position } from 'vscode-languageserver-types'; import { WorkspaceFolder } from 'vscode-languageserver'; diff --git a/extensions/css-language-features/server/src/test/completion.test.ts b/extensions/css-language-features/server/src/test/completion.test.ts index 3a832600355..d8230ba2922 100644 --- a/extensions/css-language-features/server/src/test/completion.test.ts +++ b/extensions/css-language-features/server/src/test/completion.test.ts @@ -5,7 +5,7 @@ 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 } from 'vscode-languageserver-types'; import { WorkspaceFolder } from 'vscode-languageserver-protocol'; import { getPathCompletionParticipant } from '../pathCompletion'; @@ -60,8 +60,8 @@ suite('Completions', () => { } test('CSS url() Path completion', function () { - let testUri = Uri.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: Uri.file(path.resolve(__dirname, '../../test')).toString() }]; + let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); + let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; assertCompletions('html { background-image: url("./|")', { items: [ @@ -119,8 +119,8 @@ suite('Completions', () => { }); test('CSS url() Path Completion - Unquoted url', function () { - let testUri = Uri.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: Uri.file(path.resolve(__dirname, '../../test')).toString() }]; + let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); + let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; assertCompletions('html { background-image: url(./|)', { items: [ @@ -148,8 +148,8 @@ suite('Completions', () => { }); test('CSS @import Path completion', function () { - let testUri = Uri.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: Uri.file(path.resolve(__dirname, '../../test')).toString() }]; + let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); + let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; assertCompletions(`@import './|'`, { items: [ @@ -171,8 +171,8 @@ suite('Completions', () => { * For SCSS, `@import 'foo';` can be used for importing partial file `_foo.scss` */ test('SCSS @import Path completion', function () { - let testCSSUri = Uri.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: Uri.file(path.resolve(__dirname, '../../test')).toString() }]; + let testCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); + let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; /** * We are in a CSS file, so no special treatment for SCSS partial files @@ -184,7 +184,7 @@ suite('Completions', () => { ] }, testCSSUri, folders); - let testSCSSUri = Uri.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/scss/main.scss')).toString(); + let testSCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/scss/main.scss')).toString(); assertCompletions(`@import './|'`, { items: [ { label: '_foo.scss', resultText: `@import './foo'` } @@ -193,12 +193,12 @@ suite('Completions', () => { }); test('Completion should ignore files/folders starting with dot', function () { - let testUri = Uri.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); - let folders = [{ name: 'x', uri: Uri.file(path.resolve(__dirname, '../../test')).toString() }]; + let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString(); + let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }]; assertCompletions('html { background-image: url("../|")', { count: 4 }, testUri, folders); }); -}); \ No newline at end of file +}); diff --git a/extensions/css-language-features/server/src/test/links.test.ts b/extensions/css-language-features/server/src/test/links.test.ts index bce7a11bc8a..a2a13361016 100644 --- a/extensions/css-language-features/server/src/test/links.test.ts +++ b/extensions/css-language-features/server/src/test/links.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'mocha'; import * as assert from 'assert'; -import Uri from 'vscode-uri'; +import { URI } from 'vscode-uri'; import { resolve } from 'path'; import { TextDocument, DocumentLink } from 'vscode-languageserver-types'; import { WorkspaceFolder } from 'vscode-languageserver-protocol'; @@ -54,7 +54,7 @@ suite('Links', () => { } function getTestResource(path: string) { - return Uri.file(resolve(__dirname, '../../test/linksTestFixtures', path)).toString(); + return URI.file(resolve(__dirname, '../../test/linksTestFixtures', path)).toString(); } test('url links', function () { @@ -76,4 +76,4 @@ suite('Links', () => { [{ 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 494ff395e9d..7c488a4e372 100644 --- a/extensions/css-language-features/server/src/utils/documentContext.ts +++ b/extensions/css-language-features/server/src/utils/documentContext.ts @@ -7,7 +7,7 @@ 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 { URI } from 'vscode-uri'; import { join, dirname } from 'path'; import { existsSync } from 'fs'; diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index 9cda831e23b..525a611894a 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.33.tgz#d79a0061ec270379f4d9e225f4096fb436669def" integrity sha1-15oAYewnA3n02eIl9AlvtDZmne8= -"@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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== ansi-colors@3.2.3: version "3.2.3" @@ -479,10 +479,10 @@ mkdirp@0.5.1, mkdirp@~0.5.1: dependencies: minimist "0.0.8" -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== +mocha-junit-reporter@^1.23.1: + version "1.23.1" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.1.tgz#ba11519c0b967f404e4123dd69bc4ba022ab0f12" + integrity sha512-qeDvKlZyAH2YJE1vhryvjUQ06t2hcnwwu4k5Ddwn0GQINhgEYFhlGM0DwYCVUHq5cuo32qAW6HDsTHt7zz99Ng== dependencies: debug "^2.2.0" md5 "^2.1.0" @@ -781,41 +781,40 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.3-next.8: - version "4.0.3-next.8" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.8.tgz#0b81693b6ea9d10f78775a1dcad2c0f464fbde16" - integrity sha512-agBPPu86bPKIK5v6CFnWeBXN4jvnCzc67GZa/pvrIWeRdG7nvTu5Y2wYdwdesdpWzno9/5tfFEPp0KJbKQ4l+A== +vscode-css-languageservice@^4.0.3-next.15: + version "4.0.3-next.15" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.15.tgz#e7b7dab2f1e6e9452bb2fb8c400dbcff3b8927aa" + integrity sha512-y2bNfcZgNH3F7R0N/1ePnVtzvGwi9f6leW5L0zPso/wVK9A4xw5rmZA1pTV9vMjoio2h3gUB1T8HTQeVxota2Q== dependencies: - vscode-languageserver-types "^3.15.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" 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-jsonrpc@^5.0.0-next.2: + version "5.0.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca" + integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg== -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== +vscode-languageserver-protocol@^3.15.0-next.9: + version "3.15.0-next.9" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30" + integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g== dependencies: - vscode-jsonrpc "^4.1.0-next.2" - vscode-languageserver-types "^3.15.0-next.2" + vscode-jsonrpc "^5.0.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" -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.15.0-next.5: + version "3.15.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b" + integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw== -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== +vscode-languageserver@^6.0.0-next.1: + version "6.0.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-6.0.0-next.1.tgz#4d71886d4a17d22eafc61b3a5fbf84e8e27c191f" + integrity sha512-LSF6bXoFeXfMPRNyqzI3yFX/kD2DzXBemqvyj1kDWNVraiWttm4xKF4YXsvJ7Z3s9sVt/Dpu3CFU3w61PGNZMg== dependencies: - vscode-languageserver-protocol "^3.15.0-next.6" + vscode-languageserver-protocol "^3.15.0-next.9" vscode-textbuffer "^1.0.0" - vscode-uri "^1.0.6" vscode-nls@^4.1.1: version "4.1.1" @@ -827,11 +826,6 @@ vscode-textbuffer@^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" diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index 48f16a42fe5..760f10ab04e 100644 --- a/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -2,10 +2,39 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== + +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@^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.0, 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" @@ -25,42 +54,143 @@ 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== -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== +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" + +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" + +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= -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" + +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, define-properties@^1.1.3: + 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== + +es-abstract@^1.5.1: + version "1.14.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497" + integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.0" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-inspect "^1.6.0" + object-keys "^1.1.1" + string.prototype.trimleft "^2.0.0" + string.prototype.trimright "^2.0.0" + +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== + +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: - 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@^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== + +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" @@ -79,10 +209,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" @@ -97,6 +239,73 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +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@^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-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" + +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.17.15: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +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" + minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -116,27 +325,80 @@ mkdirp@0.5.1: dependencies: minimist "0.0.8" -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.2.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.1.tgz#da941c99437da9bac412097859ff99543969f94c" + integrity sha512-VCcWkLHwk79NYQc8cxhkmI8IigTIhsCwZ6RTxQsqK6go4UvEhzJkYuHm8B2YtlSxcYq2fY+ucr4JBwoD6ci80A== 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.3.0" + yargs-parser "13.1.1" + yargs-unparser "1.6.0" -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +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== + +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" + +object-inspect@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" + integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + 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: version "1.4.0" @@ -145,55 +407,229 @@ once@^1.3.0: dependencies: wrappy "1" +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + 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= -semver@^5.5.0: - version "5.5.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" - integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== +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= -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== +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.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +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= + +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.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-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.prototype.trimleft@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" + integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" + integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.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-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: has-flag "^3.0.0" -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.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== +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: - semver "^5.5.0" - vscode-languageserver-protocol "^3.15.0-next.6" + has-flag "^3.0.0" -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== +vscode-jsonrpc@^5.0.0-next.2: + version "5.0.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca" + integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg== + +vscode-languageclient@^6.0.0-next.1: + version "6.0.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-6.0.0-next.1.tgz#deca1743afd20da092e04e40ef73cedbbd978455" + integrity sha512-eJ9VjLFNINArgRzLbQ11YlWry7dM93GEODkQBXTRfrSypksiO9qSGr4SHhWgxxP26p4FRSpzc/17+N+Egnnchg== dependencies: - vscode-jsonrpc "^4.1.0-next.2" - vscode-languageserver-types "^3.15.0-next.2" + semver "^6.3.0" + vscode-languageserver-protocol "^3.15.0-next.9" -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-protocol@^3.15.0-next.9: + version "3.15.0-next.9" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30" + integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g== + dependencies: + vscode-jsonrpc "^5.0.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" + +vscode-languageserver-types@^3.15.0-next.5: + version "3.15.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b" + integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw== 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== +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: + 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@^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" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +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.1.1, yargs-parser@^13.1.1: + 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.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs@13.3.0, yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + 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.1" diff --git a/extensions/css/cgmanifest.json b/extensions/css/cgmanifest.json index a47fef967ec..32e5d2fc299 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": "377734aad976be88a425aab5667784f3f71ea7e5" + "commitHash": "dcdc1cb4403266f4ebdb1a4f526f8b6d09fd39d6" } }, "license": "MIT", diff --git a/extensions/css/syntaxes/css.tmLanguage.json b/extensions/css/syntaxes/css.tmLanguage.json index 8dbdf1f7413..9a7188cd44d 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/377734aad976be88a425aab5667784f3f71ea7e5", + "version": "https://github.com/octref/language-css/commit/dcdc1cb4403266f4ebdb1a4f526f8b6d09fd39d6", "name": "CSS", "scopeName": "source.css", "patterns": [ @@ -1260,7 +1260,7 @@ "name": "support.type.property-name.media.css" }, "2": { - "name": "invalid.deprecated.media.css" + "name": "support.type.property-name.media.css" }, "3": { "name": "support.type.vendored.property-name.media.css" diff --git a/extensions/debug-auto-launch/package.json b/extensions/debug-auto-launch/package.json index b1444f044b8..07568c77081 100644 --- a/extensions/debug-auto-launch/package.json +++ b/extensions/debug-auto-launch/package.json @@ -50,6 +50,6 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" } } diff --git a/extensions/debug-auto-launch/yarn.lock b/extensions/debug-auto-launch/yarn.lock index e6247e29255..7af62a72ce7 100644 --- a/extensions/debug-auto-launch/yarn.lock +++ b/extensions/debug-auto-launch/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/debug-server-ready/package.json b/extensions/debug-server-ready/package.json index 2ed095cc2d7..abb9a683eba 100644 --- a/extensions/debug-server-ready/package.json +++ b/extensions/debug-server-ready/package.json @@ -106,6 +106,6 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" } } diff --git a/extensions/debug-server-ready/yarn.lock b/extensions/debug-server-ready/yarn.lock index e6247e29255..7af62a72ce7 100644 --- a/extensions/debug-server-ready/yarn.lock +++ b/extensions/debug-server-ready/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index d88c3717ab3..ed8e8ea9f87 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -440,7 +440,7 @@ "deps": "yarn add vscode-emmet-helper" }, "devDependencies": { - "@types/node": "^10.14.8", + "@types/node": "^12.11.7", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "vscode": "1.0.1" @@ -450,7 +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.16", "vscode-html-languageservice": "^3.0.3" } } diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index 7b22c533426..a801de886fd 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@^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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== ajv@^5.1.0: version "5.3.0" @@ -2469,10 +2469,10 @@ vinyl@~2.0.1: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" -vscode-emmet-helper@^1.2.15: - version "1.2.15" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.15.tgz#62dbfbf49bb9ebe329cb7bffdda5aaac725eea7a" - integrity sha512-JplvmMMWSvm/6/dZezix2ADPM49u6YahPYjs/QToohUpomW/2Eb27ecCrkCyOGBPfKLKGiOPHCssss8TSDA9ag== +vscode-emmet-helper@^1.2.16: + version "1.2.16" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-1.2.16.tgz#cfefb8b54c68178b4696d4abae806bb3a2b043e8" + integrity sha512-BuQK6fTV2w65Yd0/CJGj1EOvcJ9NHWfrMJ9nA8pjnu9jzAAnXLhnbviuGT9medMiPU0mp0tJqc/8Z0qlXcqdGw== dependencies: "@emmetio/extract-abbreviation" "0.1.6" jsonc-parser "^1.0.0" diff --git a/extensions/extension-editing/package.json b/extensions/extension-editing/package.json index 50c97fb26f4..54edf5ccbdc 100644 --- a/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -54,6 +54,6 @@ }, "devDependencies": { "@types/markdown-it": "0.0.2", - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" } } diff --git a/extensions/extension-editing/yarn.lock b/extensions/extension-editing/yarn.lock index fb98728f237..d2f69a169d8 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.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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== "@types/node@^6.0.46": version "6.0.78" diff --git a/extensions/fsharp/cgmanifest.json b/extensions/fsharp/cgmanifest.json index 47351a1a0b4..46584d1b7ef 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": "687070defaf355022a5d82d091258eccfea7317c" + "commitHash": "b4f43aafa6f843707410fabe9f904ec04fa536dc" } }, "license": "MIT", diff --git a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json index 20cfc9ecde7..ed1e9fcb5f8 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/687070defaf355022a5d82d091258eccfea7317c", + "version": "https://github.com/ionide/ionide-fsgrammar/commit/b4f43aafa6f843707410fabe9f904ec04fa536dc", "name": "fsharp", "scopeName": "source.fsharp", "patterns": [ @@ -937,10 +937,10 @@ }, { "name": "binding.fsharp", - "begin": "\\b((get|set)\\s*(?=\\())(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9\\._`\\s]+|(?<=,)\\s)*)?", + "begin": "(?<=with|and)\\s*\\b((get|set)\\s*(?=\\())(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9\\._`\\s]+|(?<=,)\\s)*)?", "end": "\\s*(=|\\n+=|(?<=\\=))", "beginCaptures": { - "3": { + "4": { "name": "variable.fsharp" } }, @@ -1240,11 +1240,11 @@ }, { "name": "constant.character.string.escape.fsharp", - "match": "\\\\([\\\\''ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})" + "match": "\\\\([\\\\''ntbr]|x[a-fA-F0-9]{2}|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})" }, { "name": "invalid.illeagal.character.string.fsharp", - "match": "\\\\(?![\\\\''ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})." + "match": "\\\\(?![\\\\''ntbr]|x[a-fA-F0-9]{2}|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})." }, { "include": "#string_formatter" diff --git a/extensions/fsharp/test/colorize-results/test_fs.json b/extensions/fsharp/test/colorize-results/test_fs.json index e5736fc10aa..2d1544d210e 100644 --- a/extensions/fsharp/test/colorize-results/test_fs.json +++ b/extensions/fsharp/test/colorize-results/test_fs.json @@ -605,18 +605,7 @@ } }, { - "c": " ", - "t": "source.fsharp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "get", + "c": " get", "t": "source.fsharp binding.fsharp", "r": { "dark_plus": "default: #D4D4D4", @@ -693,18 +682,7 @@ } }, { - "c": " ", - "t": "source.fsharp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "set", + "c": " set", "t": "source.fsharp binding.fsharp", "r": { "dark_plus": "default: #D4D4D4", diff --git a/extensions/git-ui/package.json b/extensions/git-ui/package.json index 2f1ab43f892..84133436ef8 100644 --- a/extensions/git-ui/package.json +++ b/extensions/git-ui/package.json @@ -23,6 +23,6 @@ "watch": "gulp watch-extension:git-ui" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" } -} \ No newline at end of file +} diff --git a/extensions/git-ui/src/main.ts b/extensions/git-ui/src/main.ts index d233b753be2..98fdd15c39c 100644 --- a/extensions/git-ui/src/main.ts +++ b/extensions/git-ui/src/main.ts @@ -41,12 +41,12 @@ export function exec(command: string, options: cp.ExecOptions & { stdin?: string (error ? reject : resolve)({ error, stdout, stderr }); }); if (options.stdin) { - child.stdin.write(options.stdin, (err: any) => { + child.stdin!.write(options.stdin, (err: any) => { if (err) { reject(err); return; } - child.stdin.end((err: any) => { + child.stdin!.end((err: any) => { if (err) { reject(err); } diff --git a/extensions/git-ui/yarn.lock b/extensions/git-ui/yarn.lock index b23b0ac0392..40784952b89 100644 --- a/extensions/git-ui/yarn.lock +++ b/extensions/git-ui/yarn.lock @@ -2,7 +2,7 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== diff --git a/extensions/git/package.json b/extensions/git/package.json index b64dfb4707e..2a92f716712 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -109,6 +109,24 @@ "dark": "resources/icons/dark/stage.svg" } }, + { + "command": "git.stageAllTracked", + "title": "%command.stageAllTracked%", + "category": "Git", + "icon": { + "light": "resources/icons/light/stage.svg", + "dark": "resources/icons/dark/stage.svg" + } + }, + { + "command": "git.stageAllUntracked", + "title": "%command.stageAllUntracked%", + "category": "Git", + "icon": { + "light": "resources/icons/light/stage.svg", + "dark": "resources/icons/dark/stage.svg" + } + }, { "command": "git.stageSelectedRanges", "title": "%command.stageSelectedRanges%", @@ -178,6 +196,24 @@ "dark": "resources/icons/dark/clean.svg" } }, + { + "command": "git.cleanAllTracked", + "title": "%command.cleanAllTracked%", + "category": "Git", + "icon": { + "light": "resources/icons/light/clean.svg", + "dark": "resources/icons/dark/clean.svg" + } + }, + { + "command": "git.cleanAllUntracked", + "title": "%command.cleanAllUntracked%", + "category": "Git", + "icon": { + "light": "resources/icons/light/clean.svg", + "dark": "resources/icons/dark/clean.svg" + } + }, { "command": "git.commit", "title": "%command.commit%", @@ -267,6 +303,11 @@ "title": "%command.createTag%", "category": "Git" }, + { + "command": "git.deleteTag", + "title": "%command.deleteTag%", + "category": "Git" + }, { "command": "git.fetch", "title": "%command.fetch%", @@ -362,6 +403,11 @@ "title": "%command.ignore%", "category": "Git" }, + { + "command": "git.revealInExplorer", + "title": "%command.revealInExplorer%", + "category": "Git" + }, { "command": "git.stashIncludeUntracked", "title": "%command.stashIncludeUntracked%", @@ -391,6 +437,11 @@ "command": "git.stashApplyLatest", "title": "%command.stashApplyLatest%", "category": "Git" + }, + { + "command": "git.stashDrop", + "title": "%command.stashDrop%", + "category": "Git" } ], "menus": { @@ -435,6 +486,14 @@ "command": "git.stageAll", "when": "config.git.enabled && gitOpenRepositoryCount != 0" }, + { + "command": "git.stageAllTracked", + "when": "config.git.enabled && gitOpenRepositoryCount != 0" + }, + { + "command": "git.stageAllUntracked", + "when": "config.git.enabled && gitOpenRepositoryCount != 0" + }, { "command": "git.stageSelectedRanges", "when": "config.git.enabled && gitOpenRepositoryCount != 0" @@ -507,6 +566,10 @@ "command": "git.restoreCommitTemplate", "when": "false" }, + { + "command": "git.revealInExplorer", + "when": "false" + }, { "command": "git.undoCommit", "when": "config.git.enabled && gitOpenRepositoryCount != 0" @@ -555,6 +618,10 @@ "command": "git.createTag", "when": "config.git.enabled && gitOpenRepositoryCount != 0" }, + { + "command": "git.deleteTag", + "when": "config.git.enabled && gitOpenRepositoryCount != 0" + }, { "command": "git.fetch", "when": "config.git.enabled && gitOpenRepositoryCount != 0" @@ -642,6 +709,10 @@ { "command": "git.stashApplyLatest", "when": "config.git.enabled && gitOpenRepositoryCount != 0" + }, + { + "command": "git.stashDrop", + "when": "config.git.enabled && gitOpenRepositoryCount != 0" } ], "scm/title": [ @@ -795,6 +866,11 @@ "group": "6_stash", "when": "scmProvider == git" }, + { + "command": "git.stashDrop", + "group": "6_stash", + "when": "scmProvider == git" + }, { "command": "git.showOutput", "group": "7_repository", @@ -831,22 +907,62 @@ }, { "command": "git.cleanAll", - "when": "scmProvider == git && scmResourceGroup == workingTree", + "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges == mixed", "group": "1_modification" }, { "command": "git.stageAll", - "when": "scmProvider == git && scmResourceGroup == workingTree", + "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges == mixed", "group": "1_modification" }, { "command": "git.cleanAll", - "when": "scmProvider == git && scmResourceGroup == workingTree", + "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges == mixed", "group": "inline" }, { "command": "git.stageAll", - "when": "scmProvider == git && scmResourceGroup == workingTree", + "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges == mixed", + "group": "inline" + }, + { + "command": "git.cleanAllTracked", + "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges != mixed", + "group": "1_modification" + }, + { + "command": "git.stageAllTracked", + "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges != mixed", + "group": "1_modification" + }, + { + "command": "git.cleanAllTracked", + "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges != mixed", + "group": "inline" + }, + { + "command": "git.stageAllTracked", + "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.untrackedChanges != mixed", + "group": "inline" + }, + { + "command": "git.cleanAllUntracked", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "1_modification" + }, + { + "command": "git.stageAllUntracked", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "1_modification" + }, + { + "command": "git.cleanAllUntracked", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "inline" + }, + { + "command": "git.stageAllUntracked", + "when": "scmProvider == git && scmResourceGroup == untracked", "group": "inline" } ], @@ -913,6 +1029,11 @@ "when": "scmProvider == git && scmResourceGroup == merge", "group": "inline" }, + { + "command": "git.revealInExplorer", + "when": "scmProvider == git && scmResourceGroup == merge", + "group": "2_view" + }, { "command": "git.openFile2", "when": "scmProvider == git && scmResourceGroup == merge && config.git.showInlineOpenFileAction && config.git.openDiffOnClick", @@ -948,6 +1069,11 @@ "when": "scmProvider == git && scmResourceGroup == index", "group": "inline" }, + { + "command": "git.revealInExplorer", + "when": "scmProvider == git && scmResourceGroup == index", + "group": "2_view" + }, { "command": "git.openFile2", "when": "scmProvider == git && scmResourceGroup == index && config.git.showInlineOpenFileAction && config.git.openDiffOnClick", @@ -1007,6 +1133,66 @@ "command": "git.ignore", "when": "scmProvider == git && scmResourceGroup == workingTree", "group": "1_modification@3" + }, + { + "command": "git.revealInExplorer", + "when": "scmProvider == git && scmResourceGroup == workingTree", + "group": "2_view" + }, + { + "command": "git.openChange", + "when": "scmProvider == git && scmResourceGroup == workingTree", + "group": "navigation" + }, + { + "command": "git.openChange", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "navigation" + }, + { + "command": "git.openHEADFile", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "navigation" + }, + { + "command": "git.openFile", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "navigation" + }, + { + "command": "git.stage", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "1_modification" + }, + { + "command": "git.clean", + "when": "scmProvider == git && scmResourceGroup == untracked && !gitFreshRepository", + "group": "1_modification" + }, + { + "command": "git.clean", + "when": "scmProvider == git && scmResourceGroup == untracked && !gitFreshRepository", + "group": "inline" + }, + { + "command": "git.stage", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "inline" + }, + { + "command": "git.openFile2", + "when": "scmProvider == git && scmResourceGroup == untracked && config.git.showInlineOpenFileAction && config.git.openDiffOnClick", + "group": "inline0" + }, + { + "command": "git.openChange", + "when": "scmProvider == git && scmResourceGroup == untracked && config.git.showInlineOpenFileAction && !config.git.openDiffOnClick", + "group": "inline0" + }, + { + "command": "git.ignore", + "when": "scmProvider == git && scmResourceGroup == untracked", + "group": "1_modification@3" } ], "editor/title": [ @@ -1150,7 +1336,8 @@ "%config.countBadge.off%" ], "description": "%config.countBadge%", - "default": "all" + "default": "all", + "scope": "resource" }, "git.checkoutType": { "type": "string", @@ -1410,6 +1597,22 @@ ], "default": "committerdate", "description": "%config.branchSortOrder%" + }, + "git.untrackedChanges": { + "type": "string", + "enum": [ + "mixed", + "separate", + "hidden" + ], + "enumDescriptions": [ + "%config.untrackedChanges.mixed%", + "%config.untrackedChanges.separate%", + "%config.untrackedChanges.hidden%" + ], + "default": "mixed", + "description": "%config.untrackedChanges%", + "scope": "resource" } } }, @@ -1571,7 +1774,7 @@ "@types/byline": "4.2.31", "@types/file-type": "^5.2.1", "@types/mocha": "2.2.43", - "@types/node": "^10.14.8", + "@types/node": "^12.11.7", "@types/which": "^1.0.28", "mocha": "^3.2.0" } diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 6587b65421d..0c4959e20e4 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -11,6 +11,8 @@ "command.openHEADFile": "Open File (HEAD)", "command.stage": "Stage Changes", "command.stageAll": "Stage All Changes", + "command.stageAllTracked": "Stage All Tracked Changes", + "command.stageAllUntracked": "Stage All Untracked Changes", "command.stageSelectedRanges": "Stage Selected Ranges", "command.revertSelectedRanges": "Revert Selected Ranges", "command.stageChange": "Stage Change", @@ -20,6 +22,8 @@ "command.unstageSelectedRanges": "Unstage Selected Ranges", "command.clean": "Discard Changes", "command.cleanAll": "Discard All Changes", + "command.cleanAllTracked": "Discard All Tracked Changes", + "command.cleanAllUntracked": "Discard All Untracked Changes", "command.commit": "Commit", "command.commitStaged": "Commit Staged", "command.commitEmpty": "Commit Empty", @@ -37,6 +41,7 @@ "command.renameBranch": "Rename Branch...", "command.merge": "Merge Branch...", "command.createTag": "Create Tag", + "command.deleteTag": "Delete Tag", "command.fetch": "Fetch", "command.fetchPrune": "Fetch (Prune)", "command.fetchAll": "Fetch From All Remotes", @@ -53,15 +58,17 @@ "command.removeRemote": "Remove Remote", "command.sync": "Sync", "command.syncRebase": "Sync (Rebase)", - "command.publish": "Publish Branch", + "command.publish": "Publish Branch...", "command.showOutput": "Show Git Output", "command.ignore": "Add to .gitignore", + "command.revealInExplorer": "Reveal in Explorer", "command.stashIncludeUntracked": "Stash (Include Untracked)", "command.stash": "Stash", "command.stashPop": "Pop Stash...", "command.stashPopLatest": "Pop Latest Stash", "command.stashApply": "Apply Stash...", "command.stashApplyLatest": "Apply Latest Stash", + "command.stashDrop": "Drop Stash...", "config.enabled": "Whether git is enabled.", "config.path": "Path and filename of the git executable, e.g. `C:\\Program Files\\Git\\bin\\git.exe` (Windows).", "config.autoRepositoryDetection": "Configures when repositories should be automatically detected.", @@ -118,7 +125,7 @@ "config.scanRepositories": "List of paths to search for git repositories in.", "config.showProgress": "Controls whether git actions should show progress.", "config.rebaseWhenSync": "Force git to use rebase when running the sync command.", - "config.confirmEmptyCommits": "Always confirm the creation of empty commits.", + "config.confirmEmptyCommits": "Always confirm the creation of empty commits for the 'Git: Commit Empty' command.", "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.", @@ -128,6 +135,10 @@ "config.openDiffOnClick": "Controls whether the diff editor should be opened when clicking a change. Otherwise the regular editor will be opened.", "config.supportCancellation": "Controls whether a notification comes up when running the Sync action, which allows the user to cancel the operation.", "config.branchSortOrder": "Controls the sort order for branches.", + "config.untrackedChanges": "Controls how untracked changes behave.", + "config.untrackedChanges.mixed": "All changes, tracked and untracked, appear together and behave equally.", + "config.untrackedChanges.separate": "Untracked changes appear separately in the Source Control view. They are also excluded from several actions.", + "config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.", "colors.added": "Color for added resources.", "colors.modified": "Color for modified resources.", "colors.deleted": "Color for deleted resources.", diff --git a/extensions/git/src/askpass-main.ts b/extensions/git/src/askpass-main.ts index 5da46215a1a..c08aa2a0afc 100644 --- a/extensions/git/src/askpass-main.ts +++ b/extensions/git/src/askpass-main.ts @@ -28,8 +28,8 @@ function main(argv: string[]): void { return fatal('Missing pipe'); } - if (process.env['VSCODE_GIT_COMMAND'] === 'fetch') { - return fatal('Skip fetch commands'); + if (process.env['VSCODE_GIT_COMMAND'] === 'fetch' && !!process.env['VSCODE_GIT_FETCH_SILENT']) { + return fatal('Skip silent fetch commands'); } const output = process.env['VSCODE_GIT_ASKPASS_PIPE'] as string; diff --git a/extensions/git/src/autofetch.ts b/extensions/git/src/autofetch.ts index 9fd81bfabfe..d9e436b9f5c 100644 --- a/extensions/git/src/autofetch.ts +++ b/extensions/git/src/autofetch.ts @@ -99,7 +99,7 @@ export class AutoFetcher { } try { - await this.repository.fetchDefault(); + await this.repository.fetchDefault({ silent: true }); } catch (err) { if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { this.disable(); diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts old mode 100755 new mode 100644 index dfc7bb75fb9..e58f8c42292 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -3,19 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor, MessageOptions, WorkspaceFolder } from 'vscode'; -import { Git, CommitOptions, Stash, ForcePushMode } from './git'; -import { Repository, Resource, ResourceGroupType } from './repository'; -import { Model } from './model'; -import { toGitUri, fromGitUri } from './uri'; -import { grep, isDescendant, pathEquals } from './util'; -import { applyLineChanges, intersectDiffWithRange, toLineRanges, invertLineChange, getModifiedRange } from './staging'; -import * as path from 'path'; import { lstat, Stats } from 'fs'; import * as os from 'os'; +import * as path from 'path'; +import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder } from 'vscode'; import TelemetryReporter from 'vscode-extension-telemetry'; import * as nls from 'vscode-nls'; -import { Ref, RefType, Branch, GitErrorCodes, Status } from './api/git'; +import { Branch, GitErrorCodes, Ref, RefType, Status } from './api/git'; +import { CommitOptions, ForcePushMode, Git, Stash } from './git'; +import { Model } from './model'; +import { Repository, Resource, ResourceGroupType } from './repository'; +import { applyLineChanges, getModifiedRange, intersectDiffWithRange, invertLineChange, toLineRanges } from './staging'; +import { fromGitUri, toGitUri } from './uri'; +import { grep, isDescendant, pathEquals } from './util'; const localize = nls.loadMessageBundle(); @@ -99,7 +99,7 @@ class CreateBranchItem implements QuickPickItem { constructor(private cc: CommandCenter) { } - get label(): string { return localize('create branch', '$(plus) Create new branch...'); } + get label(): string { return '$(plus) ' + localize('create branch', 'Create new branch...'); } get description(): string { return ''; } get alwaysShow(): boolean { return true; } @@ -113,7 +113,7 @@ class CreateBranchFromItem implements QuickPickItem { constructor(private cc: CommandCenter) { } - get label(): string { return localize('create branch from', '$(plus) Create new branch from...'); } + get label(): string { return '$(plus) ' + localize('create branch from', 'Create new branch from...'); } get description(): string { return ''; } get alwaysShow(): boolean { return true; } @@ -132,6 +132,20 @@ class HEADItem implements QuickPickItem { get alwaysShow(): boolean { return true; } } +class AddRemoteItem implements QuickPickItem { + + constructor(private cc: CommandCenter) { } + + get label(): string { return '$(plus) ' + localize('add remote', 'Add a new remote...'); } + get description(): string { return ''; } + + get alwaysShow(): boolean { return true; } + + async run(repository: Repository): Promise { + await this.cc.addRemote(repository); + } +} + interface CommandOptions { repository?: boolean; diff?: boolean; @@ -199,6 +213,12 @@ function createCheckoutItems(repository: Repository): CheckoutItem[] { return [...heads, ...tags, ...remoteHeads]; } +class TagItem implements QuickPickItem { + get label(): string { return this.ref.name ?? ''; } + get description(): string { return this.ref.commit?.substr(0, 8) ?? ''; } + constructor(readonly ref: Ref) { } +} + enum PushType { Push, PushTo, @@ -493,7 +513,7 @@ export class CommandCenter { const repositoryPath = await window.withProgress( opts, - (_, token) => this.git.clone(url!, parentPath, token) + (progress, token) => this.git.clone(url!, parentPath, progress, token) ); let message = localize('proposeopen', "Would you like to open the cloned repository?"); @@ -852,7 +872,8 @@ export class CommandCenter { } const workingTree = selection.filter(s => s.resourceGroupType === ResourceGroupType.WorkingTree); - const scmResources = [...workingTree, ...resolved, ...unresolved]; + const untracked = selection.filter(s => s.resourceGroupType === ResourceGroupType.Untracked); + const scmResources = [...workingTree, ...untracked, ...resolved, ...unresolved]; this.outputChannel.appendLine(`git.stage.scmResources ${scmResources.length}`); if (!scmResources.length) { @@ -893,7 +914,9 @@ export class CommandCenter { } } - await repository.add([]); + const config = workspace.getConfiguration('git', Uri.file(repository.root)); + const untrackedChanges = config.get<'mixed' | 'separate' | 'hidden'>('untrackedChanges'); + await repository.add([], untrackedChanges === 'mixed' ? undefined : { update: true }); } private async _stageDeletionConflict(repository: Repository, uri: Uri): Promise { @@ -931,6 +954,24 @@ export class CommandCenter { } } + @command('git.stageAllTracked', { repository: true }) + async stageAllTracked(repository: Repository): Promise { + const resources = repository.workingTreeGroup.resourceStates + .filter(r => r.type !== Status.UNTRACKED && r.type !== Status.IGNORED); + const uris = resources.map(r => r.resourceUri); + + await repository.add(uris); + } + + @command('git.stageAllUntracked', { repository: true }) + async stageAllUntracked(repository: Repository): Promise { + const resources = [...repository.workingTreeGroup.resourceStates, ...repository.untrackedGroup.resourceStates] + .filter(r => r.type === Status.UNTRACKED || r.type === Status.IGNORED); + const uris = resources.map(r => r.resourceUri); + + await repository.add(uris); + } + @command('git.stageChange') async stageChange(uri: Uri, changes: LineChange[], index: number): Promise { const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0]; @@ -1117,8 +1158,8 @@ export class CommandCenter { resourceStates = [resource]; } - const scmResources = resourceStates - .filter(s => s instanceof Resource && s.resourceGroupType === ResourceGroupType.WorkingTree) as Resource[]; + const scmResources = resourceStates.filter(s => s instanceof Resource + && (s.resourceGroupType === ResourceGroupType.WorkingTree || s.resourceGroupType === ResourceGroupType.Untracked)) as Resource[]; if (!scmResources.length) { return; @@ -1175,41 +1216,11 @@ export class CommandCenter { const untrackedResources = resources.filter(r => r.type === Status.UNTRACKED || r.type === Status.IGNORED); if (untrackedResources.length === 0) { - const message = resources.length === 1 - ? localize('confirm discard all single', "Are you sure you want to discard changes in {0}?", path.basename(resources[0].resourceUri.fsPath)) - : localize('confirm discard all', "Are you sure you want to discard ALL changes in {0} files?\nThis is IRREVERSIBLE!\nYour current working set will be FOREVER LOST.", resources.length); - const yes = resources.length === 1 - ? localize('discardAll multiple', "Discard 1 File") - : localize('discardAll', "Discard All {0} Files", resources.length); - const pick = await window.showWarningMessage(message, { modal: true }, yes); - - if (pick !== yes) { - return; - } - - await repository.clean(resources.map(r => r.resourceUri)); - return; + await this._cleanTrackedChanges(repository, resources); } else if (resources.length === 1) { - 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); - - if (pick !== yes) { - return; - } - - await repository.clean(resources.map(r => r.resourceUri)); + await this._cleanUntrackedChange(repository, resources[0]); } else if (trackedResources.length === 0) { - const message = localize('confirm delete multiple', "Are you sure you want to DELETE {0} files?", resources.length); - const yes = localize('delete files', "Delete Files"); - const pick = await window.showWarningMessage(message, { modal: true }, yes); - - if (pick !== yes) { - return; - } - - await repository.clean(resources.map(r => r.resourceUri)); - + await this._cleanUntrackedChanges(repository, resources); } else { // resources.length > 1 && untrackedResources.length > 0 && trackedResources.length > 0 const untrackedMessage = untrackedResources.length === 1 ? localize('there are untracked files single', "The following untracked file will be DELETED FROM DISK if discarded: {0}.", path.basename(untrackedResources[0].resourceUri.fsPath)) @@ -1234,6 +1245,74 @@ export class CommandCenter { } } + @command('git.cleanAllTracked', { repository: true }) + async cleanAllTracked(repository: Repository): Promise { + const resources = repository.workingTreeGroup.resourceStates + .filter(r => r.type !== Status.UNTRACKED && r.type !== Status.IGNORED); + + if (resources.length === 0) { + return; + } + + await this._cleanTrackedChanges(repository, resources); + } + + @command('git.cleanAllUntracked', { repository: true }) + async cleanAllUntracked(repository: Repository): Promise { + const resources = [...repository.workingTreeGroup.resourceStates, ...repository.untrackedGroup.resourceStates] + .filter(r => r.type === Status.UNTRACKED || r.type === Status.IGNORED); + + if (resources.length === 0) { + return; + } + + if (resources.length === 1) { + await this._cleanUntrackedChange(repository, resources[0]); + } else { + await this._cleanUntrackedChanges(repository, resources); + } + } + + private async _cleanTrackedChanges(repository: Repository, resources: Resource[]): Promise { + const message = resources.length === 1 + ? localize('confirm discard all single', "Are you sure you want to discard changes in {0}?", path.basename(resources[0].resourceUri.fsPath)) + : localize('confirm discard all', "Are you sure you want to discard ALL changes in {0} files?\nThis is IRREVERSIBLE!\nYour current working set will be FOREVER LOST.", resources.length); + const yes = resources.length === 1 + ? localize('discardAll multiple', "Discard 1 File") + : localize('discardAll', "Discard All {0} Files", resources.length); + const pick = await window.showWarningMessage(message, { modal: true }, yes); + + if (pick !== yes) { + return; + } + + await repository.clean(resources.map(r => r.resourceUri)); + } + + private async _cleanUntrackedChange(repository: Repository, resource: Resource): Promise { + const message = localize('confirm delete', "Are you sure you want to DELETE {0}?\nThis is IRREVERSIBLE!\nThis file will be FOREVER LOST.", path.basename(resource.resourceUri.fsPath)); + const yes = localize('delete file', "Delete file"); + const pick = await window.showWarningMessage(message, { modal: true }, yes); + + if (pick !== yes) { + return; + } + + await repository.clean([resource.resourceUri]); + } + + private async _cleanUntrackedChanges(repository: Repository, resources: Resource[]): Promise { + const message = localize('confirm delete multiple', "Are you sure you want to DELETE {0} files?", resources.length); + const yes = localize('delete files', "Delete Files"); + const pick = await window.showWarningMessage(message, { modal: true }, yes); + + if (pick !== yes) { + return; + } + + await repository.clean(resources.map(r => r.resourceUri)); + } + private async smartCommit( repository: Repository, getCommitMessage: () => Promise, @@ -1249,13 +1328,15 @@ export class CommandCenter { promptToSaveFilesBeforeCommit = 'never'; } + const enableSmartCommit = config.get('enableSmartCommit') === true; + if (promptToSaveFilesBeforeCommit !== 'never') { let documents = workspace.textDocuments .filter(d => !d.isUntitled && d.isDirty && isDescendant(repository.root, d.uri.fsPath)); - if (promptToSaveFilesBeforeCommit === 'staged') { + if (promptToSaveFilesBeforeCommit === 'staged' || repository.indexGroup.resourceStates.length > 0) { documents = documents - .filter(d => repository.indexGroup.resourceStates.some(s => s.resourceUri.path === d.uri.fsPath)); + .filter(d => repository.indexGroup.resourceStates.some(s => pathEquals(s.resourceUri.fsPath, d.uri.fsPath))); } if (documents.length > 0) { @@ -1268,14 +1349,13 @@ export class CommandCenter { if (pick === saveAndCommit) { await Promise.all(documents.map(d => d.save())); - await repository.add(documents.map(d => d.uri)); + await repository.add([]); } else if (pick !== commit) { return false; // do not commit on cancel } } } - const enableSmartCommit = config.get('enableSmartCommit') === true; const enableCommitSigning = config.get('enableCommitSigning') === true; const noStagedChanges = repository.indexGroup.resourceStates.length === 0; const noUnstagedChanges = repository.workingTreeGroup.resourceStates.length === 0; @@ -1341,6 +1421,10 @@ export class CommandCenter { opts.all = 'tracked'; } + if (opts.all && config.get<'mixed' | 'separate' | 'hidden'>('untrackedChanges') !== 'mixed') { + opts.all = 'tracked'; + } + await repository.commit(message, opts); const postCommitCommand = config.get<'none' | 'push' | 'sync'>('postCommitCommand'); @@ -1360,28 +1444,38 @@ export class CommandCenter { private async commitWithAnyInput(repository: Repository, opts?: CommitOptions): Promise { const message = repository.inputBox.value; const getCommitMessage = async () => { - if (message) { - return message; + let _message: string | undefined = message; + if (!_message) { + let value: string | undefined = undefined; + + if (opts && opts.amend && repository.HEAD && repository.HEAD.commit) { + value = (await repository.getCommit(repository.HEAD.commit)).message; + } + + const branchName = repository.headShortName; + let placeHolder: string; + + if (branchName) { + placeHolder = localize('commitMessageWithHeadLabel2', "Message (commit on '{0}')", branchName); + } else { + placeHolder = localize('commit message', "Commit message"); + } + + _message = await window.showInputBox({ + value, + placeHolder, + prompt: localize('provide commit message', "Please provide a commit message"), + ignoreFocusOut: true + }); } - let value: string | undefined = undefined; - - if (opts && opts.amend && repository.HEAD && repository.HEAD.commit) { - value = (await repository.getCommit(repository.HEAD.commit)).message; - } - - return await window.showInputBox({ - value, - placeHolder: localize('commit message', "Commit message"), - prompt: localize('provide commit message', "Please provide a commit message"), - ignoreFocusOut: true - }); + return _message ? repository.cleanUpCommitEditMessage(_message) : _message; }; const didCommit = await this.smartCommit(repository, getCommitMessage, opts); if (message && didCommit) { - repository.inputBox.value = await repository.getCommitTemplate(); + repository.inputBox.value = await repository.getInputTemplate(); } } @@ -1458,6 +1552,15 @@ export class CommandCenter { const commit = await repository.getCommit('HEAD'); + if (commit.parents.length > 1) { + const yes = localize('undo commit', "Undo merge commit"); + const result = await window.showWarningMessage(localize('merge commit', "The last commit was a merge commit. Are you sure you want to undo it?"), { modal: true }, yes); + + if (result !== yes) { + return; + } + } + if (commit.parents.length > 0) { await repository.reset('HEAD~'); } else { @@ -1483,7 +1586,6 @@ export class CommandCenter { const quickpick = window.createQuickPick(); quickpick.items = picks; quickpick.placeholder = placeHolder; - quickpick.ignoreFocusOut = true; quickpick.show(); const choice = await new Promise(c => quickpick.onDidAccept(() => c(quickpick.activeItems[0]))); @@ -1672,6 +1774,26 @@ export class CommandCenter { await repository.tag(name, message); } + @command('git.deleteTag', { repository: true }) + async deleteTag(repository: Repository): Promise { + const picks = repository.refs.filter(ref => ref.type === RefType.Tag) + .map(ref => new TagItem(ref)); + + if (picks.length === 0) { + window.showWarningMessage(localize('no tags', "This repository has no tags.")); + return; + } + + const placeHolder = localize('select a tag to delete', 'Select a tag to delete'); + const choice = await window.showQuickPick(picks, { placeHolder }); + + if (!choice) { + return; + } + + await repository.deleteTag(choice.label); + } + @command('git.fetch', { repository: true }) async fetch(repository: Repository): Promise { if (repository.remotes.length === 0) { @@ -1722,7 +1844,7 @@ export class CommandCenter { const remoteRefs = repository.refs; const remoteRefsFiltered = remoteRefs.filter(r => (r.remote === remotePick.label)); - const branchPicks = remoteRefsFiltered.map(r => ({ label: r.name })) as { label: string; description: string }[]; + const branchPicks = remoteRefsFiltered.map(r => ({ label: r.name! })); const branchPlaceHolder = localize('pick branch pull', "Pick a branch to pull from"); const branchPick = await window.showQuickPick(branchPicks, { placeHolder: branchPlaceHolder }); @@ -1829,15 +1951,24 @@ export class CommandCenter { } } else { const branchName = repository.HEAD.name; - const picks = remotes.filter(r => r.pushUrl !== undefined).map(r => ({ label: r.name, description: r.pushUrl! })); + const addRemote = new AddRemoteItem(this); + const picks = [...remotes.filter(r => r.pushUrl !== undefined).map(r => ({ label: r.name, description: r.pushUrl })), addRemote]; const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName); - const pick = await window.showQuickPick(picks, { placeHolder }); + const choice = await window.showQuickPick(picks, { placeHolder }); - if (!pick) { + if (!choice) { return; } - await repository.pushTo(pick.label, branchName, undefined, forcePushMode); + if (choice === addRemote) { + const newRemote = await this.addRemote(repository); + + if (newRemote) { + await repository.pushTo(newRemote, branchName, undefined, forcePushMode); + } + } else { + await repository.pushTo(choice.label, branchName, undefined, forcePushMode); + } } } @@ -1872,7 +2003,7 @@ export class CommandCenter { } @command('git.addRemote', { repository: true }) - async addRemote(repository: Repository): Promise { + async addRemote(repository: Repository): Promise { const remotes = repository.remotes; const sanitize = (name: string) => { @@ -1914,6 +2045,8 @@ export class CommandCenter { } await repository.addRemote(name, url); + + return name; } @command('git.removeRemote', { repository: true }) @@ -2029,19 +2162,25 @@ export class CommandCenter { return; } + const addRemote = new AddRemoteItem(this); + const picks = [...repository.remotes.map(r => ({ label: r.name, description: r.pushUrl })), addRemote]; const branchName = repository.HEAD && repository.HEAD.name || ''; - const selectRemote = async () => { - const picks = repository.remotes.map(r => r.name); - const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName); - return await window.showQuickPick(picks, { placeHolder }); - }; - const choice = remotes.length === 1 ? remotes[0].name : await selectRemote(); + const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName); + const choice = await window.showQuickPick(picks, { placeHolder }); if (!choice) { return; } - await repository.pushTo(choice, branchName, true); + if (choice === addRemote) { + const newRemote = await this.addRemote(repository); + + if (newRemote) { + await repository.pushTo(newRemote, branchName, true); + } + } else { + await repository.pushTo(choice.label, branchName, true); + } } @command('git.ignore') @@ -2069,8 +2208,22 @@ export class CommandCenter { await this.runByRepository(resources, async (repository, resources) => repository.ignore(resources)); } + @command('git.revealInExplorer') + async revealInExplorer(resourceState: SourceControlResourceState): Promise { + if (!resourceState) { + return; + } + + if (!(resourceState.resourceUri instanceof Uri)) { + return; + } + + await commands.executeCommand('revealInExplorer', resourceState.resourceUri); + } + private async _stash(repository: Repository, includeUntracked = false): Promise { - const noUnstagedChanges = repository.workingTreeGroup.resourceStates.length === 0; + const noUnstagedChanges = repository.workingTreeGroup.resourceStates.length === 0 + && (!includeUntracked || repository.untrackedGroup.resourceStates.length === 0); const noStagedChanges = repository.indexGroup.resourceStates.length === 0; if (noUnstagedChanges && noStagedChanges) { @@ -2152,6 +2305,18 @@ export class CommandCenter { await repository.applyStash(); } + @command('git.stashDrop', { repository: true }) + async stashDrop(repository: Repository): Promise { + const placeHolder = localize('pick stash to drop', "Pick a stash to drop"); + const stash = await this.pickStash(repository, placeHolder); + + if (!stash) { + return; + } + + await repository.dropStash(stash.index); + } + private async pickStash(repository: Repository, placeHolder: string): Promise { const stashes = await repository.getStashes(); diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index 1b36349886e..12883fe46d4 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -113,6 +113,7 @@ class GitDecorationProvider implements DecorationProvider { this.collectSubmoduleDecorationData(newDecorations); this.collectDecorationData(this.repository.indexGroup, newDecorations); + this.collectDecorationData(this.repository.untrackedGroup, newDecorations); this.collectDecorationData(this.repository.workingTreeGroup, newDecorations); this.collectDecorationData(this.repository.mergeGroup, newDecorations); diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 5d47228c455..a397664fea4 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -12,10 +12,12 @@ 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, splitInChunks, Limiter } from './util'; -import { CancellationToken } from 'vscode'; +import { CancellationToken, Progress } from 'vscode'; import { URI } from 'vscode-uri'; import { detectEncoding } from './encoding'; import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status } from './api/git'; +import * as byline from 'byline'; +import { StringDecoder } from 'string_decoder'; // https://github.com/microsoft/vscode/issues/65693 const MAX_CLI_LENGTH = 30000; @@ -163,6 +165,7 @@ export interface SpawnOptions extends cp.SpawnOptions { encoding?: string; log?: boolean; cancellationToken?: CancellationToken; + onSpawn?: (childProcess: cp.ChildProcess) => void; } async function exec(child: cp.ChildProcess, cancellationToken?: CancellationToken): Promise> { @@ -193,13 +196,13 @@ async function exec(child: cp.ChildProcess, cancellationToken?: CancellationToke }), new Promise(c => { const buffers: Buffer[] = []; - on(child.stdout, 'data', (b: Buffer) => buffers.push(b)); - once(child.stdout, 'close', () => c(Buffer.concat(buffers))); + on(child.stdout!, 'data', (b: Buffer) => buffers.push(b)); + once(child.stdout!, 'close', () => c(Buffer.concat(buffers))); }), new Promise(c => { const buffers: Buffer[] = []; - on(child.stderr, 'data', (b: Buffer) => buffers.push(b)); - once(child.stderr, 'close', () => c(Buffer.concat(buffers).toString('utf8'))); + on(child.stderr!, 'data', (b: Buffer) => buffers.push(b)); + once(child.stderr!, 'close', () => c(Buffer.concat(buffers).toString('utf8'))); }) ]) as Promise<[number, Buffer, string]>; @@ -341,7 +344,7 @@ export class Git { return; } - async clone(url: string, parentPath: string, cancellationToken?: CancellationToken): Promise { + async clone(url: string, parentPath: string, progress: Progress<{ increment: number }>, cancellationToken?: CancellationToken): Promise { let baseFolderName = decodeURI(url).replace(/[\/]+$/, '').replace(/^.*[\/\\]/, '').replace(/\.git$/, '') || 'repository'; let folderName = baseFolderName; let folderPath = path.join(parentPath, folderName); @@ -354,8 +357,36 @@ export class Git { await mkdirp(parentPath); + const onSpawn = (child: cp.ChildProcess) => { + const decoder = new StringDecoder('utf8'); + const lineStream = new byline.LineStream({ encoding: 'utf8' }); + child.stderr!.on('data', (buffer: Buffer) => lineStream.write(decoder.write(buffer))); + + let totalProgress = 0; + let previousProgress = 0; + + lineStream.on('data', (line: string) => { + let match: RegExpMatchArray | null = null; + + if (match = /Counting objects:\s*(\d+)%/i.exec(line)) { + totalProgress = Math.floor(parseInt(match[1]) * 0.1); + } else if (match = /Compressing objects:\s*(\d+)%/i.exec(line)) { + totalProgress = 10 + Math.floor(parseInt(match[1]) * 0.1); + } else if (match = /Receiving objects:\s*(\d+)%/i.exec(line)) { + totalProgress = 20 + Math.floor(parseInt(match[1]) * 0.4); + } else if (match = /Resolving deltas:\s*(\d+)%/i.exec(line)) { + totalProgress = 60 + Math.floor(parseInt(match[1]) * 0.4); + } + + if (totalProgress !== previousProgress) { + progress.report({ increment: totalProgress - previousProgress }); + previousProgress = totalProgress; + } + }); + }; + try { - await this.exec(parentPath, ['clone', url.includes(' ') ? encodeURI(url) : url, folderPath], { cancellationToken }); + await this.exec(parentPath, ['clone', url.includes(' ') ? encodeURI(url) : url, folderPath, '--progress'], { cancellationToken, onSpawn }); } catch (err) { if (err.stderr) { err.stderr = err.stderr.replace(/^Cloning.+$/m, '').trim(); @@ -370,7 +401,8 @@ export class Git { async getRepositoryRoot(repositoryPath: string): Promise { const result = await this.exec(repositoryPath, ['rev-parse', '--show-toplevel']); - return path.normalize(result.stdout.trim()); + // Keep trailing spaces which are part of the directory name + return path.normalize(result.stdout.trimLeft().replace(/(\r\n|\r|\n)+$/, '')); } async getRepositoryDotGit(repositoryPath: string): Promise { @@ -401,8 +433,12 @@ export class Git { private async _exec(args: string[], options: SpawnOptions = {}): Promise> { const child = this.spawn(args, options); + if (options.onSpawn) { + options.onSpawn(child); + } + if (options.input) { - child.stdin.end(options.input, 'utf8'); + child.stdin!.end(options.input, 'utf8'); } const bufferResult = await exec(child, options.cancellationToken); @@ -846,7 +882,7 @@ export class Repository { async detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }> { const child = await this.stream(['show', object]); - const buffer = await readBytes(child.stdout, 4100); + const buffer = await readBytes(child.stdout!, 4100); try { child.kill(); @@ -1115,7 +1151,7 @@ export class Repository { async stage(path: string, data: string): Promise { const child = this.stream(['hash-object', '--stdin', '-w', '--path', path], { stdio: [null, null, null] }); - child.stdin.end(data, 'utf8'); + child.stdin!.end(data, 'utf8'); const { exitCode, stdout } = await exec(child); const hash = stdout.toString('utf8'); @@ -1291,6 +1327,11 @@ export class Repository { await this.run(args); } + async deleteTag(name: string): Promise { + let args = ['tag', '-d', name]; + await this.run(args); + } + async clean(paths: string[]): Promise { const pathsByGroup = groupBy(paths, p => path.dirname(p)); const groups = Object.keys(pathsByGroup).map(k => pathsByGroup[k]); @@ -1366,8 +1407,9 @@ export class Repository { await this.run(args); } - async fetch(options: { remote?: string, ref?: string, all?: boolean, prune?: boolean, depth?: number } = {}): Promise { + async fetch(options: { remote?: string, ref?: string, all?: boolean, prune?: boolean, depth?: number, silent?: boolean } = {}): Promise { const args = ['fetch']; + const spawnOptions: SpawnOptions = {}; if (options.remote) { args.push(options.remote); @@ -1387,8 +1429,12 @@ export class Repository { args.push(`--depth=${options.depth}`); } + if (options.silent) { + spawnOptions.env = { 'VSCODE_GIT_FETCH_SILENT': 'true' }; + } + try { - await this.run(args); + await this.run(args, spawnOptions); } catch (err) { if (/No remote repository specified\./.test(err.stderr || '')) { err.gitErrorCode = GitErrorCodes.NoRemoteRepositorySpecified; @@ -1551,6 +1597,24 @@ export class Repository { } } + async dropStash(index?: number): Promise { + const args = ['stash', 'drop']; + + if (typeof index === 'number') { + args.push(`stash@{${index}}`); + } + + try { + await this.run(args); + } catch (err) { + if (/No stash found/.test(err.stderr || '')) { + err.gitErrorCode = GitErrorCodes.NoStashFound; + } + + throw err; + } + } + getStatus(limit = 5000): Promise<{ status: IFileStatus[]; didHitLimit: boolean; }> { return new Promise<{ status: IFileStatus[]; didHitLimit: boolean; }>((c, e) => { const parser = new GitStatusParser(); @@ -1577,19 +1641,19 @@ export class Repository { if (parser.status.length > limit) { child.removeListener('exit', onExit); - child.stdout.removeListener('data', onStdoutData); + child.stdout!.removeListener('data', onStdoutData); child.kill(); c({ status: parser.status.slice(0, limit), didHitLimit: true }); } }; - child.stdout.setEncoding('utf8'); - child.stdout.on('data', onStdoutData); + child.stdout!.setEncoding('utf8'); + child.stdout!.on('data', onStdoutData); const stderrData: string[] = []; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', raw => stderrData.push(raw as string)); + child.stderr!.setEncoding('utf8'); + child.stderr!.on('data', raw => stderrData.push(raw as string)); child.on('error', cpErrorHandler(e)); child.on('exit', onExit); @@ -1748,6 +1812,23 @@ export class Repository { } } + cleanupCommitEditMessage(message: string): string { + //TODO: Support core.commentChar + return message.replace(/^\s*#.*$\n?/gm, '').trim(); + } + + + async getMergeMessage(): Promise { + const mergeMsgPath = path.join(this.repositoryRoot, '.git', 'MERGE_MSG'); + + try { + const raw = await readfile(mergeMsgPath, 'utf8'); + return raw.trim(); + } catch { + return undefined; + } + } + async getCommitTemplate(): Promise { try { const result = await this.run(['config', '--get', 'commit.template']); @@ -1766,7 +1847,7 @@ export class Repository { } const raw = await readfile(templatePath, 'utf8'); - return raw.replace(/^\s*#.*$\n?/gm, ''); + return raw.trim(); } catch (err) { return ''; diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index da6a940428e..da6f150efa4 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -190,7 +190,7 @@ export class Model { openRepositoriesToDispose.forEach(r => r.dispose()); } - private async onDidChangeVisibleTextEditors(editors: TextEditor[]): Promise { + private async onDidChangeVisibleTextEditors(editors: readonly TextEditor[]): Promise { const config = workspace.getConfiguration('git'); const autoRepositoryDetection = config.get('autoRepositoryDetection'); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index fadd1ac6e74..949c97bb8a3 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -3,17 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, Decoration, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env, ProgressOptions, CancellationToken } 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, combinedDisposable } from './util'; -import { memoize, throttle, debounce } from './decorators'; -import { toGitUri } from './uri'; -import { AutoFetcher } from './autofetch'; -import * as path from 'path'; -import * as nls from 'vscode-nls'; import * as fs from 'fs'; +import * as path from 'path'; +import { CancellationToken, Command, Disposable, env, Event, EventEmitter, LogLevel, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, Decoration } from 'vscode'; +import * as nls from 'vscode-nls'; +import { Branch, Change, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status } from './api/git'; +import { AutoFetcher } from './autofetch'; +import { debounce, memoize, throttle } from './decorators'; +import { Commit, CommitOptions, ForcePushMode, GitError, Repository as BaseRepository, Stash, Submodule } from './git'; import { StatusBarCommands } from './statusbar'; -import { Branch, Ref, Remote, RefType, GitErrorCodes, Status, LogOptions, Change } from './api/git'; +import { toGitUri } from './uri'; +import { anyEvent, combinedDisposable, debounceEvent, dispose, EmptyDisposable, eventToPromise, filterEvent, find, IDisposable, isDescendant, onceEvent } from './util'; import { IFileWatcher, watch } from './watch'; const timeout = (millis: number) => new Promise(c => setTimeout(c, millis)); @@ -33,7 +33,8 @@ export const enum RepositoryState { export const enum ResourceGroupType { Merge, Index, - WorkingTree + WorkingTree, + Untracked } export class Resource implements SourceControlResourceState { @@ -292,6 +293,7 @@ export const enum Operation { Merge = 'Merge', Ignore = 'Ignore', Tag = 'Tag', + DeleteTag = 'DeleteTag', Stash = 'Stash', CheckIgnore = 'CheckIgnore', GetObjectDetails = 'GetObjectDetails', @@ -569,6 +571,9 @@ export class Repository implements Disposable { private _workingTreeGroup: SourceControlResourceGroup; get workingTreeGroup(): GitResourceGroup { return this._workingTreeGroup as GitResourceGroup; } + private _untrackedGroup: SourceControlResourceGroup; + get untrackedGroup(): GitResourceGroup { return this._untrackedGroup as GitResourceGroup; } + private _HEAD: Branch | undefined; get HEAD(): Branch | undefined { return this._HEAD; @@ -579,6 +584,27 @@ export class Repository implements Disposable { return this._refs; } + get headShortName(): string | undefined { + if (!this.HEAD) { + return; + } + + const HEAD = this.HEAD; + + if (HEAD.name) { + return HEAD.name; + } + + const tag = this.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0]; + const tagName = tag && tag.name; + + if (tagName) { + return tagName; + } + + return (HEAD.commit || '').substr(0, 8); + } + private _remotes: Remote[] = []; get remotes(): Remote[] { return this._remotes; @@ -620,6 +646,7 @@ export class Repository implements Disposable { this.mergeGroup.resourceStates = []; this.indexGroup.resourceStates = []; this.workingTreeGroup.resourceStates = []; + this.untrackedGroup.resourceStates = []; this._sourceControl.count = 0; } @@ -687,6 +714,7 @@ export class Repository implements Disposable { 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._untrackedGroup = this._sourceControl.createResourceGroup('untracked', localize('untracked changes', "UNTRACKED CHANGES")); const updateIndexGroupVisibility = () => { const config = workspace.getConfiguration('git', root); @@ -700,11 +728,16 @@ export class Repository implements Disposable { const onConfigListenerForBranchSortOrder = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.branchSortOrder', root)); onConfigListenerForBranchSortOrder(this.updateModelState, this, this.disposables); + const onConfigListenerForUntracked = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.untrackedChanges', root)); + onConfigListenerForUntracked(this.updateModelState, this, this.disposables); + this.mergeGroup.hideWhenEmpty = true; + this.untrackedGroup.hideWhenEmpty = true; this.disposables.push(this.mergeGroup); this.disposables.push(this.indexGroup); this.disposables.push(this.workingTreeGroup); + this.disposables.push(this.untrackedGroup); this.disposables.push(new AutoFetcher(this, globalState)); @@ -729,8 +762,6 @@ export class Repository implements Disposable { const onDidChangeCountBadge = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.countBadge', root)); onDidChangeCountBadge(this.setCountBadge, this, this.disposables); this.setCountBadge(); - - this.updateCommitTemplate(); } validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined { @@ -806,12 +837,14 @@ export class Repository implements Disposable { return toGitUri(uri, '', { replaceFileExtension: true }); } - private async updateCommitTemplate(): Promise { - try { - this._sourceControl.commitTemplate = await this.repository.getCommitTemplate(); - } catch (e) { - // noop + async getInputTemplate(): Promise { + const mergeMessage = await this.repository.getMergeMessage(); + + if (mergeMessage) { + return mergeMessage; } + + return await this.repository.getCommitTemplate(); } getConfigs(): Promise<{ key: string; value: string; }[]> { @@ -890,8 +923,8 @@ export class Repository implements Disposable { return this.run(Operation.HashObject, () => this.repository.hashObject(data)); } - async add(resources: Uri[]): Promise { - await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath))); + async add(resources: Uri[], opts?: { update?: boolean }): Promise { + await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.fsPath), opts)); } async rm(resources: Uri[]): Promise { @@ -936,6 +969,7 @@ export class Repository implements Disposable { const toClean: string[] = []; const toCheckout: string[] = []; const submodulesToUpdate: string[] = []; + const resourceStates = [...this.workingTreeGroup.resourceStates, ...this.untrackedGroup.resourceStates]; resources.forEach(r => { const fsPath = r.fsPath; @@ -948,7 +982,7 @@ export class Repository implements Disposable { } const raw = r.toString(); - const scmResource = find(this.workingTreeGroup.resourceStates, sr => sr.resourceUri.toString() === raw); + const scmResource = find(resourceStates, sr => sr.resourceUri.toString() === raw); if (!scmResource) { return; @@ -1000,6 +1034,10 @@ export class Repository implements Disposable { await this.run(Operation.Tag, () => this.repository.tag(name, message)); } + async deleteTag(name: string): Promise { + await this.run(Operation.DeleteTag, () => this.repository.deleteTag(name)); + } + async checkout(treeish: string): Promise { await this.run(Operation.Checkout, () => this.repository.checkout(treeish, [])); } @@ -1033,8 +1071,8 @@ export class Repository implements Disposable { } @throttle - async fetchDefault(): Promise { - await this.run(Operation.Fetch, () => this.repository.fetch()); + async fetchDefault(options: { silent?: boolean } = {}): Promise { + await this.run(Operation.Fetch, () => this.repository.fetch(options)); } @throttle @@ -1228,6 +1266,10 @@ export class Repository implements Disposable { return await this.run(Operation.Stash, () => this.repository.popStash(index)); } + async dropStash(index?: number): Promise { + return await this.run(Operation.Stash, () => this.repository.dropStash(index)); + } + async applyStash(index?: number): Promise { return await this.run(Operation.Stash, () => this.repository.applyStash(index)); } @@ -1236,6 +1278,10 @@ export class Repository implements Disposable { return await this.run(Operation.GetCommitTemplate, async () => this.repository.getCommitTemplate()); } + async cleanUpCommitEditMessage(editMessage: string): Promise { + return this.repository.cleanupCommitEditMessage(editMessage); + } + async ignore(files: Uri[]): Promise { return await this.run(Operation.Ignore, async () => { const ignoreFile = `${this.repository.root}${path.sep}.gitignore`; @@ -1273,7 +1319,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', '-v', '-z', '--stdin'], { stdio: [null, null, null] }); - child.stdin.end(filePaths.join('\0'), 'utf8'); + child.stdin!.end(filePaths.join('\0'), 'utf8'); const onExit = (exitCode: number) => { if (exitCode === 1) { @@ -1295,12 +1341,12 @@ export class Repository implements Disposable { data += raw; }; - child.stdout.setEncoding('utf8'); - child.stdout.on('data', onStdoutData); + child.stdout!.setEncoding('utf8'); + child.stdout!.on('data', onStdoutData); let stderr: string = ''; - child.stderr.setEncoding('utf8'); - child.stderr.on('data', raw => stderr += raw); + child.stderr!.setEncoding('utf8'); + child.stderr!.on('data', raw => stderr += raw); child.on('error', reject); child.on('exit', onExit); @@ -1402,6 +1448,7 @@ export class Repository implements Disposable { private async updateModelState(): Promise { const { status, didHitLimit } = await this.repository.getStatus(); const config = workspace.getConfiguration('git'); + const scopedConfig = workspace.getConfiguration('git', Uri.file(this.repository.root)); const shouldIgnore = config.get('ignoreLimitWarning') === true; const useIcons = !config.get('decorations.enabled', true); this.isRepositoryHuge = didHitLimit; @@ -1457,22 +1504,34 @@ export class Repository implements Disposable { const [refs, remotes, submodules, rebaseCommit] = await Promise.all([this.repository.getRefs({ sort }), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit()]); this._HEAD = HEAD; - this._refs = refs; - this._remotes = remotes; - this._submodules = submodules; + this._refs = refs!; + this._remotes = remotes!; + this._submodules = submodules!; this.rebaseCommit = rebaseCommit; + const untrackedChanges = scopedConfig.get<'mixed' | 'separate' | 'hidden'>('untrackedChanges'); const index: Resource[] = []; const workingTree: Resource[] = []; const merge: Resource[] = []; + const untracked: Resource[] = []; status.forEach(raw => { const uri = Uri.file(path.join(this.repository.root, raw.path)); - const renameUri = raw.rename ? Uri.file(path.join(this.repository.root, raw.rename)) : undefined; + const renameUri = raw.rename + ? Uri.file(path.join(this.repository.root, raw.rename)) + : undefined; switch (raw.x + raw.y) { - case '??': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons)); - case '!!': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons)); + case '??': switch (untrackedChanges) { + case 'mixed': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons)); + case 'separate': return untracked.push(new Resource(ResourceGroupType.Untracked, uri, Status.UNTRACKED, useIcons)); + default: return undefined; + } + case '!!': switch (untrackedChanges) { + case 'mixed': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons)); + case 'separate': return untracked.push(new Resource(ResourceGroupType.Untracked, uri, Status.IGNORED, useIcons)); + default: return undefined; + } case 'DD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_DELETED, useIcons)); case 'AU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_US, useIcons)); case 'UD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_THEM, useIcons)); @@ -1495,6 +1554,7 @@ export class Repository implements Disposable { case 'D': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break; case 'A': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri)); break; } + return undefined; }); @@ -1502,20 +1562,38 @@ export class Repository implements Disposable { this.mergeGroup.resourceStates = merge; this.indexGroup.resourceStates = index; this.workingTreeGroup.resourceStates = workingTree; + this.untrackedGroup.resourceStates = untracked; // set count badge this.setCountBadge(); this._onDidChangeStatus.fire(); + + this._sourceControl.commitTemplate = await this.getInputTemplate(); } private setCountBadge(): void { - const countBadge = workspace.getConfiguration('git').get('countBadge'); - let count = this.mergeGroup.resourceStates.length + this.indexGroup.resourceStates.length + this.workingTreeGroup.resourceStates.length; + const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); + const countBadge = config.get<'all' | 'tracked' | 'off'>('countBadge'); + const untrackedChanges = config.get<'mixed' | 'separate' | 'hidden'>('untrackedChanges'); + + let count = + this.mergeGroup.resourceStates.length + + this.indexGroup.resourceStates.length + + this.workingTreeGroup.resourceStates.length; switch (countBadge) { case 'off': count = 0; break; - case 'tracked': count = count - this.workingTreeGroup.resourceStates.filter(r => r.type === Status.UNTRACKED || r.type === Status.IGNORED).length; break; + case 'tracked': + if (untrackedChanges === 'mixed') { + count -= this.workingTreeGroup.resourceStates.filter(r => r.type === Status.UNTRACKED || r.type === Status.IGNORED).length; + } + break; + case 'all': + if (untrackedChanges === 'separate') { + count += this.untrackedGroup.resourceStates.length; + } + break; } this._sourceControl.count = count; @@ -1617,7 +1695,7 @@ export class Repository implements Disposable { const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8); return head - + (this.workingTreeGroup.resourceStates.length > 0 ? '*' : '') + + (this.workingTreeGroup.resourceStates.length + this.untrackedGroup.resourceStates.length > 0 ? '*' : '') + (this.indexGroup.resourceStates.length > 0 ? '+' : '') + (this.mergeGroup.resourceStates.length > 0 ? '!' : ''); } @@ -1643,15 +1721,11 @@ export class Repository implements Disposable { } private updateInputBoxPlaceholder(): void { - const HEAD = this.HEAD; - - if (HEAD) { - const tag = this.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0]; - const tagName = tag && tag.name; - const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8); + const branchName = this.headShortName; + if (branchName) { // '{0}' will be replaced by the corresponding key-command later in the process, which is why it needs to stay. - this._sourceControl.inputBox.placeholder = localize('commitMessageWithHeadLabel', "Message ({0} to commit on '{1}')", "{0}", head); + this._sourceControl.inputBox.placeholder = localize('commitMessageWithHeadLabel', "Message ({0} to commit on '{1}')", "{0}", branchName); } else { this._sourceControl.inputBox.placeholder = localize('commitMessage', "Message ({0} to commit)"); } diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index d2e201ca01d..0722cb16fbd 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -160,7 +160,7 @@ export async function mkdirp(path: string, mode?: number): Promise { if (err.code === 'EEXIST') { const stat = await nfcall(fs.stat, path); - if (stat.isDirectory) { + if (stat.isDirectory()) { return; } diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index 1f2ea8aed42..2bfd883067d 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.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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== "@types/which@^1.0.28": version "1.0.28" diff --git a/extensions/grunt/package.json b/extensions/grunt/package.json index f65cc6e62b0..40344a17913 100644 --- a/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -20,7 +20,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" }, "main": "./out/main", "activationEvents": [ @@ -55,6 +55,10 @@ "type": "string", "description": "%grunt.taskDefinition.type.description%" }, + "args": { + "type": "array", + "description": "%grunt.taskDefinition.args.description%" + }, "file": { "type": "string", "description": "%grunt.taskDefinition.file.description%" diff --git a/extensions/grunt/package.nls.json b/extensions/grunt/package.nls.json index 7f1b68bbe0b..873de038882 100644 --- a/extensions/grunt/package.nls.json +++ b/extensions/grunt/package.nls.json @@ -3,5 +3,6 @@ "displayName": "Grunt support for VS Code", "config.grunt.autoDetect": "Controls whether auto detection of Grunt tasks is on or off. Default is on.", "grunt.taskDefinition.type.description": "The Grunt task to customize.", + "grunt.taskDefinition.args.description": "Command line arguments to pass to the grunt task", "grunt.taskDefinition.file.description": "The Grunt file that provides the task. Can be omitted." -} \ No newline at end of file +} diff --git a/extensions/grunt/src/main.ts b/extensions/grunt/src/main.ts index 3756d7522e3..d8ef8a82673 100644 --- a/extensions/grunt/src/main.ts +++ b/extensions/grunt/src/main.ts @@ -67,6 +67,7 @@ function showError() { } interface GruntTaskDefinition extends vscode.TaskDefinition { task: string; + args?: string[]; file?: string; } @@ -121,14 +122,14 @@ class FolderDetector { } public async getTask(_task: vscode.Task): Promise { - const gruntTask = (_task.definition).task; + const taskDefinition = _task.definition; + const gruntTask = taskDefinition.task; if (gruntTask) { - let kind: GruntTaskDefinition = (_task.definition); let options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath }; let source = 'grunt'; let task = gruntTask.indexOf(' ') === -1 - ? new vscode.Task(kind, this.workspaceFolder, gruntTask, source, new vscode.ShellExecution(`${await this._gruntCommand} ${gruntTask.name}`, options)) - : new vscode.Task(kind, this.workspaceFolder, gruntTask, source, new vscode.ShellExecution(`${await this._gruntCommand} "${gruntTask.name}"`, options)); + ? new vscode.Task(taskDefinition, this.workspaceFolder, gruntTask, source, new vscode.ShellExecution(`${await this._gruntCommand}`, [gruntTask, ...taskDefinition.args], options)) + : new vscode.Task(taskDefinition, this.workspaceFolder, gruntTask, source, new vscode.ShellExecution(`${await this._gruntCommand}`, [`"${gruntTask}"`, ...taskDefinition.args], options)); return task; } return undefined; diff --git a/extensions/grunt/yarn.lock b/extensions/grunt/yarn.lock index e6247e29255..7af62a72ce7 100644 --- a/extensions/grunt/yarn.lock +++ b/extensions/grunt/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/gulp/package.json b/extensions/gulp/package.json index b602bf30c7d..3577dd8e37e 100644 --- a/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -20,7 +20,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" }, "main": "./out/main", "activationEvents": [ diff --git a/extensions/gulp/yarn.lock b/extensions/gulp/yarn.lock index e6247e29255..7af62a72ce7 100644 --- a/extensions/gulp/yarn.lock +++ b/extensions/gulp/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/html-language-features/client/src/customData.ts b/extensions/html-language-features/client/src/customData.ts index 4c89d719539..14d8a66a8aa 100644 --- a/extensions/html-language-features/client/src/customData.ts +++ b/extensions/html-language-features/client/src/customData.ts @@ -34,22 +34,6 @@ export function getCustomDataPathsInAllWorkspaces(workspaceFolders: WorkspaceFol }); } } - - if ( - wfHtmlConfig && - wfHtmlConfig.workspaceFolderValue && - wfHtmlConfig.workspaceFolderValue.experimental && - wfHtmlConfig.workspaceFolderValue.experimental.customData - ) { - const customData = wfHtmlConfig.workspaceFolderValue.experimental.customData; - if (Array.isArray(customData)) { - customData.forEach(t => { - if (typeof t === 'string') { - dataPaths.push(path.resolve(wf.uri.fsPath, t)); - } - }); - } - } }); return dataPaths; @@ -61,30 +45,12 @@ export function getCustomDataPathsFromAllExtensions(): string[] { for (const extension of extensions.all) { const contributes = extension.packageJSON && extension.packageJSON.contributes; - if ( - contributes && - contributes.html && - contributes.html.customData && - Array.isArray(contributes.html.customData) - ) { + if (contributes && contributes.html && contributes.html.customData && Array.isArray(contributes.html.customData)) { const relativePaths: string[] = contributes.html.customData; relativePaths.forEach(rp => { dataPaths.push(path.resolve(extension.extensionPath, rp)); }); } - - if ( - contributes && - contributes.html && - contributes.html.experimental && - contributes.html.experimental.customData && - Array.isArray(contributes.html.experimental.customData) - ) { - const relativePaths: string[] = contributes.html.experimental.customData; - relativePaths.forEach(rp => { - dataPaths.push(path.resolve(extension.extensionPath, rp)); - }); - } } return dataPaths; diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 5f98f732b52..89bdc325721 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -8,8 +8,8 @@ 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 } from 'vscode'; -import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams } from 'vscode-languageclient'; +import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace, Disposable, FormattingOptions, CancellationToken, ProviderResult, TextEdit } from 'vscode'; +import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams, DocumentRangeFormattingParams, DocumentRangeFormattingRequest } from 'vscode-languageclient'; import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; import TelemetryReporter from 'vscode-extension-telemetry'; @@ -50,6 +50,8 @@ export function activate(context: ExtensionContext) { let documentSelector = ['html', 'handlebars']; let embeddedLanguages = { css: true, javascript: true }; + let rangeFormatting: Disposable | undefined = undefined; + let dataPaths = [ ...getCustomDataPathsInAllWorkspaces(workspace.workspaceFolders), ...getCustomDataPathsFromAllExtensions() @@ -63,8 +65,9 @@ export function activate(context: ExtensionContext) { }, initializationOptions: { embeddedLanguages, - dataPaths - } + dataPaths, + provideFormatter: false, // tell the server to not provide formatting capability and ignore the `html.format.enable` setting. + }, }; // Create the language client and start the client. @@ -87,8 +90,38 @@ export function activate(context: ExtensionContext) { } }); toDispose.push(disposable); + + // manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652. + updateFormatterRegistration(); + toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() }); + toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration('html.format.enable') && updateFormatterRegistration())); }); + function updateFormatterRegistration() { + const formatEnabled = workspace.getConfiguration().get('html.format.enable'); + if (!formatEnabled && rangeFormatting) { + rangeFormatting.dispose(); + rangeFormatting = undefined; + } else if (formatEnabled && !rangeFormatting) { + rangeFormatting = languages.registerDocumentRangeFormattingEditProvider(documentSelector, { + provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult { + let params: DocumentRangeFormattingParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + range: client.code2ProtocolConverter.asRange(range), + options: client.code2ProtocolConverter.asFormattingOptions(options) + }; + return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then( + client.protocol2CodeConverter.asTextEdits, + (error) => { + client.logFailedRequest(DocumentRangeFormattingRequest.type, error); + return Promise.resolve([]); + } + ); + } + }); + } + } + languages.setLanguageConfiguration('html', { indentationRules: { increaseIndentPattern: /<(?!\?|(?:area|base|br|col|frame|hr|html|img|input|link|meta|param)\b|[^>]*\/>)([-_\.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!.*<\/\1>)|)|\{[^}"']*$/, diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index 557fe83ca86..7b8bc811406 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -41,16 +41,6 @@ }, "scope": "resource" }, - "html.experimental.customData": { - "type": "array", - "description": "A list of JSON file paths that define custom tags, properties and other HTML syntax constructs. Only workspace folder setting will be read.", - "default": [], - "items": { - "type": "string" - }, - "scope": "resource", - "deprecationMessage": "This setting is no longe experimental. Use `html.customData` instead." - }, "html.format.enable": { "type": "boolean", "scope": "window", @@ -197,10 +187,10 @@ }, "dependencies": { "vscode-extension-telemetry": "0.1.1", - "vscode-languageclient": "^5.3.0-next.6", + "vscode-languageclient": "^6.0.0-next.1", "vscode-nls": "^4.1.1" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" } } diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index e6eca4275bf..c1c84eae886 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,19 +9,19 @@ }, "main": "./out/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.3-next.8", - "vscode-html-languageservice": "^3.0.4-next.3", - "vscode-languageserver": "^5.3.0-next.8", - "vscode-languageserver-types": "3.15.0-next.2", + "vscode-css-languageservice": "^4.0.3-next.15", + "vscode-html-languageservice": "^3.0.4-next.6", + "vscode-languageserver": "^6.0.0-next.1", + "vscode-languageserver-types": "3.15.0-next.5", "vscode-nls": "^4.1.1", "vscode-uri": "^2.0.3" }, "devDependencies": { "@types/mocha": "2.2.33", - "@types/node": "^10.14.8", - "glob": "^7.1.2", - "mocha": "^5.2.0", - "mocha-junit-reporter": "^1.17.0", + "@types/node": "^12.11.7", + "glob": "^7.1.4", + "mocha": "^6.1.4", + "mocha-junit-reporter": "^1.23.1", "mocha-multi-reporters": "^1.1.7" }, "scripts": { diff --git a/extensions/html-language-features/server/src/htmlServerMain.ts b/extensions/html-language-features/server/src/htmlServerMain.ts index 01b43d9a9ba..9fd60b242eb 100644 --- a/extensions/html-language-features/server/src/htmlServerMain.ts +++ b/extensions/html-language-features/server/src/htmlServerMain.ts @@ -49,7 +49,7 @@ let workspaceFolders: WorkspaceFolder[] = []; let languageModes: LanguageModes; let clientSnippetSupport = false; -let clientDynamicRegisterSupport = false; +let dynamicFormatterRegistration = false; let scopedSettingsSupport = false; let workspaceFoldersSupport = false; let foldingRangeLimit = Number.MAX_VALUE; @@ -118,7 +118,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { } clientSnippetSupport = getClientCapability('textDocument.completion.completionItem.snippetSupport', false); - clientDynamicRegisterSupport = getClientCapability('workspace.symbol.dynamicRegistration', false); + dynamicFormatterRegistration = getClientCapability('textDocument.rangeFormatting.dynamicRegistration', false) && (typeof params.initializationOptions.provideFormatter !== 'boolean'); scopedSettingsSupport = getClientCapability('workspace.configuration', false); workspaceFoldersSupport = getClientCapability('workspace.workspaceFolders', false); foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); @@ -128,7 +128,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: ['.', ':', '<', '"', '=', '/'] } : undefined, hoverProvider: true, documentHighlightProvider: true, - documentRangeFormattingProvider: false, + documentRangeFormattingProvider: params.initializationOptions.provideFormatter === true, documentLinkProvider: { resolveProvider: false }, documentSymbolProvider: true, definitionProvider: true, @@ -136,7 +136,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { referencesProvider: true, colorProvider: {}, foldingRangeProvider: true, - selectionRangeProvider: true + selectionRangeProvider: true, }; return { capabilities }; }); @@ -171,7 +171,7 @@ connection.onDidChangeConfiguration((change) => { documents.all().forEach(triggerValidation); // dynamically enable & disable the formatter - if (clientDynamicRegisterSupport) { + if (dynamicFormatterRegistration) { const enableFormatter = globalSettings && globalSettings.html && globalSettings.html.format && globalSettings.html.format.enable; if (enableFormatter) { if (!formatterRegistration) { @@ -472,4 +472,4 @@ connection.onSelectionRanges((params, token) => { // Listen on the connection -connection.listen(); \ No newline at end of file +connection.listen(); diff --git a/extensions/html-language-features/server/src/modes/embeddedSupport.ts b/extensions/html-language-features/server/src/modes/embeddedSupport.ts index de80fa5c8e3..df47be3ed97 100644 --- a/extensions/html-language-features/server/src/modes/embeddedSupport.ts +++ b/extensions/html-language-features/server/src/modes/embeddedSupport.ts @@ -56,7 +56,7 @@ export function getDocumentRegions(languageService: LanguageService, document: T } importedScripts.push(value); } else if (lastAttributeName === 'type' && lastTagName.toLowerCase() === 'script') { - if (/["'](module|(text|application)\/(java|ecma)script)["']/.test(scanner.getTokenText())) { + if (/["'](module|(text|application)\/(java|ecma)script|text\/babel)["']/.test(scanner.getTokenText())) { languageIdFromType = 'javascript'; } else { languageIdFromType = undefined; @@ -228,4 +228,4 @@ function getAttributeLanguage(attributeName: string): string | null { return null; } return match[1] ? 'css' : 'javascript'; -} \ No newline at end of file +} diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index 7b9957f070d..ea357367f35 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -7,16 +7,40 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.33.tgz#d79a0061ec270379f4d9e225f4096fb436669def" integrity sha1-15oAYewnA3n02eIl9AlvtDZmne8= -"@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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== + +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@^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.0, 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,15 +59,45 @@ 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@^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" + +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" @@ -55,12 +109,12 @@ crypt@~0.0.1: 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 +123,115 @@ 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, define-properties@^1.1.3: + 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== + +es-abstract@^1.5.1: + version "1.14.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497" + integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.0" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-inspect "^1.6.0" + object-keys "^1.1.1" + string.prototype.trimleft "^2.0.0" + string.prototype.trimright "^2.0.0" + +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== + +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@^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== + +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 +250,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" @@ -129,11 +285,78 @@ is-buffer@~1.1.1: 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@^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-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" + +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.15: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +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" + md5@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" @@ -162,10 +385,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.1: + version "1.23.1" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.1.tgz#ba11519c0b967f404e4123dd69bc4ba022ab0f12" + integrity sha512-qeDvKlZyAH2YJE1vhryvjUQ06t2hcnwwu4k5Ddwn0GQINhgEYFhlGM0DwYCVUHq5cuo32qAW6HDsTHt7zz99Ng== dependencies: debug "^2.2.0" md5 "^2.1.0" @@ -181,28 +404,86 @@ 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.2.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.1.tgz#da941c99437da9bac412097859ff99543969f94c" + integrity sha512-VCcWkLHwk79NYQc8cxhkmI8IigTIhsCwZ6RTxQsqK6go4UvEhzJkYuHm8B2YtlSxcYq2fY+ucr4JBwoD6ci80A== 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.3.0" + yargs-parser "13.1.1" + yargs-unparser "1.6.0" ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +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== + +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" + +object-inspect@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" + integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + 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: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -210,11 +491,93 @@ once@^1.3.0: dependencies: wrappy "1" +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + 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= +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@^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.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +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= + +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.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-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.prototype.trimleft@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" + integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" + integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + 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 +585,75 @@ 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.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-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: has-flag "^3.0.0" -vscode-css-languageservice@^4.0.3-next.8: - version "4.0.3-next.8" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.8.tgz#0b81693b6ea9d10f78775a1dcad2c0f464fbde16" - integrity sha512-agBPPu86bPKIK5v6CFnWeBXN4jvnCzc67GZa/pvrIWeRdG7nvTu5Y2wYdwdesdpWzno9/5tfFEPp0KJbKQ4l+A== +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-languageserver-types "^3.15.0-next.2" + has-flag "^3.0.0" + +vscode-css-languageservice@^4.0.3-next.15: + version "4.0.3-next.15" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.15.tgz#e7b7dab2f1e6e9452bb2fb8c400dbcff3b8927aa" + integrity sha512-y2bNfcZgNH3F7R0N/1ePnVtzvGwi9f6leW5L0zPso/wVK9A4xw5rmZA1pTV9vMjoio2h3gUB1T8HTQeVxota2Q== + dependencies: + vscode-languageserver-types "^3.15.0-next.5" vscode-nls "^4.1.1" vscode-uri "^2.0.3" -vscode-html-languageservice@^3.0.4-next.3: - version "3.0.4-next.3" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.4-next.3.tgz#7a0fc33aae846165b157acbb8b133cc3fcf2ca0d" - integrity sha512-PGIcKFxqsvVMv51QWreuQx9LhN43Vzhgl8RYI8CcWThjl+J8uUKImjwAWq9zndOiiRUPF2Zk7zME/dMIis1hOw== +vscode-html-languageservice@^3.0.4-next.6: + version "3.0.4-next.6" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.4-next.6.tgz#ef0f535828f086bcf9bafb2609d54bb285d29d2a" + integrity sha512-DvFpvPJ9wGKIpNa6kxoUSRjZTzLadyKPO2rNhmU7oor9pAQbaNIdJBGoGCm3YELLLPFNcR0/jWDDC4z8wFPk3Q== dependencies: - vscode-languageserver-types "^3.15.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" 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-jsonrpc@^5.0.0-next.2: + version "5.0.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca" + integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg== -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== +vscode-languageserver-protocol@^3.15.0-next.9: + version "3.15.0-next.9" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30" + integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g== dependencies: - vscode-jsonrpc "^4.1.0-next.2" - vscode-languageserver-types "^3.15.0-next.2" + vscode-jsonrpc "^5.0.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" -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-types@3.15.0-next.5, vscode-languageserver-types@^3.15.0-next.5: + version "3.15.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b" + integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw== -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== +vscode-languageserver@^6.0.0-next.1: + version "6.0.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-6.0.0-next.1.tgz#4d71886d4a17d22eafc61b3a5fbf84e8e27c191f" + integrity sha512-LSF6bXoFeXfMPRNyqzI3yFX/kD2DzXBemqvyj1kDWNVraiWttm4xKF4YXsvJ7Z3s9sVt/Dpu3CFU3w61PGNZMg== dependencies: - vscode-languageserver-protocol "^3.15.0-next.6" + vscode-languageserver-protocol "^3.15.0-next.9" vscode-textbuffer "^1.0.0" - vscode-uri "^1.0.6" vscode-nls@^4.1.1: version "4.1.1" @@ -284,16 +665,39 @@ vscode-textbuffer@^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: + 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@^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" @@ -303,3 +707,41 @@ xml@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + +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.1.1, yargs-parser@^13.1.1: + 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.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs@13.3.0, yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + 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.1" diff --git a/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock index 21d801f04a0..e365fdb58b7 100644 --- a/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== applicationinsights@1.0.8: version "1.0.8" @@ -28,11 +28,16 @@ diagnostic-channel@0.2.0: dependencies: semver "^5.3.0" -semver@^5.3.0, semver@^5.5.0: +semver@^5.3.0: version "5.5.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + vscode-extension-telemetry@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b" @@ -40,31 +45,31 @@ vscode-extension-telemetry@0.1.1: dependencies: applicationinsights "1.0.8" -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-jsonrpc@^5.0.0-next.2: + version "5.0.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca" + integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg== -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== +vscode-languageclient@^6.0.0-next.1: + version "6.0.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-6.0.0-next.1.tgz#deca1743afd20da092e04e40ef73cedbbd978455" + integrity sha512-eJ9VjLFNINArgRzLbQ11YlWry7dM93GEODkQBXTRfrSypksiO9qSGr4SHhWgxxP26p4FRSpzc/17+N+Egnnchg== dependencies: - semver "^5.5.0" - vscode-languageserver-protocol "^3.15.0-next.6" + semver "^6.3.0" + vscode-languageserver-protocol "^3.15.0-next.9" -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== +vscode-languageserver-protocol@^3.15.0-next.9: + version "3.15.0-next.9" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30" + integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g== dependencies: - vscode-jsonrpc "^4.1.0-next.2" - vscode-languageserver-types "^3.15.0-next.2" + vscode-jsonrpc "^5.0.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" -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.15.0-next.5: + version "3.15.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b" + integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw== vscode-nls@^4.1.1: version "4.1.1" diff --git a/extensions/html/test/colorize-fixtures/test.html b/extensions/html/test/colorize-fixtures/test.html index 295e0ce7df1..13fd84fbd06 100644 --- a/extensions/html/test/colorize-fixtures/test.html +++ b/extensions/html/test/colorize-fixtures/test.html @@ -34,7 +34,7 @@ }); diff --git a/extensions/html/test/colorize-results/test_html.json b/extensions/html/test/colorize-results/test_html.json index a31b6b2af48..970d4214a74 100644 --- a/extensions/html/test/colorize-results/test_html.json +++ b/extensions/html/test/colorize-results/test_html.json @@ -2431,7 +2431,7 @@ } }, { - "c": "octicon", + "c": "codicon", "t": "text.html.derivative meta.tag.inline.span.start.html meta.attribute.class.html string.unquoted.html", "r": { "dark_plus": "string: #CE9178", @@ -3189,4 +3189,4 @@ "hc_black": "punctuation.definition.tag: #808080" } } -] \ No newline at end of file +] diff --git a/extensions/image-preview/README.md b/extensions/image-preview/README.md index e8664c77a90..ccb5ac3954a 100644 --- a/extensions/image-preview/README.md +++ b/extensions/image-preview/README.md @@ -1,3 +1,17 @@ # Image Preview **Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. + +## Features + +This extension provides VS Code's built-in image preview functionality. + +Supported image formats: + +- `*.jpg`, `*.jpe`, `*.jpeg` +- `*.png` +- `*.bmp` +- `*.gif` +- `*.ico` +- `*.tga` +- `*.webp` diff --git a/src/vs/base/parts/tree/browser/loading-dark.svg b/extensions/image-preview/media/loading-dark.svg similarity index 100% rename from src/vs/base/parts/tree/browser/loading-dark.svg rename to extensions/image-preview/media/loading-dark.svg diff --git a/src/vs/base/parts/tree/browser/loading-hc.svg b/extensions/image-preview/media/loading-hc.svg similarity index 100% rename from src/vs/base/parts/tree/browser/loading-hc.svg rename to extensions/image-preview/media/loading-hc.svg diff --git a/src/vs/base/parts/tree/browser/loading.svg b/extensions/image-preview/media/loading.svg similarity index 100% rename from src/vs/base/parts/tree/browser/loading.svg rename to extensions/image-preview/media/loading.svg diff --git a/extensions/image-preview/media/main.css b/extensions/image-preview/media/main.css index e2779bca0d1..ff3e6d0f0d2 100644 --- a/extensions/image-preview/media/main.css +++ b/extensions/image-preview/media/main.css @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ html, body { + width: 100%; height: 100%; - max-height: 100%; + text-align: center; } - body img { max-width: none; max-height: none; @@ -21,6 +21,7 @@ body img { .container { padding: 5px 0 0 10px; box-sizing: border-box; + -webkit-user-select: none; user-select: none; } @@ -34,6 +35,7 @@ body img { padding: 0; background-position: 0 0, 8px 8px; background-size: 16px 16px; + border: 1px solid var(--vscode-imagePreview-border); } .container.image img { @@ -62,11 +64,11 @@ body img { margin: auto; } -.container.zoom-in { +.container.ready.zoom-in { cursor: zoom-in; } -.container.zoom-out { +.container.ready.zoom-out { cursor: zoom-out; } @@ -76,3 +78,39 @@ body img { text-decoration: underline; margin-left: 5px; } + +.container.loading, +.container.error { + display: flex; + justify-content: center; + align-items: center; +} + +.loading-indicator { + width: 30px; + height: 30px; + background-image: url('./loading.svg'); + background-size: cover; +} + +.loading-indicator, +.image-load-error-message { + display: none; +} + +.loading .loading-indicator, +.error .image-load-error-message { + display: block; +} + +.image-load-error-message { + margin: 1em; +} + +.vscode-dark .loading-indicator { + background-image: url('./loading-dark.svg'); +} + +.vscode-high-contrast .loading-indicator { + background-image: url('./loading-hc.svg'); +} diff --git a/extensions/image-preview/media/main.js b/extensions/image-preview/media/main.js index 81f2da7401e..94364c28503 100644 --- a/extensions/image-preview/media/main.js +++ b/extensions/image-preview/media/main.js @@ -69,13 +69,15 @@ let scale = initialState.scale; let ctrlPressed = false; let altPressed = false; + let hasLoadedImage = false; + let consumeClick = false; // Elements - const container = /** @type {HTMLElement} */(document.querySelector('body')); + const container = document.body; const image = document.createElement('img'); function updateScale(newScale) { - if (!image || !image.parentElement) { + if (!image || !hasLoadedImage || !image.parentElement) { return; } @@ -87,9 +89,6 @@ image.style.width = 'auto'; vscode.setState(undefined); } else { - const oldWidth = image.width; - const oldHeight = image.height; - scale = clamp(newScale, MIN_SCALE, MAX_SCALE); if (scale >= PIXELATION_THRESHOLD) { image.classList.add('pixelated'); @@ -97,25 +96,19 @@ image.classList.remove('pixelated'); } - const { scrollTop, scrollLeft } = image.parentElement; - const dx = (scrollLeft + image.parentElement.clientWidth / 2) / image.parentElement.scrollWidth; - const dy = (scrollTop + image.parentElement.clientHeight / 2) / image.parentElement.scrollHeight; + const dx = (window.scrollX + container.clientWidth / 2) / container.scrollWidth; + const dy = (window.scrollY + container.clientHeight / 2) / container.scrollHeight; image.classList.remove('scale-to-fit'); image.style.minWidth = `${(image.naturalWidth * scale)}px`; image.style.width = `${(image.naturalWidth * scale)}px`; - const newWidth = image.width; - const scaleFactor = (newWidth - oldWidth) / oldWidth; + const newScrollX = container.scrollWidth * dx - container.clientWidth / 2; + const newScrollY = container.scrollHeight * dy - container.clientHeight / 2; - const newScrollLeft = ((oldWidth * scaleFactor * dx) + scrollLeft); - const newScrollTop = ((oldHeight * scaleFactor * dy) + scrollTop); - // scrollbar.setScrollPosition({ - // scrollLeft: newScrollLeft, - // scrollTop: newScrollTop, - // }); + window.scrollTo(newScrollX, newScrollY); - vscode.setState({ scale: scale, offsetX: newScrollLeft, offsetY: newScrollTop }); + vscode.setState({ scale: scale, offsetX: newScrollX, offsetY: newScrollY }); } vscode.postMessage({ @@ -124,8 +117,20 @@ }); } + function changeActive(value) { + if (value) { + container.classList.add('zoom-in'); + consumeClick = true; + } else { + ctrlPressed = false; + altPressed = false; + container.classList.remove('zoom-out'); + container.classList.remove('zoom-in'); + } + } + function firstZoom() { - if (!image) { + if (!image || !hasLoadedImage) { return; } @@ -133,8 +138,36 @@ updateScale(scale); } + function zoomIn() { + if (scale === 'fit') { + firstZoom(); + } + + let i = 0; + for (; i < zoomLevels.length; ++i) { + if (zoomLevels[i] > scale) { + break; + } + } + updateScale(zoomLevels[i] || MAX_SCALE); + } + + function zoomOut() { + if (scale === 'fit') { + firstZoom(); + } + + let i = zoomLevels.length - 1; + for (; i >= 0; --i) { + if (zoomLevels[i] < scale) { + break; + } + } + updateScale(zoomLevels[i] || MIN_SCALE); + } + window.addEventListener('keydown', (/** @type {KeyboardEvent} */ e) => { - if (!image) { + if (!image || !hasLoadedImage) { return; } ctrlPressed = e.ctrlKey; @@ -147,7 +180,7 @@ }); window.addEventListener('keyup', (/** @type {KeyboardEvent} */ e) => { - if (!image) { + if (!image || !hasLoadedImage) { return; } @@ -160,8 +193,8 @@ } }); - container.addEventListener('click', (/** @type {MouseEvent} */ e) => { - if (!image) { + container.addEventListener('mousedown', (/** @type {MouseEvent} */ e) => { + if (!image || !hasLoadedImage) { return; } @@ -169,32 +202,45 @@ return; } + consumeClick = false; + }); + + container.addEventListener('click', (/** @type {MouseEvent} */ e) => { + if (!image || !hasLoadedImage) { + return; + } + + if (e.button !== 0) { + return; + } + + ctrlPressed = e.ctrlKey; + altPressed = e.altKey; + + if (isMac ? altPressed : ctrlPressed) { + container.classList.remove('zoom-in'); + container.classList.add('zoom-out'); + } + + if (consumeClick) { + consumeClick = false; + return; + } // left click if (scale === 'fit') { firstZoom(); } if (!(isMac ? altPressed : ctrlPressed)) { // zoom in - let i = 0; - for (; i < zoomLevels.length; ++i) { - if (zoomLevels[i] > scale) { - break; - } - } - updateScale(zoomLevels[i] || MAX_SCALE); + zoomIn(); } else { - let i = zoomLevels.length - 1; - for (; i >= 0; --i) { - if (zoomLevels[i] < scale) { - break; - } - } - updateScale(zoomLevels[i] || MIN_SCALE); + zoomOut(); } }); container.addEventListener('wheel', (/** @type {WheelEvent} */ e) => { - if (!image) { + e.preventDefault(); + if (!image || !hasLoadedImage) { return; } @@ -203,19 +249,18 @@ return; } - e.preventDefault(); - e.stopPropagation(); - if (scale === 'fit') { firstZoom(); } let delta = e.deltaY > 0 ? 1 : -1; updateScale(scale * (1 - delta * SCALE_PINCH_FACTOR)); - }); + }, { passive: false }); - window.addEventListener('scroll', () => { - if (!image || !image.parentElement || scale === 'fit') { + window.addEventListener('scroll', e => { + e.preventDefault(); + + if (!image || !hasLoadedImage || !image.parentElement || scale === 'fit') { return; } @@ -223,25 +268,24 @@ if (entry) { vscode.setState({ scale: entry.scale, offsetX: window.scrollX, offsetY: window.scrollY }); } - }); + }, { passive: false }); container.classList.add('image'); - container.classList.add('zoom-in'); image.classList.add('scale-to-fit'); - image.style.visibility = 'hidden'; image.addEventListener('load', () => { - if (!image) { - return; - } + hasLoadedImage = true; vscode.postMessage({ type: 'size', value: `${image.naturalWidth}x${image.naturalHeight}`, }); - image.style.visibility = 'visible'; + document.body.classList.remove('loading'); + document.body.classList.add('ready'); + document.body.append(image); + updateScale(scale); if (initialState.scale !== 'fit') { @@ -249,14 +293,31 @@ } }); + image.addEventListener('error', () => { + hasLoadedImage = true; + document.body.classList.add('error'); + document.body.classList.remove('loading'); + }); + image.src = decodeURI(settings.src); - document.body.append(image); window.addEventListener('message', e => { switch (e.data.type) { case 'setScale': updateScale(e.data.scale); break; + + case 'setActive': + changeActive(e.data.value); + break; + + case 'zoomIn': + zoomIn(); + break; + + case 'zoomOut': + zoomOut(); + break; } }); }()); diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index b7f2aeb6b8e..c6149de85de 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -2,6 +2,7 @@ "name": "image-preview", "displayName": "%displayName%", "description": "%description%", + "extensionKind": "ui", "version": "1.0.0", "publisher": "vscode", "icon": "icon.png", @@ -16,21 +17,50 @@ "Other" ], "activationEvents": [ - "onWebviewEditor:imagePreview.previewEditor" + "onWebviewEditor:imagePreview.previewEditor", + "onCommand:imagePreview.zoomIn", + "onCommand:imagePreview.zoomOut" ], "contributes": { "webviewEditors": [ { "viewType": "imagePreview.previewEditor", "displayName": "%webviewEditors.displayName%", + "priority": "builtin", "selector": [ { - "filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,tga,tif,tiff,webp}", + "filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,tga,webp}", "mime": "image/*" } ] } - ] + ], + "commands": [ + { + "command": "imagePreview.zoomIn", + "title": "%command.zoomIn%", + "category": "Image Preview" + }, + { + "command": "imagePreview.zoomOut", + "title": "%command.zoomOut%", + "category": "Image Preview" + } + ], + "menus": { + "commandPalette": [ + { + "command": "imagePreview.zoomIn", + "when": "imagePreviewFocus", + "group": "1_imagePreview" + }, + { + "command": "imagePreview.zoomOut", + "when": "imagePreviewFocus", + "group": "1_imagePreview" + } + ] + } }, "scripts": { "compile": "gulp compile-extension:image-preview", diff --git a/extensions/image-preview/package.nls.json b/extensions/image-preview/package.nls.json index 78c753d1d54..304b1df9a3d 100644 --- a/extensions/image-preview/package.nls.json +++ b/extensions/image-preview/package.nls.json @@ -1,5 +1,7 @@ { "displayName": "Image Preview", - "description": "Previews images.", - "webviewEditors.displayName": "Image Preview" + "description": "Provides VS Code's built-in image preview", + "webviewEditors.displayName": "Image Preview", + "command.zoomIn": "Zoom in", + "command.zoomOut": "Zoom out" } diff --git a/extensions/image-preview/src/extension.ts b/extensions/image-preview/src/extension.ts index a47e4cb8bc7..cd68edf2e5c 100644 --- a/extensions/image-preview/src/extension.ts +++ b/extensions/image-preview/src/extension.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { Preview } from './preview'; +import { PreviewManager } from './preview'; import { SizeStatusBarEntry } from './sizeStatusBarEntry'; import { ZoomStatusBarEntry } from './zoomStatusBarEntry'; @@ -17,12 +17,23 @@ export function activate(context: vscode.ExtensionContext) { const zoomStatusBarEntry = new ZoomStatusBarEntry(); context.subscriptions.push(zoomStatusBarEntry); + const previewManager = new PreviewManager(extensionRoot, sizeStatusBarEntry, zoomStatusBarEntry); + context.subscriptions.push(vscode.window.registerWebviewEditorProvider( - Preview.viewType, + PreviewManager.viewType, { - async resolveWebviewEditor(resource: vscode.Uri, editor: vscode.WebviewEditor): Promise { - // tslint:disable-next-line: no-unused-expression - new Preview(extensionRoot, resource, editor, sizeStatusBarEntry, zoomStatusBarEntry); + async resolveWebviewEditor({ resource }, editor: vscode.WebviewPanel): Promise { + previewManager.resolve(resource, editor); + return {}; } })); -} \ No newline at end of file + + context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => { + previewManager.activePreview?.zoomIn(); + })); + + context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomOut', () => { + previewManager.activePreview?.zoomOut(); + })); +} + diff --git a/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/preview.ts index f9d4885e85a..b678daf6436 100644 --- a/extensions/image-preview/src/preview.ts +++ b/extensions/image-preview/src/preview.ts @@ -4,20 +4,76 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { SizeStatusBarEntry } from './sizeStatusBarEntry'; -import { ZoomStatusBarEntry } from './zoomStatusBarEntry'; +import * as nls from 'vscode-nls'; import { Disposable } from './dispose'; +import { SizeStatusBarEntry } from './sizeStatusBarEntry'; +import { Scale, ZoomStatusBarEntry } from './zoomStatusBarEntry'; -export class Preview extends Disposable { +const localize = nls.loadMessageBundle(); + + +export class PreviewManager { public static readonly viewType = 'imagePreview.previewEditor'; - private _active = true; + private readonly _previews = new Set(); + private _activePreview: Preview | undefined; constructor( private readonly extensionRoot: vscode.Uri, + private readonly sizeStatusBarEntry: SizeStatusBarEntry, + private readonly zoomStatusBarEntry: ZoomStatusBarEntry, + ) { } + + public resolve( resource: vscode.Uri, - private readonly webviewEditor: vscode.WebviewEditor, + webviewEditor: vscode.WebviewPanel, + ) { + const preview = new Preview(this.extensionRoot, resource, webviewEditor, this.sizeStatusBarEntry, this.zoomStatusBarEntry); + this._previews.add(preview); + this.setActivePreview(preview); + + webviewEditor.onDidDispose(() => { this._previews.delete(preview); }); + + webviewEditor.onDidChangeViewState(() => { + if (webviewEditor.active) { + this.setActivePreview(preview); + } else if (this._activePreview === preview && !webviewEditor.active) { + this.setActivePreview(undefined); + } + }); + } + + public get activePreview() { return this._activePreview; } + + private setActivePreview(value: Preview | undefined): void { + this._activePreview = value; + this.setPreviewActiveContext(!!value); + } + + private setPreviewActiveContext(value: boolean) { + vscode.commands.executeCommand('setContext', 'imagePreviewFocus', value); + } +} + +const enum PreviewState { + Disposed, + Visible, + Active, +} + +class Preview extends Disposable { + + private readonly id: string = `${Date.now()}-${Math.random().toString()}`; + + private _previewState = PreviewState.Visible; + private _imageSize: string | undefined; + private _imageZoom: Scale | undefined; + + constructor( + private readonly extensionRoot: vscode.Uri, + private readonly resource: vscode.Uri, + private readonly webviewEditor: vscode.WebviewPanel, private readonly sizeStatusBarEntry: SizeStatusBarEntry, private readonly zoomStatusBarEntry: ZoomStatusBarEntry, ) { @@ -34,56 +90,103 @@ export class Preview extends Disposable { ] }; - webviewEditor.webview.html = this.getWebiewContents(webviewEditor, resource); - this._register(webviewEditor.webview.onDidReceiveMessage(message => { switch (message.type) { case 'size': { - this.sizeStatusBarEntry.update(message.value); + this._imageSize = message.value; + this.update(); break; } case 'zoom': { - this.zoomStatusBarEntry.update(message.value); + this._imageZoom = message.value; + this.update(); break; } } })); this._register(zoomStatusBarEntry.onDidChangeScale(e => { - this.webviewEditor.webview.postMessage({ type: 'setScale', scale: e.scale }); + if (this._previewState === PreviewState.Active) { + this.webviewEditor.webview.postMessage({ type: 'setScale', scale: e.scale }); + } })); this._register(webviewEditor.onDidChangeViewState(() => { this.update(); })); + this._register(webviewEditor.onDidDispose(() => { - if (this._active) { - this.sizeStatusBarEntry.hide(); - this.zoomStatusBarEntry.hide(); + if (this._previewState === PreviewState.Active) { + this.sizeStatusBarEntry.hide(this.id); + this.zoomStatusBarEntry.hide(this.id); + } + this._previewState = PreviewState.Disposed; + })); + + const watcher = this._register(vscode.workspace.createFileSystemWatcher(resource.fsPath)); + this._register(watcher.onDidChange(e => { + if (e.toString() === this.resource.toString()) { + this.render(); } })); + this._register(watcher.onDidDelete(e => { + if (e.toString() === this.resource.toString()) { + this.webviewEditor.dispose(); + } + })); + + this.render(); this.update(); } - private update() { - this._active = this.webviewEditor.active; - if (this._active) { - this.sizeStatusBarEntry.show(); - this.zoomStatusBarEntry.show(); - } else { - this.sizeStatusBarEntry.hide(); - this.zoomStatusBarEntry.hide(); + public zoomIn() { + if (this._previewState === PreviewState.Active) { + this.webviewEditor.webview.postMessage({ type: 'zoomIn' }); } } - private getWebiewContents(webviewEditor: vscode.WebviewEditor, resource: vscode.Uri): string { + public zoomOut() { + if (this._previewState === PreviewState.Active) { + this.webviewEditor.webview.postMessage({ type: 'zoomOut' }); + } + } + + private render() { + if (this._previewState !== PreviewState.Disposed) { + this.webviewEditor.webview.html = this.getWebiewContents(); + } + } + + private update() { + if (this._previewState === PreviewState.Disposed) { + return; + } + + if (this.webviewEditor.active) { + this._previewState = PreviewState.Active; + this.sizeStatusBarEntry.show(this.id, this._imageSize || ''); + this.zoomStatusBarEntry.show(this.id, this._imageZoom || 'fit'); + } else { + if (this._previewState === PreviewState.Active) { + this.sizeStatusBarEntry.hide(this.id); + this.zoomStatusBarEntry.hide(this.id); + } + this._previewState = PreviewState.Visible; + } + this.webviewEditor.webview.postMessage({ type: 'setActive', value: this.webviewEditor.active }); + } + + private getWebiewContents(): string { + const version = Date.now().toString(); const settings = { isMac: process.platform === 'darwin', - src: this.getResourcePath(webviewEditor, resource) + src: this.getResourcePath(this.webviewEditor, this.resource, version), }; + const nonce = Date.now().toString(); + return /* html */` @@ -91,22 +194,33 @@ export class Preview extends Disposable { Image Preview - + + + - - + +
+
${localize('preview.imageLoadError', "An error occurred while loading the image")}
+ `; } - private getResourcePath(webviewEditor: vscode.WebviewEditor, resource: vscode.Uri) { - if (resource.scheme === 'data') { - return encodeURI(resource.toString(true)); - } + private getResourcePath(webviewEditor: vscode.WebviewPanel, resource: vscode.Uri, version: string) { + switch (resource.scheme) { + case 'data': + return encodeURI(resource.toString(true)); - return encodeURI(webviewEditor.webview.asWebviewUri(resource).toString(true)); + case 'git': + // Show blank image + return encodeURI('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAEElEQVR42gEFAPr/AP///wAI/AL+Sr4t6gAAAABJRU5ErkJggg=='); + + + default: + return encodeURI(webviewEditor.webview.asWebviewUri(resource).toString(true) + `?version=${version}`); + } } private extensionResource(path: string) { diff --git a/extensions/image-preview/src/sizeStatusBarEntry.ts b/extensions/image-preview/src/sizeStatusBarEntry.ts index 88f75f0cfd6..6b2bff746cf 100644 --- a/extensions/image-preview/src/sizeStatusBarEntry.ts +++ b/extensions/image-preview/src/sizeStatusBarEntry.ts @@ -5,29 +5,35 @@ import * as vscode from 'vscode'; import { Disposable } from './dispose'; +import * as nls from 'vscode-nls'; + +const localize = nls.loadMessageBundle(); export class SizeStatusBarEntry extends Disposable { private readonly _entry: vscode.StatusBarItem; + private _showingOwner: string | undefined; + constructor() { super(); this._entry = this._register(vscode.window.createStatusBarItem({ id: 'imagePreview.size', - name: 'Image Size', + name: localize('sizeStatusBar.name', "Image Size"), alignment: vscode.StatusBarAlignment.Right, priority: 101 /* to the left of editor status (100) */, })); } - public show() { + public show(owner: string, text: string) { + this._showingOwner = owner; + this._entry.text = text; this._entry.show(); } - public hide() { - this._entry.hide(); + public hide(owner: string) { + if (owner === this._showingOwner) { + this._entry.hide(); + this._showingOwner = undefined; + } } - - public update(text: string) { - this._entry.text = text; - } -} \ No newline at end of file +} diff --git a/extensions/image-preview/src/zoomStatusBarEntry.ts b/extensions/image-preview/src/zoomStatusBarEntry.ts index 11580b84299..dc102a48d64 100644 --- a/extensions/image-preview/src/zoomStatusBarEntry.ts +++ b/extensions/image-preview/src/zoomStatusBarEntry.ts @@ -11,7 +11,7 @@ const localize = nls.loadMessageBundle(); const selectZoomLevelCommandId = '_imagePreview.selectZoomLevel'; -type Scale = number | 'fit'; +export type Scale = number | 'fit'; export class ZoomStatusBarEntry extends Disposable { private readonly _entry: vscode.StatusBarItem; @@ -19,11 +19,13 @@ export class ZoomStatusBarEntry extends Disposable { private readonly _onDidChangeScale = this._register(new vscode.EventEmitter<{ scale: Scale }>()); public readonly onDidChangeScale = this._onDidChangeScale.event; + private _showOwner: string | undefined; + constructor() { super(); this._entry = this._register(vscode.window.createStatusBarItem({ id: 'imagePreview.zoom', - name: 'Image Zoom', + name: localize('zoomStatusBar.name', "Image Zoom"), alignment: vscode.StatusBarAlignment.Right, priority: 102 /* to the left of editor size entry (101) */, })); @@ -48,16 +50,17 @@ export class ZoomStatusBarEntry extends Disposable { this._entry.command = selectZoomLevelCommandId; } - public show() { + public show(owner: string, scale: Scale) { + this._showOwner = owner; + this._entry.text = this.zoomLabel(scale); this._entry.show(); } - public hide() { - this._entry.hide(); - } - - public update(scale: Scale) { - this._entry.text = this.zoomLabel(scale); + public hide(owner: string) { + if (owner === this._showOwner) { + this._entry.hide(); + this._showOwner = undefined; + } } private zoomLabel(scale: Scale): string { @@ -65,4 +68,4 @@ export class ZoomStatusBarEntry extends Disposable { ? localize('zoomStatusBar.wholeImageLabel', "Whole Image") : `${Math.round(scale * 100)}%`; } -} \ No newline at end of file +} diff --git a/extensions/jake/package.json b/extensions/jake/package.json index 1b1af72106b..e919813a216 100644 --- a/extensions/jake/package.json +++ b/extensions/jake/package.json @@ -20,7 +20,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" }, "main": "./out/main", "activationEvents": [ diff --git a/extensions/jake/yarn.lock b/extensions/jake/yarn.lock index e6247e29255..7af62a72ce7 100644 --- a/extensions/jake/yarn.lock +++ b/extensions/jake/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/java/cgmanifest.json b/extensions/java/cgmanifest.json index 0bf644ce0cf..762917e9802 100644 --- a/extensions/java/cgmanifest.json +++ b/extensions/java/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "atom/language-java", "repositoryUrl": "https://github.com/atom/language-java", - "commitHash": "ed8ad7451b4d0454374885a102dbe63befdea509" + "commitHash": "123beb50115b0bfb0db8f2325df6d05fb8a016a8" } }, "license": "MIT", diff --git a/extensions/java/syntaxes/java.tmLanguage.json b/extensions/java/syntaxes/java.tmLanguage.json index 76044a9cc7d..f806edf7b6d 100644 --- a/extensions/java/syntaxes/java.tmLanguage.json +++ b/extensions/java/syntaxes/java.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-java/commit/ed8ad7451b4d0454374885a102dbe63befdea509", + "version": "https://github.com/atom/language-java/commit/123beb50115b0bfb0db8f2325df6d05fb8a016a8", "name": "Java", "scopeName": "source.java", "patterns": [ @@ -582,7 +582,7 @@ } }, { - "match": "{(@link)\\s+(\\S+)?#([\\w$]+\\s*\\([^\\(\\)]*\\)).*}", + "match": "{(@link)\\s+(\\S+)?#([\\w$]+\\s*\\([^\\(\\)]*\\)).*?}", "captures": { "1": { "name": "keyword.other.documentation.javadoc.java" diff --git a/extensions/javascript/package.json b/extensions/javascript/package.json index 6909de1400f..8d315c45835 100644 --- a/extensions/javascript/package.json +++ b/extensions/javascript/package.json @@ -98,36 +98,6 @@ "language": "javascriptreact", "path": "./snippets/javascript.json" } - ], - "jsonValidation": [ - { - "fileMatch": ".bowerrc", - "url": "https://schemastore.azurewebsites.net/schemas/json/bowerrc.json" - }, - { - "fileMatch": ".babelrc", - "url": "https://schemastore.azurewebsites.net/schemas/json/babelrc.json" - }, - { - "fileMatch": ".babelrc.json", - "url": "https://schemastore.azurewebsites.net/schemas/json/babelrc.json" - }, - { - "fileMatch": "jsconfig.json", - "url": "https://schemastore.azurewebsites.net/schemas/json/jsconfig.json" - }, - { - "fileMatch": "jsconfig.json", - "url": "./schemas/jsconfig.schema.json" - }, - { - "fileMatch": "jsconfig.*.json", - "url": "https://schemastore.azurewebsites.net/schemas/json/jsconfig.json" - }, - { - "fileMatch": "jsconfig.*.json", - "url": "./schemas/jsconfig.schema.json" - } ] } -} \ No newline at end of file +} diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 64493d1483f..47894898ab3 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/ce3979047399920f77d79272b3af45b4d86006ac", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/477c1b17e273b64af13040c064c9ed62c8b32fba", "name": "JavaScript (with React support)", "scopeName": "source.js", "patterns": [ @@ -426,7 +426,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.js", - "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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js entity.name.function.js" @@ -484,7 +484,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.js", - "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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js variable.other.constant.js entity.name.function.js" @@ -868,7 +868,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*([_$[: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)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js" @@ -1081,7 +1081,7 @@ }, "field-declaration": { "name": "meta.field.declaration.js", - "begin": "(?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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "meta.definition.property.js entity.name.function.js" @@ -2059,6 +2059,9 @@ }, "end": "(?=;|$|^)", "patterns": [ + { + "include": "#single-line-comment-consuming-line-ending" + }, { "include": "#comment" }, @@ -2100,6 +2103,9 @@ }, "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*([_$[: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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.js" @@ -2695,7 +2701,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -2728,7 +2734,7 @@ ] }, { - "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -2782,13 +2788,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "end": "(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", "patterns": [ { "name": "meta.function-call.js", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "end": "(?=\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", "patterns": [ { "include": "#support-function-call-identifiers" @@ -2806,6 +2812,10 @@ "name": "meta.function-call.js punctuation.accessor.optional.js", "match": "\\?\\." }, + { + "name": "meta.function-call.js keyword.operator.definiteassignment.js", + "match": "\\!" + }, { "include": "#type-arguments" }, @@ -2872,7 +2882,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.js" @@ -2956,7 +2966,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*([_$[: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)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js" @@ -3558,7 +3568,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*([_$[: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))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.js" @@ -4071,7 +4081,7 @@ }, "patterns": [ { - "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))))", + "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))", "captures": { "1": { "name": "storage.modifier.js" @@ -4271,8 +4281,47 @@ ] }, "type-predicate-operator": { - "name": "keyword.operator.expression.is.js", - "match": "(?)\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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js.jsx entity.name.function.js.jsx" @@ -484,7 +484,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.js.jsx", - "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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js.jsx variable.other.constant.js.jsx entity.name.function.js.jsx" @@ -868,7 +868,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*([_$[: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)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js.jsx" @@ -1081,7 +1081,7 @@ }, "field-declaration": { "name": "meta.field.declaration.js.jsx", - "begin": "(?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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "meta.definition.property.js.jsx entity.name.function.js.jsx" @@ -2059,6 +2059,9 @@ }, "end": "(?=;|$|^)", "patterns": [ + { + "include": "#single-line-comment-consuming-line-ending" + }, { "include": "#comment" }, @@ -2100,6 +2103,9 @@ }, "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*([_$[: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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.js.jsx" @@ -2695,7 +2701,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -2728,7 +2734,7 @@ ] }, { - "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -2782,13 +2788,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "end": "(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", "patterns": [ { "name": "meta.function-call.js.jsx", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "end": "(?=\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", "patterns": [ { "include": "#support-function-call-identifiers" @@ -2806,6 +2812,10 @@ "name": "meta.function-call.js.jsx punctuation.accessor.optional.js.jsx", "match": "\\?\\." }, + { + "name": "meta.function-call.js.jsx keyword.operator.definiteassignment.js.jsx", + "match": "\\!" + }, { "include": "#type-arguments" }, @@ -2872,7 +2882,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.js.jsx" @@ -2956,7 +2966,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*([_$[: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)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.js.jsx" @@ -3558,7 +3568,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*([_$[: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))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.js.jsx" @@ -4071,7 +4081,7 @@ }, "patterns": [ { - "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))))", + "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))", "captures": { "1": { "name": "storage.modifier.js.jsx" @@ -4271,8 +4281,47 @@ ] }, "type-predicate-operator": { - "name": "keyword.operator.expression.is.js.jsx", - "match": "(? { - disposable = client.onTelemetry(e => { - if (telemetryReporter) { - telemetryReporter.sendTelemetryEvent(e.key, e.data); - } - }); - const schemaDocuments: { [uri: string]: boolean } = {}; // handle content request @@ -158,11 +156,23 @@ export function activate(context: ExtensionContext) { return Promise.reject(error); }); } else { + if (telemetryReporter && uri.authority === 'schema.management.azure.com') { + /* __GDPR__ + "json.schema" : { + "schemaURL" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + telemetryReporter.sendTelemetryEvent('json.schema', { schemaURL: uriPath }); + } const headers = { 'Accept-Encoding': 'gzip, deflate' }; return xhr({ url: uriPath, followRedirects: 5, headers }).then(response => { return response.responseText; }, (error: XHRResponse) => { - return Promise.reject(new ResponseError(error.status, error.responseText || getErrorStatusDescription(error.status) || error.toString())); + let extraInfo = error.responseText || error.toString(); + if (extraInfo.length > 256) { + extraInfo = `${extraInfo.substr(0, 256)}...`; + } + return Promise.reject(new ResponseError(error.status, getErrorStatusDescription(error.status) + '\n' + extraInfo)); }); } }); @@ -224,10 +234,13 @@ export function activate(context: ExtensionContext) { extensions.onDidChange(_ => { client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context)); }); + + // manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652. + updateFormatterRegistration(); + toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() }); + toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration('html.format.enable') && updateFormatterRegistration())); }); - - let languageConfiguration: LanguageConfiguration = { wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/, indentationRules: { @@ -237,8 +250,35 @@ export function activate(context: ExtensionContext) { }; languages.setLanguageConfiguration('json', languageConfiguration); languages.setLanguageConfiguration('jsonc', languageConfiguration); + + function updateFormatterRegistration() { + const formatEnabled = workspace.getConfiguration().get('json.format.enable'); + if (!formatEnabled && rangeFormatting) { + rangeFormatting.dispose(); + rangeFormatting = undefined; + } else if (formatEnabled && !rangeFormatting) { + rangeFormatting = languages.registerDocumentRangeFormattingEditProvider(documentSelector, { + provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult { + let params: DocumentRangeFormattingParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + range: client.code2ProtocolConverter.asRange(range), + options: client.code2ProtocolConverter.asFormattingOptions(options) + }; + return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then( + client.protocol2CodeConverter.asTextEdits, + (error) => { + client.logFailedRequest(DocumentRangeFormattingRequest.type, error); + return Promise.resolve([]); + } + ); + } + }); + } + } } + + export function deactivate(): Promise { return telemetryReporter ? telemetryReporter.dispose() : Promise.resolve(null); } @@ -286,8 +326,8 @@ function getSettings(): Settings { proxyStrictSSL: httpSettings.get('proxyStrictSSL') }, json: { - format: workspace.getConfiguration('json').get('format'), schemas: [], + resultLimit: 5000 } }; let schemaSettingsById: { [schemaId: string]: JSONSchemaSettings } = Object.create(null); diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 167583302c2..66c58578756 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -102,12 +102,12 @@ } }, "dependencies": { - "request-light": "^0.2.4", + "request-light": "^0.2.5", "vscode-extension-telemetry": "0.1.1", - "vscode-languageclient": "^5.3.0-next.6", + "vscode-languageclient": "^6.0.0-next.1", "vscode-nls": "^4.1.1" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" } } diff --git a/extensions/json-language-features/server/README.md b/extensions/json-language-features/server/README.md index 5ca997d9e12..71356e3c441 100644 --- a/extensions/json-language-features/server/README.md +++ b/extensions/json-language-features/server/README.md @@ -12,7 +12,7 @@ The JSON Language server provides language-specific smarts for editing, validati The JSON language server supports requests on documents of language id `json` and `jsonc`. - `json` documents are parsed and validated following the [JSON specification](https://tools.ietf.org/html/rfc7159). -- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`) and accepts trailing commas. JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format. +- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`). JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format. The server implements the following capabilities of the language server protocol: @@ -40,6 +40,13 @@ The JSON language server has the following dependencies on the client's capabili ## Configuration +### Initialization options + +The client can send the following initialization options to the server: + +- `provideFormatter: boolean | undefined`. If defined, the value defines whether the server provides the `documentRangeFormattingProvider` capability on initialization. If undefined, the setting `json.format.enable` is used to determine whether formatting is provided. The formatter will then be registered through dynamic registration. If the client does not support dynamic registration, no formatter will be available. +- `handledSchemaProtocols`: The URI schemas handles by the server. See section `Schema configuration` below. + ### Settings Clients may send a `workspace/didChangeConfiguration` notification to notify the server of settings changes. @@ -51,9 +58,9 @@ The server supports the following settings: - json - `format` - - `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* + - `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* and `initializationOptions.provideFormatter` is not defined. - `schema`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content. - - `fileMatch`: an array or file names or paths (separated by `/`). `*` can be used as a wildcard. + - `fileMatch`: an array of file names or paths (separated by `/`). `*` can be used as a wildcard. - `url`: The URL of the schema, optional when also a schema is provided. - `schema`: The schema content. @@ -92,9 +99,9 @@ To find the schema for a given JSON document, the server uses the following mech - The settings define a schema association based on the documents URL. Settings can either associate a schema URL to a file or path pattern, and they can directly provide a schema. - Additionally, schema associations can also be provided by a custom 'schemaAssociations' configuration call. -Schemas are identified by URLs. To load the content of a schema, the JSON language server either tries to load from that URI or path itself, or delegates to the client. +Schemas are identified by URLs. To load the content of a schema, the JSON language server either tries to load from that URI or path itself or delegates to the client. -The `initializationOptions.handledSchemaProtocols` initialization option defines which URLs are handled by the server. Requests for all other URIs are send to the client. +The `initializationOptions.handledSchemaProtocols` initialization option defines which URLs are handled by the server. Requests for all other URIs are sent to the client. `handledSchemaProtocols` is part of the initialization options and can't be changed while the server is running. @@ -114,7 +121,7 @@ If `handledSchemaProtocols` is not set, the JSON language server will load the f #### Schema content request -Requests for schemas with URLs not handled by the server are forwarded to the client through an LSP request. This request is a JSON language server specific, non-standardized, extension to the LSP. +Requests for schemas with URLs not handled by the server are forwarded to the client through an LSP request. This request is a JSON language server-specific, non-standardized, extension to the LSP. Request: - method: 'vscode/content' @@ -123,12 +130,12 @@ Request: #### Schema content change notification -When the client is aware that a schema content has changed, it will notify the server through a notification. This notification is a JSON language server specific, non-standardized, extension to the LSP. +When the client is aware that a schema content has changed, it will notify the server through a notification. This notification is a JSON language server-specific, non-standardized, extension to the LSP. The server will, as a response, clear the schema content from the cache and reload the schema content when required again. #### Schema associations notification -In addition to the settings, schemas associations can also be provided through a notification from the client to the server. This notification is a JSON language server specific, non-standardized, extension to the LSP. +In addition to the settings, schemas associations can also be provided through a notification from the client to the server. This notification is a JSON language server-specific, non-standardized, extension to the LSP. Notification: - method: 'json/schemaAssociations' diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 28c46483250..cd3a1b19e59 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -1,7 +1,7 @@ { "name": "vscode-json-languageserver", "description": "JSON language server", - "version": "1.2.1", + "version": "1.2.2", "author": "Microsoft Corporation", "license": "MIT", "engines": { @@ -12,16 +12,15 @@ }, "main": "./out/jsonServerMain", "dependencies": { - "jsonc-parser": "^2.1.1", - "request-light": "^0.2.4", - "vscode-json-languageservice": "^3.3.4", - "vscode-languageserver": "^5.3.0-next.8", - "vscode-nls": "^4.1.1", - "vscode-uri": "^2.0.3" + "jsonc-parser": "^2.2.0", + "request-light": "^0.2.5", + "vscode-json-languageservice": "^3.4.3", + "vscode-languageserver": "^6.0.0-next.1", + "vscode-uri": "^2.1.1" }, "devDependencies": { "@types/mocha": "2.2.33", - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" }, "scripts": { "prepublishOnly": "npm run clean && npm run compile", diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index c741c03e3ea..1c407fa1277 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -13,8 +13,10 @@ import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDes import * as fs from 'fs'; import { URI } from 'vscode-uri'; import * as URL from 'url'; +import { posix } from 'path'; +import { setTimeout, clearTimeout } from 'timers'; import { formatError, runSafe, runSafeAsync } from './utils/runner'; -import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration, ClientCapabilities } from 'vscode-json-languageservice'; +import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration, ClientCapabilities, SchemaRequestService } from 'vscode-json-languageservice'; import { getLanguageModelCache } from './languageModelCache'; interface ISchemaAssociations { @@ -56,40 +58,40 @@ const workspaceContext = { return URL.resolve(resource, relativePath); } }; -function getSchemaRequestService(handledSchemas: { [schema: string]: boolean }) { +const fileRequestService: SchemaRequestService = (uri: string) => { + const fsPath = URI.parse(uri).fsPath; + return new Promise((c, e) => { + fs.readFile(fsPath, 'UTF-8', (err, result) => { + err ? e(err.message || err.toString()) : c(result.toString()); + }); + }); +}; + +const httpRequestService: SchemaRequestService = (uri: string) => { + const headers = { 'Accept-Encoding': 'gzip, deflate' }; + return xhr({ url: uri, followRedirects: 5, headers }).then(response => { + return response.responseText; + }, (error: XHRResponse) => { + return Promise.reject(error.responseText || getErrorStatusDescription(error.status) || error.toString()); + }); +}; + +function getSchemaRequestService(handledSchemas: string[] = ['https', 'http', 'file']) { + const builtInHandlers: { [protocol: string]: SchemaRequestService } = {}; + for (let protocol of handledSchemas) { + if (protocol === 'file') { + builtInHandlers[protocol] = fileRequestService; + } else if (protocol === 'http' || protocol === 'https') { + builtInHandlers[protocol] = httpRequestService; + } + } return (uri: string): Thenable => { const protocol = uri.substr(0, uri.indexOf(':')); - if (!handledSchemas || handledSchemas[protocol]) { - if (protocol === 'file') { - const fsPath = URI.parse(uri).fsPath; - return new Promise((c, e) => { - fs.readFile(fsPath, 'UTF-8', (err, result) => { - err ? e(err.message || err.toString()) : c(result.toString()); - }); - }); - } else if (protocol === 'http' || protocol === 'https') { - if (uri.indexOf('//schema.management.azure.com/') !== -1) { - /* __GDPR__ - "json.schema" : { - "schemaURL" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - connection.telemetry.logEvent({ - key: 'json.schema', - value: { - schemaURL: uri - } - }); - } - const headers = { 'Accept-Encoding': 'gzip, deflate' }; - return xhr({ url: uri, followRedirects: 5, headers }).then(response => { - return response.responseText; - }, (error: XHRResponse) => { - return Promise.reject(error.responseText || getErrorStatusDescription(error.status) || error.toString()); - }); - } + const builtInHandler = builtInHandlers[protocol]; + if (builtInHandler) { + return builtInHandler(uri); } return connection.sendRequest(VSCodeContentRequest.type, uri).then(responseText => { return responseText; @@ -114,10 +116,13 @@ const documents: TextDocuments = new TextDocuments(); documents.listen(connection); let clientSnippetSupport = false; -let clientDynamicRegisterSupport = false; -let foldingRangeLimit = Number.MAX_VALUE; +let dynamicFormatterRegistration = false; let hierarchicalDocumentSymbolSupport = false; +let foldingRangeLimitDefault = Number.MAX_VALUE; +let foldingRangeLimit = Number.MAX_VALUE; +let resultLimit = Number.MAX_VALUE; + // 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 => { @@ -144,8 +149,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { } clientSnippetSupport = getClientCapability('textDocument.completion.completionItem.snippetSupport', false); - clientDynamicRegisterSupport = getClientCapability('workspace.symbol.dynamicRegistration', false); - foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); + dynamicFormatterRegistration = getClientCapability('textDocument.rangeFormatting.dynamicRegistration', false) && (typeof params.initializationOptions.provideFormatter !== 'boolean'); + foldingRangeLimitDefault = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); hierarchicalDocumentSymbolSupport = getClientCapability('textDocument.documentSymbol.hierarchicalDocumentSymbolSupport', false); const capabilities: ServerCapabilities = { // Tell the client that the server works in FULL text document sync mode @@ -153,7 +158,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: ['"', ':'] } : undefined, hoverProvider: true, documentSymbolProvider: true, - documentRangeFormattingProvider: false, + documentRangeFormattingProvider: params.initializationOptions.provideFormatter === true, colorProvider: {}, foldingRangeProvider: true, selectionRangeProvider: true @@ -169,6 +174,7 @@ interface Settings { json: { schemas: JSONSchemaSettings[]; format: { enable: boolean; }; + resultLimit?: number; }; http: { proxy: string; @@ -182,6 +188,39 @@ interface JSONSchemaSettings { schema?: JSONSchema; } +namespace LimitExceededWarnings { + const pendingWarnings: { [uri: string]: { features: { [name: string]: string }; timeout?: NodeJS.Timeout; } } = {}; + + export function cancel(uri: string) { + const warning = pendingWarnings[uri]; + if (warning && warning.timeout) { + clearTimeout(warning.timeout); + delete pendingWarnings[uri]; + } + } + + export function onResultLimitExceeded(uri: string, resultLimit: number, name: string) { + return () => { + let warning = pendingWarnings[uri]; + if (warning) { + if (!warning.timeout) { + // already shown + return; + } + warning.features[name] = name; + warning.timeout.refresh(); + } else { + warning = { features: { [name]: name } }; + warning.timeout = setTimeout(() => { + connection.window.showInformationMessage(`${posix.basename(uri)}: For performance reasons, ${Object.keys(warning.features).join(' and ')} have been limited to ${resultLimit} items.`); + warning.timeout = undefined; + }, 2000); + pendingWarnings[uri] = warning; + } + }; + } +} + let jsonConfigurationSettings: JSONSchemaSettings[] | undefined = undefined; let schemaAssociations: ISchemaAssociations | undefined = undefined; let formatterRegistration: Thenable | null = null; @@ -194,8 +233,11 @@ connection.onDidChangeConfiguration((change) => { jsonConfigurationSettings = settings.json && settings.json.schemas; updateConfiguration(); + foldingRangeLimit = Math.trunc(Math.max(settings.json && settings.json.resultLimit || foldingRangeLimitDefault, 0)); + resultLimit = Math.trunc(Math.max(settings.json && settings.json.resultLimit || Number.MAX_VALUE, 0)); + // dynamically enable & disable the formatter - if (clientDynamicRegisterSupport) { + if (dynamicFormatterRegistration) { const enableFormatter = settings && settings.json && settings.json.format && settings.json.format.enable; if (enableFormatter) { if (!formatterRegistration) { @@ -270,11 +312,13 @@ function updateConfiguration() { // The content of a text document has changed. This event is emitted // when the text document first opened or when its content has changed. documents.onDidChangeContent((change) => { + LimitExceededWarnings.cancel(change.document.uri); triggerValidation(change.document); }); // a document has closed: clear all diagnostics documents.onDidClose(event => { + LimitExceededWarnings.cancel(event.document.uri); cleanPendingValidation(event.document); connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] }); }); @@ -383,10 +427,11 @@ connection.onDocumentSymbol((documentSymbolParams, token) => { const document = documents.get(documentSymbolParams.textDocument.uri); if (document) { const jsonDocument = getJSONDocument(document); + const onResultLimitExceeded = LimitExceededWarnings.onResultLimitExceeded(document.uri, resultLimit, 'document symbols'); if (hierarchicalDocumentSymbolSupport) { - return languageService.findDocumentSymbols2(document, jsonDocument); + return languageService.findDocumentSymbols2(document, jsonDocument, { resultLimit, onResultLimitExceeded }); } else { - return languageService.findDocumentSymbols(document, jsonDocument); + return languageService.findDocumentSymbols(document, jsonDocument, { resultLimit, onResultLimitExceeded }); } } return []; @@ -407,8 +452,9 @@ connection.onDocumentColor((params, token) => { return runSafeAsync(async () => { const document = documents.get(params.textDocument.uri); if (document) { + const onResultLimitExceeded = LimitExceededWarnings.onResultLimitExceeded(document.uri, resultLimit, 'document colors'); const jsonDocument = getJSONDocument(document); - return languageService.findDocumentColors(document, jsonDocument); + return languageService.findDocumentColors(document, jsonDocument, { resultLimit, onResultLimitExceeded }); } return []; }, [], `Error while computing document colors for ${params.textDocument.uri}`, token); @@ -429,7 +475,8 @@ connection.onFoldingRanges((params, token) => { return runSafe(() => { const document = documents.get(params.textDocument.uri); if (document) { - return languageService.getFoldingRanges(document, { rangeLimit: foldingRangeLimit }); + const onRangeLimitExceeded = LimitExceededWarnings.onResultLimitExceeded(document.uri, foldingRangeLimit, 'folding ranges'); + return languageService.getFoldingRanges(document, { rangeLimit: foldingRangeLimit, onRangeLimitExceeded }); } return null; }, null, `Error while computing folding ranges for ${params.textDocument.uri}`, token); diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 8230b9546bc..43e1602f768 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -7,18 +7,25 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.33.tgz#d79a0061ec270379f4d9e225f4096fb436669def" integrity sha1-15oAYewnA3n02eIl9AlvtDZmne8= -"@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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== -agent-base@4, agent-base@^4.1.0: +agent-base@4: version "4.1.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.1.2.tgz#80fa6cde440f4dcf9af2617cf246099b5d99f0c8" integrity sha512-VE6QoEdaugY86BohRtfGmTDabxdU5sCKOkbcPA6PXKJsRzEi/7A3RCTxJal1ft/4qSfPht5/iQLhMh/wzSkkNw== dependencies: es6-promisify "^5.0.0" +agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + debug@3.1.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -46,74 +53,68 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -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== +https-proxy-agent@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== dependencies: - agent-base "^4.1.0" + agent-base "^4.3.0" debug "^3.1.0" -jsonc-parser@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.1.1.tgz#83dc3d7a6e7186346b889b1280eefa04446c6d3e" - integrity sha512-VC0CjnWJylKB1iov4u76/W/5Ef0ydDkjtYWxoZ9t3HdWlSnZQwZL5MgFikaB/EtQ4RmMEw3tmQzuYnZA2/Ja1g== +jsonc-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.0.tgz#f206f87f9d49d644b7502052c04e82dd6392e9ef" + integrity sha512-4fLQxW1j/5fWj6p78vAlAafoCKtuBm6ghv+Ij5W2DrDx0qE+ZdEl2c6Ko1mgJNF5ftX1iEWQQ4Ap7+3GlhjkOA== ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -request-light@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.4.tgz#3cea29c126682e6bcadf7915353322eeba01a755" - integrity sha512-pM9Fq5jRnSb+82V7M97rp8FE9/YNeP2L9eckB4Szd7lyeclSIx02aIpPO/6e4m6Dy31+FBN/zkFMTd2HkNO3ow== +request-light@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.5.tgz#38a3da7b2e56f7af8cbba57e8a94930ee2380746" + integrity sha512-eBEh+GzJAftUnex6tcL6eV2JCifY0+sZMIUpUPOVXbs2nV5hla4ZMmO3icYKGuGVuQ2zHE9evh4OrRcH4iyYYw== dependencies: http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" - vscode-nls "^4.0.0" - -vscode-json-languageservice@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.4.tgz#4ff67580491d3a5dc469f4a78643f20adff0278d" - integrity sha512-/nuI4uDBfxyVyeGtBdYwP/tIaXYKOoymUOSozYKLzsmrDmu555gZpzc11LrARa96z92wSaa5hfjTtNMAoM2mxw== - dependencies: - jsonc-parser "^2.1.1" - vscode-languageserver-types "^3.15.0-next.2" + https-proxy-agent "^2.2.3" 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== +vscode-json-languageservice@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.4.3.tgz#e0792619ec3f8730194c93ef74474d4429606cd6" + integrity sha512-SRIy75K4/6H1vmMYVsxYwynFUNMOEzIhTy+Pm6D24JHTquwMe7rx/35X75u2sw65e46ZP67izyrJ6ahaAi8UjQ== dependencies: - vscode-jsonrpc "^4.1.0-next.2" - vscode-languageserver-types "^3.15.0-next.2" + jsonc-parser "^2.2.0" + vscode-languageserver-types "^3.15.0-next.5" + vscode-nls "^4.1.1" + vscode-uri "^2.1.0" -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-jsonrpc@^5.0.0-next.2: + version "5.0.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca" + integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg== -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== +vscode-languageserver-protocol@^3.15.0-next.9: + version "3.15.0-next.9" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30" + integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g== dependencies: - vscode-languageserver-protocol "^3.15.0-next.6" + vscode-jsonrpc "^5.0.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" + +vscode-languageserver-types@^3.15.0-next.5: + version "3.15.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b" + integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw== + +vscode-languageserver@^6.0.0-next.1: + version "6.0.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-6.0.0-next.1.tgz#4d71886d4a17d22eafc61b3a5fbf84e8e27c191f" + integrity sha512-LSF6bXoFeXfMPRNyqzI3yFX/kD2DzXBemqvyj1kDWNVraiWttm4xKF4YXsvJ7Z3s9sVt/Dpu3CFU3w61PGNZMg== + dependencies: + vscode-languageserver-protocol "^3.15.0-next.9" 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" @@ -125,12 +126,12 @@ vscode-textbuffer@^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.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.0.tgz#475a4269e63edbc13914b40c84bc1416e3398156" + integrity sha512-3voe44nOhb6OdKlpZShVsmVvY2vFQHMe6REP3Ky9RVJuPyM/XidsjH6HncCIDdSmbcF5YQHrTC/Q+Q2loJGkOw== -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-uri@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.1.tgz#5aa1803391b6ebdd17d047f51365cf62c38f6e90" + integrity sha512-eY9jmGoEnVf8VE8xr5znSah7Qt1P/xsCdErz+g8HYZtJ7bZqKH5E3d+6oVNm1AC/c6IHUDokbmVXKOi4qPAC9A== diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index fdc89dd7cf1..b5064b13420 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -2,18 +2,25 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== -agent-base@4, agent-base@^4.1.0: +agent-base@4: 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" +agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + 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" @@ -69,12 +76,12 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -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== +https-proxy-agent@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== dependencies: - agent-base "^4.1.0" + agent-base "^4.3.0" debug "^3.1.0" ms@2.0.0: @@ -87,24 +94,24 @@ 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== -request-light@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.4.tgz#3cea29c126682e6bcadf7915353322eeba01a755" - integrity sha512-pM9Fq5jRnSb+82V7M97rp8FE9/YNeP2L9eckB4Szd7lyeclSIx02aIpPO/6e4m6Dy31+FBN/zkFMTd2HkNO3ow== +request-light@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.5.tgz#38a3da7b2e56f7af8cbba57e8a94930ee2380746" + integrity sha512-eBEh+GzJAftUnex6tcL6eV2JCifY0+sZMIUpUPOVXbs2nV5hla4ZMmO3icYKGuGVuQ2zHE9evh4OrRcH4iyYYw== dependencies: http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" - vscode-nls "^4.0.0" + https-proxy-agent "^2.2.3" + vscode-nls "^4.1.1" semver@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== -semver@^5.5.0: - version "5.5.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" - integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== vscode-extension-telemetry@0.1.1: version "0.1.1" @@ -113,36 +120,31 @@ vscode-extension-telemetry@0.1.1: dependencies: applicationinsights "1.0.8" -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-jsonrpc@^5.0.0-next.2: + version "5.0.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca" + integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg== -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== +vscode-languageclient@^6.0.0-next.1: + version "6.0.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-6.0.0-next.1.tgz#deca1743afd20da092e04e40ef73cedbbd978455" + integrity sha512-eJ9VjLFNINArgRzLbQ11YlWry7dM93GEODkQBXTRfrSypksiO9qSGr4SHhWgxxP26p4FRSpzc/17+N+Egnnchg== dependencies: - semver "^5.5.0" - vscode-languageserver-protocol "^3.15.0-next.6" + semver "^6.3.0" + vscode-languageserver-protocol "^3.15.0-next.9" -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== +vscode-languageserver-protocol@^3.15.0-next.9: + version "3.15.0-next.9" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30" + integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g== dependencies: - vscode-jsonrpc "^4.1.0-next.2" - vscode-languageserver-types "^3.15.0-next.2" + vscode-jsonrpc "^5.0.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" -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.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-languageserver-types@^3.15.0-next.5: + version "3.15.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b" + integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw== vscode-nls@^4.1.1: version "4.1.1" diff --git a/extensions/json/language-configuration.json b/extensions/json/language-configuration.json index 9a73ac64aae..7faa70cef7a 100644 --- a/extensions/json/language-configuration.json +++ b/extensions/json/language-configuration.json @@ -12,8 +12,7 @@ { "open": "[", "close": "]", "notIn": ["string"] }, { "open": "(", "close": ")", "notIn": ["string"] }, { "open": "'", "close": "'", "notIn": ["string"] }, - { "open": "/*", "close": "*/", "notIn": ["string"] }, { "open": "\"", "close": "\"", "notIn": ["string", "comment"] }, { "open": "`", "close": "`", "notIn": ["string", "comment"] } ] -} \ No newline at end of file +} diff --git a/extensions/json/package.json b/extensions/json/package.json index 6ef4b971691..e66955770bc 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -27,7 +27,8 @@ ".swcrc", ".webmanifest", ".js.map", - ".css.map" + ".css.map", + ".har" ], "filenames": [ "composer.lock", diff --git a/extensions/json/syntaxes/JSON.tmLanguage.json b/extensions/json/syntaxes/JSON.tmLanguage.json index d296aac33eb..910045be39e 100644 --- a/extensions/json/syntaxes/JSON.tmLanguage.json +++ b/extensions/json/syntaxes/JSON.tmLanguage.json @@ -5,7 +5,7 @@ "Once accepted there, we are happy to receive an update request." ], "version": "https://github.com/Microsoft/vscode-JSON.tmLanguage/commit/9bd83f1c252b375e957203f21793316203f61f70", - "name": "JSON (JavaScript Next)", + "name": "JSON (Javascript Next)", "scopeName": "source.json", "patterns": [ { @@ -210,4 +210,4 @@ ] } } -} +} \ No newline at end of file diff --git a/extensions/log/cgmanifest.json b/extensions/log/cgmanifest.json index f1704efec87..56318ba0e84 100644 --- a/extensions/log/cgmanifest.json +++ b/extensions/log/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "vscode-logfile-highlighter", "repositoryUrl": "https://github.com/emilast/vscode-logfile-highlighter", - "commitHash": "30a19d24b9a0070b0fab5eef45f89c92e7cd71ea" + "commitHash": "e90aa2554b439827f125fd60ff6d7773fc582fcc" } }, "license": "MIT", - "version": "2.4.1" + "version": "2.5.0" } ], "version": 1 diff --git a/extensions/log/syntaxes/log.tmLanguage.json b/extensions/log/syntaxes/log.tmLanguage.json index e2e5af634b1..b0f144a67fe 100644 --- a/extensions/log/syntaxes/log.tmLanguage.json +++ b/extensions/log/syntaxes/log.tmLanguage.json @@ -4,18 +4,34 @@ "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/emilast/vscode-logfile-highlighter/commit/30a19d24b9a0070b0fab5eef45f89c92e7cd71ea", + "version": "https://github.com/emilast/vscode-logfile-highlighter/commit/e90aa2554b439827f125fd60ff6d7773fc582fcc", "name": "Log file", "scopeName": "text.log", "patterns": [ { - "match": "\\b(DEBUG|Debug|Trace)\\b|(?i)\\b(debug)\\:", + "match": "\\b(Trace)\\b:", + "name": "comment log.verbose" + }, + { + "match": "(?i)\\[(verbose|verb|vrb|vb|v)\\]", + "name": "comment log.verbose" + }, + { + "match": "\\bV/", + "name": "comment log.verbose" + }, + { + "match": "\\b(DEBUG|Debug)\\b|(?i)\\b(debug)\\:", "name": "markup.changed log.debug" }, { "match": "(?i)\\[(debug|dbug|dbg|de|d)\\]", "name": "markup.changed log.debug" }, + { + "match": "\\bD/", + "name": "markup.changed log.debug" + }, { "match": "\\b(HINT|INFO|INFORMATION|Info|NOTICE)\\b|(?i)\\b(info|information)\\:", "name": "markup.inserted log.info" @@ -24,6 +40,10 @@ "match": "(?i)\\[(information|info|inf|in|i)\\]", "name": "markup.inserted log.info" }, + { + "match": "\\bI/", + "name": "markup.inserted log.info" + }, { "match": "\\b(WARNING|WARN|Warn)\\b|(?i)\\b(warning)\\:", "name": "markup.deleted log.warning" @@ -32,6 +52,10 @@ "match": "(?i)\\[(warning|warn|wrn|wn|w)\\]", "name": "markup.deleted log.warning" }, + { + "match": "\\bW/", + "name": "markup.deleted log.warning" + }, { "match": "\\b(ALERT|CRITICAL|EMERGENCY|ERROR|FAILURE|FAIL|Fatal|Error)\\b|(?i)\\b(error)\\:", "name": "string.regexp, strong log.error" @@ -40,6 +64,10 @@ "match": "(?i)\\[(error|eror|err|er|e|fatal|fatl|ftl|fa|f)\\]", "name": "string.regexp, strong log.error" }, + { + "match": "\\bE/", + "name": "string.regexp, strong log.error" + }, { "match": "\\b\\d{4}-\\d{2}-\\d{2}(T|\\b)", "name": "comment log.date" diff --git a/extensions/make/cgmanifest.json b/extensions/make/cgmanifest.json index 5407e8b07c6..544b0bc5bd3 100644 --- a/extensions/make/cgmanifest.json +++ b/extensions/make/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "fadeevab/make.tmbundle", "repositoryUrl": "https://github.com/fadeevab/make.tmbundle", - "commitHash": "fa280d2f20b0b63dc7c11b6001e9257e2c67f826" + "commitHash": "fd57c0552dbe5e4d0c1e6765daea4b296d9bfc59" } }, "licenseDetail": [ diff --git a/extensions/make/syntaxes/make.tmLanguage.json b/extensions/make/syntaxes/make.tmLanguage.json index fd184ee1d48..2503fce46fc 100644 --- a/extensions/make/syntaxes/make.tmLanguage.json +++ b/extensions/make/syntaxes/make.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/fadeevab/make.tmbundle/commit/fa280d2f20b0b63dc7c11b6001e9257e2c67f826", + "version": "https://github.com/fadeevab/make.tmbundle/commit/fd57c0552dbe5e4d0c1e6765daea4b296d9bfc59", "name": "Makefile", "scopeName": "source.makefile", "patterns": [ @@ -342,7 +342,7 @@ ] }, "variable-assignment": { - "begin": "(^[ ]*|\\G\\s*)([^\\s]+)\\s*((?) ?" }, "fenced_code_block_css": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(css|css.erb)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(css|css.erb)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -96,7 +96,7 @@ ] }, "fenced_code_block_basic": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(html|htm|shtml|xhtml|inc|tmpl|tpl)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(html|htm|shtml|xhtml|inc|tmpl|tpl)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -129,7 +129,7 @@ ] }, "fenced_code_block_ini": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ini|conf)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ini|conf)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -162,7 +162,7 @@ ] }, "fenced_code_block_java": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(java|bsh)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(java|bsh)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -195,7 +195,7 @@ ] }, "fenced_code_block_lua": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(lua)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(lua)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -228,7 +228,7 @@ ] }, "fenced_code_block_makefile": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(Makefile|makefile|GNUmakefile|OCamlMakefile)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(Makefile|makefile|GNUmakefile|OCamlMakefile)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -261,7 +261,7 @@ ] }, "fenced_code_block_perl": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl|pl|pm|pod|t|PL|psgi|vcl)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl|pl|pm|pod|t|PL|psgi|vcl)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -294,7 +294,7 @@ ] }, "fenced_code_block_r": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(R|r|s|S|Rprofile|\\{\\.r.+?\\})(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(R|r|s|S|Rprofile|\\{\\.r.+?\\})((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -327,7 +327,7 @@ ] }, "fenced_code_block_ruby": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ruby|rb|rbx|rjs|Rakefile|rake|cgi|fcgi|gemspec|irbrc|Capfile|ru|prawn|Cheffile|Gemfile|Guardfile|Hobofile|Vagrantfile|Appraisals|Rantfile|Berksfile|Berksfile.lock|Thorfile|Puppetfile)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ruby|rb|rbx|rjs|Rakefile|rake|cgi|fcgi|gemspec|irbrc|Capfile|ru|prawn|Cheffile|Gemfile|Guardfile|Hobofile|Vagrantfile|Appraisals|Rantfile|Berksfile|Berksfile.lock|Thorfile|Puppetfile)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -360,7 +360,7 @@ ] }, "fenced_code_block_php": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(php|php3|php4|php5|phpt|phtml|aw|ctp)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(php|php3|php4|php5|phpt|phtml|aw|ctp)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -396,7 +396,7 @@ ] }, "fenced_code_block_sql": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(sql|ddl|dml)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(sql|ddl|dml)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -429,7 +429,7 @@ ] }, "fenced_code_block_vs_net": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(vb)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(vb)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -462,7 +462,7 @@ ] }, "fenced_code_block_xml": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xml|xsd|tld|jsp|pt|cpt|dtml|rss|opml)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xml|xsd|tld|jsp|pt|cpt|dtml|rss|opml)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -495,7 +495,7 @@ ] }, "fenced_code_block_xsl": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xsl|xslt)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xsl|xslt)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -528,7 +528,7 @@ ] }, "fenced_code_block_yaml": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(yaml|yml)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(yaml|yml)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -561,7 +561,7 @@ ] }, "fenced_code_block_dosbatch": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(bat|batch)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(bat|batch)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -594,7 +594,7 @@ ] }, "fenced_code_block_clojure": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(clj|cljs|clojure)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(clj|cljs|clojure)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -627,7 +627,7 @@ ] }, "fenced_code_block_coffee": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(coffee|Cakefile|coffee.erb)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(coffee|Cakefile|coffee.erb)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -660,7 +660,7 @@ ] }, "fenced_code_block_c": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(c|h)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(c|h)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -693,7 +693,7 @@ ] }, "fenced_code_block_cpp": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cpp|c\\+\\+|cxx)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cpp|c\\+\\+|cxx)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -726,7 +726,7 @@ ] }, "fenced_code_block_diff": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(patch|diff|rej)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(patch|diff|rej)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -759,7 +759,7 @@ ] }, "fenced_code_block_dockerfile": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dockerfile|Dockerfile)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dockerfile|Dockerfile)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -792,7 +792,7 @@ ] }, "fenced_code_block_git_commit": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(COMMIT_EDITMSG|MERGE_MSG)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(COMMIT_EDITMSG|MERGE_MSG)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -825,7 +825,7 @@ ] }, "fenced_code_block_git_rebase": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(git-rebase-todo)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(git-rebase-todo)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -858,7 +858,7 @@ ] }, "fenced_code_block_go": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(go|golang)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(go|golang)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -891,7 +891,7 @@ ] }, "fenced_code_block_groovy": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(groovy|gvy)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(groovy|gvy)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -924,7 +924,7 @@ ] }, "fenced_code_block_pug": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jade|pug)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jade|pug)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -957,7 +957,7 @@ ] }, "fenced_code_block_js": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(js|jsx|javascript|es6|mjs|\\{\\.js.+?\\})(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(js|jsx|javascript|es6|mjs|\\{\\.js.+?\\})((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -990,7 +990,7 @@ ] }, "fenced_code_block_js_regexp": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(regexp)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(regexp)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1023,7 +1023,7 @@ ] }, "fenced_code_block_json": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(json|json5|sublime-settings|sublime-menu|sublime-keymap|sublime-mousemap|sublime-theme|sublime-build|sublime-project|sublime-completions)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(json|json5|sublime-settings|sublime-menu|sublime-keymap|sublime-mousemap|sublime-theme|sublime-build|sublime-project|sublime-completions)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1056,7 +1056,7 @@ ] }, "fenced_code_block_jsonc": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jsonc)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jsonc)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1089,7 +1089,7 @@ ] }, "fenced_code_block_less": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(less)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(less)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1122,7 +1122,7 @@ ] }, "fenced_code_block_objc": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(objectivec|objective-c|mm|objc|obj-c|m|h)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(objectivec|objective-c|mm|objc|obj-c|m|h)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1155,7 +1155,7 @@ ] }, "fenced_code_block_swift": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(swift)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(swift)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1188,7 +1188,7 @@ ] }, "fenced_code_block_scss": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scss)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scss)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1221,7 +1221,7 @@ ] }, "fenced_code_block_perl6": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl6|p6|pl6|pm6|nqp)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl6|p6|pl6|pm6|nqp)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1254,7 +1254,7 @@ ] }, "fenced_code_block_powershell": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(powershell|ps1|psm1|psd1)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(powershell|ps1|psm1|psd1)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1287,7 +1287,7 @@ ] }, "fenced_code_block_python": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(python|py|py3|rpy|pyw|cpy|SConstruct|Sconstruct|sconstruct|SConscript|gyp|gypi|\\{\\.python.+?\\})(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(python|py|py3|rpy|pyw|cpy|SConstruct|Sconstruct|sconstruct|SConscript|gyp|gypi|\\{\\.python.+?\\})((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1320,7 +1320,7 @@ ] }, "fenced_code_block_regexp_python": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(re)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(re)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1353,7 +1353,7 @@ ] }, "fenced_code_block_rust": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|rs|\\{\\.rust.+?\\})(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|rs|\\{\\.rust.+?\\})((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1386,7 +1386,7 @@ ] }, "fenced_code_block_scala": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scala|sbt)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scala|sbt)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1419,7 +1419,7 @@ ] }, "fenced_code_block_shell": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(shell|sh|bash|zsh|bashrc|bash_profile|bash_login|profile|bash_logout|.textmate_init|\\{\\.bash.+?\\})(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(shell|sh|bash|zsh|bashrc|bash_profile|bash_login|profile|bash_logout|.textmate_init|\\{\\.bash.+?\\})((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1452,7 +1452,7 @@ ] }, "fenced_code_block_ts": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(typescript|ts)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(typescript|ts)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1485,7 +1485,7 @@ ] }, "fenced_code_block_tsx": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(tsx)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(tsx)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1518,7 +1518,7 @@ ] }, "fenced_code_block_csharp": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cs|csharp|c#)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cs|csharp|c#)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1551,7 +1551,7 @@ ] }, "fenced_code_block_fsharp": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(fs|fsharp|f#)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(fs|fsharp|f#)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1584,7 +1584,7 @@ ] }, "fenced_code_block_dart": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dart)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dart)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1617,7 +1617,7 @@ ] }, "fenced_code_block_handlebars": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(handlebars|hbs)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(handlebars|hbs)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1650,7 +1650,7 @@ ] }, "fenced_code_block_markdown": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(markdown|md)(\\s+[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(markdown|md)((\\s+|:|\\{)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1682,6 +1682,39 @@ } ] }, + "fenced_code_block_log": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(log)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.log", + "patterns": [ + { + "include": "text.log" + } + ] + } + ] + }, "fenced_code_block": { "patterns": [ { @@ -1831,6 +1864,9 @@ { "include": "#fenced_code_block_markdown" }, + { + "include": "#fenced_code_block_log" + }, { "include": "#fenced_code_block_unknown" } diff --git a/extensions/markdown-language-features/media/highlight.css b/extensions/markdown-language-features/media/highlight.css index 112799d4662..47444a10348 100644 --- a/extensions/markdown-language-features/media/highlight.css +++ b/extensions/markdown-language-features/media/highlight.css @@ -123,26 +123,33 @@ Visual Studio-like style based on original C# coloring by Jason Diamond - * Build: `lodash modularize exports="npm" -o ./` - * Copyright jQuery Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ - -/** Used as the `TypeError` message for "Functions" methods. */ -var FUNC_ERROR_TEXT = 'Expected a function'; - -/** Used as references for various `Number` constants. */ -var NAN = 0 / 0; - -/** `Object#toString` result references. */ -var symbolTag = '[object Symbol]'; - -/** Used to match leading and trailing whitespace. */ -var reTrim = /^\s+|\s+$/g; - -/** Used to detect bad signed hexadecimal string values. */ -var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - -/** Used to detect binary string values. */ -var reIsBinary = /^0b[01]+$/i; - -/** Used to detect octal string values. */ -var reIsOctal = /^0o[0-7]+$/i; - -/** Built-in method references without a dependency on `root`. */ -var freeParseInt = parseInt; - -/** Detect free variable `global` from Node.js. */ -var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - -/** Detect free variable `self`. */ -var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - -/** Used as a reference to the global object. */ -var root = freeGlobal || freeSelf || Function('return this')(); - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var objectToString = objectProto.toString; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeMax = Math.max, - nativeMin = Math.min; - -/** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Date - * @returns {number} Returns the timestamp. - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. - */ -var now = function() { - return root.Date.now(); -}; - -/** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // Avoid costly calculations while the window size is in flux. - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); - * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); - */ -function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; - - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } - - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - result = wait - timeSinceLastCall; - - return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; - } - - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; - - // Either this is the first call, activity has stopped and we're at the - // trailing edge, the system time has gone backwards and we're treating - // it as the trailing edge, or we've hit the `maxWait` limit. - return (lastCallTime === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } - - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } - - function trailingEdge(time) { - timerId = undefined; - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } - - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; - } - - function flush() { - return timerId === undefined ? result : trailingEdge(now()); - } - - function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); - - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; -} - -/** - * Creates a throttled function that only invokes `func` at most once per - * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed `func` invocations and a `flush` method to - * immediately invoke them. Provide `options` to indicate whether `func` - * should be invoked on the leading and/or trailing edge of the `wait` - * timeout. The `func` is invoked with the last arguments provided to the - * throttled function. Subsequent calls to the throttled function return the - * result of the last `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the throttled function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=true] - * Specify invoking on the leading edge of the timeout. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // Avoid excessively updating the position while scrolling. - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. - * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); - * jQuery(element).on('click', throttled); - * - * // Cancel the trailing throttled invocation. - * jQuery(window).on('popstate', throttled.cancel); - */ -function throttle(func, wait, options) { - var leading = true, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - return debounce(func, wait, { - 'leading': leading, - 'maxWait': wait, - 'trailing': trailing - }); -} - -/** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ -function isObject(value) { - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); -} - -/** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ -function isObjectLike(value) { - return !!value && typeof value == 'object'; -} - -/** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ -function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && objectToString.call(value) == symbolTag); -} - -/** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ -function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); -} - -module.exports = throttle; - -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js"))) - -/***/ }), - -/***/ "./node_modules/webpack/buildin/global.js": -/*!***********************************!*\ - !*** (webpack)/buildin/global.js ***! - \***********************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1, eval)("this"); -} catch (e) { - // This works if the window reference is available - if (typeof window === "object") g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), - -/***/ "./preview-src/activeLineMarker.ts": -/*!*****************************************!*\ - !*** ./preview-src/activeLineMarker.ts ***! - \*****************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -const scroll_sync_1 = __webpack_require__(/*! ./scroll-sync */ "./preview-src/scroll-sync.ts"); -class ActiveLineMarker { - onDidChangeTextEditorSelection(line) { - const { previous } = scroll_sync_1.getElementsForSourceLine(line); - this._update(previous && previous.element); - } - _update(before) { - this._unmarkActiveElement(this._current); - this._markActiveElement(before); - this._current = before; - } - _unmarkActiveElement(element) { - if (!element) { - return; - } - element.className = element.className.replace(/\bcode-active-line\b/g, ''); - } - _markActiveElement(element) { - if (!element) { - return; - } - element.className += ' code-active-line'; - } -} -exports.ActiveLineMarker = ActiveLineMarker; - - -/***/ }), - -/***/ "./preview-src/events.ts": -/*!*******************************!*\ - !*** ./preview-src/events.ts ***! - \*******************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 }); -function onceDocumentLoaded(f) { - if (document.readyState === 'loading' || document.readyState === 'uninitialized') { - document.addEventListener('DOMContentLoaded', f); - } - else { - f(); - } -} -exports.onceDocumentLoaded = onceDocumentLoaded; - - -/***/ }), - -/***/ "./preview-src/index.ts": -/*!******************************!*\ - !*** ./preview-src/index.ts ***! - \******************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 activeLineMarker_1 = __webpack_require__(/*! ./activeLineMarker */ "./preview-src/activeLineMarker.ts"); -const events_1 = __webpack_require__(/*! ./events */ "./preview-src/events.ts"); -const messaging_1 = __webpack_require__(/*! ./messaging */ "./preview-src/messaging.ts"); -const scroll_sync_1 = __webpack_require__(/*! ./scroll-sync */ "./preview-src/scroll-sync.ts"); -const settings_1 = __webpack_require__(/*! ./settings */ "./preview-src/settings.ts"); -const throttle = __webpack_require__(/*! lodash.throttle */ "./node_modules/lodash.throttle/index.js"); -let scrollDisabled = true; -const marker = new activeLineMarker_1.ActiveLineMarker(); -const settings = settings_1.getSettings(); -const vscode = acquireVsCodeApi(); -// Set VS Code state -let state = settings_1.getData('data-state'); -vscode.setState(state); -const messaging = messaging_1.createPosterForVsCode(vscode); -window.cspAlerter.setPoster(messaging); -window.styleLoadingMonitor.setPoster(messaging); -window.onload = () => { - updateImageSizes(); -}; -events_1.onceDocumentLoaded(() => { - if (settings.scrollPreviewWithEditor) { - setTimeout(() => { - // Try to scroll to fragment if available - if (state.fragment) { - const element = scroll_sync_1.getLineElementForFragment(state.fragment); - if (element) { - scrollDisabled = true; - scroll_sync_1.scrollToRevealSourceLine(element.line); - } - } - else { - const initialLine = +settings.line; - if (!isNaN(initialLine)) { - scrollDisabled = true; - scroll_sync_1.scrollToRevealSourceLine(initialLine); - } - } - }, 0); - } -}); -const onUpdateView = (() => { - const doScroll = throttle((line) => { - scrollDisabled = true; - scroll_sync_1.scrollToRevealSourceLine(line); - }, 50); - return (line, settings) => { - if (!isNaN(line)) { - settings.line = line; - doScroll(line); - } - }; -})(); -let updateImageSizes = throttle(() => { - const imageInfo = []; - let images = document.getElementsByTagName('img'); - if (images) { - let i; - for (i = 0; i < images.length; i++) { - const img = images[i]; - if (img.classList.contains('loading')) { - img.classList.remove('loading'); - } - imageInfo.push({ - id: img.id, - height: img.height, - width: img.width - }); - } - messaging.postMessage('cacheImageSizes', imageInfo); - } -}, 50); -window.addEventListener('resize', () => { - scrollDisabled = true; - updateImageSizes(); -}, true); -window.addEventListener('message', event => { - if (event.data.source !== settings.source) { - return; - } - switch (event.data.type) { - case 'onDidChangeTextEditorSelection': - marker.onDidChangeTextEditorSelection(event.data.line); - break; - case 'updateView': - onUpdateView(event.data.line, settings); - break; - } -}, false); -document.addEventListener('dblclick', event => { - if (!settings.doubleClickToSwitchToEditor) { - return; - } - // Ignore clicks on links - for (let node = event.target; node; node = node.parentNode) { - if (node.tagName === 'A') { - return; - } - } - const offset = event.pageY; - const line = scroll_sync_1.getEditorLineNumberForPageOffset(offset); - if (typeof line === 'number' && !isNaN(line)) { - messaging.postMessage('didClick', { line: Math.floor(line) }); - } -}); -document.addEventListener('click', event => { - if (!event) { - return; - } - let node = event.target; - while (node) { - if (node.tagName && node.tagName === 'A' && node.href) { - if (node.getAttribute('href').startsWith('#')) { - break; - } - if (node.href.startsWith('file://') || node.href.startsWith('vscode-resource:') || node.href.startsWith(settings.webviewResourceRoot)) { - const [path, fragment] = node.href.replace(/^(file:\/\/|vscode-resource:)/i, '').replace(new RegExp(`^${escapeRegExp(settings.webviewResourceRoot)}`)).split('#'); - messaging.postMessage('clickLink', { path, fragment }); - event.preventDefault(); - event.stopPropagation(); - break; - } - break; - } - node = node.parentNode; - } -}, true); -if (settings.scrollEditorWithPreview) { - window.addEventListener('scroll', throttle(() => { - if (scrollDisabled) { - scrollDisabled = false; - } - else { - const line = scroll_sync_1.getEditorLineNumberForPageOffset(window.scrollY); - if (typeof line === 'number' && !isNaN(line)) { - messaging.postMessage('revealLine', { line }); - state.line = line; - vscode.setState(state); - } - } - }, 50)); -} -function escapeRegExp(text) { - return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); -} - - -/***/ }), - -/***/ "./preview-src/messaging.ts": -/*!**********************************!*\ - !*** ./preview-src/messaging.ts ***! - \**********************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 settings_1 = __webpack_require__(/*! ./settings */ "./preview-src/settings.ts"); -exports.createPosterForVsCode = (vscode) => { - return new class { - postMessage(type, body) { - vscode.postMessage({ - type, - source: settings_1.getSettings().source, - body - }); - } - }; -}; - - -/***/ }), - -/***/ "./preview-src/scroll-sync.ts": -/*!************************************!*\ - !*** ./preview-src/scroll-sync.ts ***! - \************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 settings_1 = __webpack_require__(/*! ./settings */ "./preview-src/settings.ts"); -function clamp(min, max, value) { - return Math.min(max, Math.max(min, value)); -} -function clampLine(line) { - return clamp(0, settings_1.getSettings().lineCount - 1, line); -} -const getCodeLineElements = (() => { - let elements; - return () => { - if (!elements) { - elements = [{ element: document.body, line: 0 }]; - for (const element of document.getElementsByClassName('code-line')) { - const line = +element.getAttribute('data-line'); - if (!isNaN(line)) { - elements.push({ element: element, line }); - } - } - } - return elements; - }; -})(); -/** - * Find the html elements that map to a specific target line in the editor. - * - * If an exact match, returns a single element. If the line is between elements, - * returns the element prior to and the element after the given line. - */ -function getElementsForSourceLine(targetLine) { - const lineNumber = Math.floor(targetLine); - const lines = getCodeLineElements(); - let previous = lines[0] || null; - for (const entry of lines) { - if (entry.line === lineNumber) { - return { previous: entry, next: undefined }; - } - else if (entry.line > lineNumber) { - return { previous, next: entry }; - } - previous = entry; - } - return { previous }; -} -exports.getElementsForSourceLine = getElementsForSourceLine; -/** - * Find the html elements that are at a specific pixel offset on the page. - */ -function getLineElementsAtPageOffset(offset) { - const lines = getCodeLineElements(); - const position = offset - window.scrollY; - let lo = -1; - let hi = lines.length - 1; - while (lo + 1 < hi) { - const mid = Math.floor((lo + hi) / 2); - const bounds = lines[mid].element.getBoundingClientRect(); - if (bounds.top + bounds.height >= position) { - hi = mid; - } - else { - lo = mid; - } - } - const hiElement = lines[hi]; - const hiBounds = hiElement.element.getBoundingClientRect(); - if (hi >= 1 && hiBounds.top > position) { - const loElement = lines[lo]; - return { previous: loElement, next: hiElement }; - } - return { previous: hiElement }; -} -exports.getLineElementsAtPageOffset = getLineElementsAtPageOffset; -/** - * Attempt to reveal the element for a source line in the editor. - */ -function scrollToRevealSourceLine(line) { - if (!settings_1.getSettings().scrollPreviewWithEditor) { - return; - } - if (line <= 0) { - window.scroll(window.scrollX, 0); - return; - } - const { previous, next } = getElementsForSourceLine(line); - if (!previous) { - return; - } - let scrollTo = 0; - const rect = previous.element.getBoundingClientRect(); - const previousTop = rect.top; - if (next && next.line !== previous.line) { - // Between two elements. Go to percentage offset between them. - const betweenProgress = (line - previous.line) / (next.line - previous.line); - const elementOffset = next.element.getBoundingClientRect().top - previousTop; - scrollTo = previousTop + betweenProgress * elementOffset; - } - else { - const progressInElement = line - Math.floor(line); - scrollTo = previousTop + (rect.height * progressInElement); - } - window.scroll(window.scrollX, Math.max(1, window.scrollY + scrollTo)); -} -exports.scrollToRevealSourceLine = scrollToRevealSourceLine; -function getEditorLineNumberForPageOffset(offset) { - const { previous, next } = getLineElementsAtPageOffset(offset); - if (previous) { - const previousBounds = previous.element.getBoundingClientRect(); - const offsetFromPrevious = (offset - window.scrollY - previousBounds.top); - if (next) { - const progressBetweenElements = offsetFromPrevious / (next.element.getBoundingClientRect().top - previousBounds.top); - const line = previous.line + progressBetweenElements * (next.line - previous.line); - return clampLine(line); - } - else { - const progressWithinElement = offsetFromPrevious / (previousBounds.height); - const line = previous.line + progressWithinElement; - return clampLine(line); - } - } - return null; -} -exports.getEditorLineNumberForPageOffset = getEditorLineNumberForPageOffset; -/** - * Try to find the html element by using a fragment id - */ -function getLineElementForFragment(fragment) { - return getCodeLineElements().find((element) => { - return element.element.id === fragment; - }); -} -exports.getLineElementForFragment = getLineElementForFragment; - - -/***/ }), - -/***/ "./preview-src/settings.ts": -/*!*********************************!*\ - !*** ./preview-src/settings.ts ***! - \*********************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 }); -let cachedSettings = undefined; -function getData(key) { - const element = document.getElementById('vscode-markdown-preview-data'); - if (element) { - const data = element.getAttribute(key); - if (data) { - return JSON.parse(data); - } - } - throw new Error(`Could not load data for ${key}`); -} -exports.getData = getData; -function getSettings() { - if (cachedSettings) { - return cachedSettings; - } - cachedSettings = getData('data-settings'); - if (cachedSettings) { - return cachedSettings; - } - throw new Error('Could not load settings'); -} -exports.getSettings = getSettings; - - -/***/ }) - -/******/ }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL2xvZGFzaC50aHJvdHRsZS9pbmRleC5qcyIsIndlYnBhY2s6Ly8vKHdlYnBhY2spL2J1aWxkaW4vZ2xvYmFsLmpzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2FjdGl2ZUxpbmVNYXJrZXIudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvZXZlbnRzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2luZGV4LnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL21lc3NhZ2luZy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zY3JvbGwtc3luYy50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zZXR0aW5ncy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSx5REFBaUQsY0FBYztBQUMvRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBMkIsMEJBQTBCLEVBQUU7QUFDdkQseUNBQWlDLGVBQWU7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOERBQXNELCtEQUErRDs7QUFFckg7QUFDQTs7O0FBR0E7QUFDQTs7Ozs7Ozs7Ozs7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsT0FBTztBQUNsQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLDhDQUE4QyxrQkFBa0I7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLFNBQVM7QUFDcEIsV0FBVyxPQUFPO0FBQ2xCLFdBQVcsT0FBTyxZQUFZO0FBQzlCLFdBQVcsUUFBUTtBQUNuQjtBQUNBLFdBQVcsUUFBUTtBQUNuQjtBQUNBLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtREFBbUQsb0JBQW9CO0FBQ3ZFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsRUFBRTtBQUNiLGFBQWEsUUFBUTtBQUNyQjtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLEVBQUU7QUFDYixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxFQUFFO0FBQ2IsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOzs7Ozs7Ozs7Ozs7O0FDdGJBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNENBQTRDOztBQUU1Qzs7Ozs7Ozs7Ozs7OztBQ25CQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxXQUFXO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLG1CQUFtQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsTUFBTTtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyx5QkFBeUI7QUFDcEU7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdIQUF3SCwyQ0FBMkM7QUFDbkssb0RBQW9ELGlCQUFpQjtBQUNyRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxREFBcUQsT0FBTztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsZ0NBQWdDO0FBQ2hDOzs7Ozs7Ozs7Ozs7O0FDckpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QixrQ0FBa0M7QUFDM0Q7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLHlCQUF5QjtBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQjtBQUNwQjtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGlCQUFpQjtBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOzs7Ozs7Ozs7Ozs7O0FDdklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0MsSUFBSTtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbIiBcdC8vIFRoZSBtb2R1bGUgY2FjaGVcbiBcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG5cbiBcdC8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG4gXHRmdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cbiBcdFx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG4gXHRcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKSB7XG4gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4gXHRcdH1cbiBcdFx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcbiBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuIFx0XHRcdGk6IG1vZHVsZUlkLFxuIFx0XHRcdGw6IGZhbHNlLFxuIFx0XHRcdGV4cG9ydHM6IHt9XG4gXHRcdH07XG5cbiBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG4gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbiBcdFx0bW9kdWxlLmwgPSB0cnVlO1xuXG4gXHRcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG4gXHRcdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbiBcdH1cblxuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZXMgb2JqZWN0IChfX3dlYnBhY2tfbW9kdWxlc19fKVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5tID0gbW9kdWxlcztcblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcbiBcdF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG5cbiBcdC8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb24gZm9yIGhhcm1vbnkgZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XG4gXHRcdGlmKCFfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZXhwb3J0cywgbmFtZSkpIHtcbiBcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgbmFtZSwge1xuIFx0XHRcdFx0Y29uZmlndXJhYmxlOiBmYWxzZSxcbiBcdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXG4gXHRcdFx0XHRnZXQ6IGdldHRlclxuIFx0XHRcdH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gXCIuL3ByZXZpZXctc3JjL2luZGV4LnRzXCIpO1xuIiwiLyoqXG4gKiBsb2Rhc2ggKEN1c3RvbSBCdWlsZCkgPGh0dHBzOi8vbG9kYXNoLmNvbS8+XG4gKiBCdWlsZDogYGxvZGFzaCBtb2R1bGFyaXplIGV4cG9ydHM9XCJucG1cIiAtbyAuL2BcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzIDxodHRwczovL2pxdWVyeS5vcmcvPlxuICogUmVsZWFzZWQgdW5kZXIgTUlUIGxpY2Vuc2UgPGh0dHBzOi8vbG9kYXNoLmNvbS9saWNlbnNlPlxuICogQmFzZWQgb24gVW5kZXJzY29yZS5qcyAxLjguMyA8aHR0cDovL3VuZGVyc2NvcmVqcy5vcmcvTElDRU5TRT5cbiAqIENvcHlyaWdodCBKZXJlbXkgQXNoa2VuYXMsIERvY3VtZW50Q2xvdWQgYW5kIEludmVzdGlnYXRpdmUgUmVwb3J0ZXJzICYgRWRpdG9yc1xuICovXG5cbi8qKiBVc2VkIGFzIHRoZSBgVHlwZUVycm9yYCBtZXNzYWdlIGZvciBcIkZ1bmN0aW9uc1wiIG1ldGhvZHMuICovXG52YXIgRlVOQ19FUlJPUl9URVhUID0gJ0V4cGVjdGVkIGEgZnVuY3Rpb24nO1xuXG4vKiogVXNlZCBhcyByZWZlcmVuY2VzIGZvciB2YXJpb3VzIGBOdW1iZXJgIGNvbnN0YW50cy4gKi9cbnZhciBOQU4gPSAwIC8gMDtcblxuLyoqIGBPYmplY3QjdG9TdHJpbmdgIHJlc3VsdCByZWZlcmVuY2VzLiAqL1xudmFyIHN5bWJvbFRhZyA9ICdbb2JqZWN0IFN5bWJvbF0nO1xuXG4vKiogVXNlZCB0byBtYXRjaCBsZWFkaW5nIGFuZCB0cmFpbGluZyB3aGl0ZXNwYWNlLiAqL1xudmFyIHJlVHJpbSA9IC9eXFxzK3xcXHMrJC9nO1xuXG4vKiogVXNlZCB0byBkZXRlY3QgYmFkIHNpZ25lZCBoZXhhZGVjaW1hbCBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNCYWRIZXggPSAvXlstK10weFswLTlhLWZdKyQvaTtcblxuLyoqIFVzZWQgdG8gZGV0ZWN0IGJpbmFyeSBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNCaW5hcnkgPSAvXjBiWzAxXSskL2k7XG5cbi8qKiBVc2VkIHRvIGRldGVjdCBvY3RhbCBzdHJpbmcgdmFsdWVzLiAqL1xudmFyIHJlSXNPY3RhbCA9IC9eMG9bMC03XSskL2k7XG5cbi8qKiBCdWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcyB3aXRob3V0IGEgZGVwZW5kZW5jeSBvbiBgcm9vdGAuICovXG52YXIgZnJlZVBhcnNlSW50ID0gcGFyc2VJbnQ7XG5cbi8qKiBEZXRlY3QgZnJlZSB2YXJpYWJsZSBgZ2xvYmFsYCBmcm9tIE5vZGUuanMuICovXG52YXIgZnJlZUdsb2JhbCA9IHR5cGVvZiBnbG9iYWwgPT0gJ29iamVjdCcgJiYgZ2xvYmFsICYmIGdsb2JhbC5PYmplY3QgPT09IE9iamVjdCAmJiBnbG9iYWw7XG5cbi8qKiBEZXRlY3QgZnJlZSB2YXJpYWJsZSBgc2VsZmAuICovXG52YXIgZnJlZVNlbGYgPSB0eXBlb2Ygc2VsZiA9PSAnb2JqZWN0JyAmJiBzZWxmICYmIHNlbGYuT2JqZWN0ID09PSBPYmplY3QgJiYgc2VsZjtcblxuLyoqIFVzZWQgYXMgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvYmplY3QuICovXG52YXIgcm9vdCA9IGZyZWVHbG9iYWwgfHwgZnJlZVNlbGYgfHwgRnVuY3Rpb24oJ3JldHVybiB0aGlzJykoKTtcblxuLyoqIFVzZWQgZm9yIGJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzLiAqL1xudmFyIG9iamVjdFByb3RvID0gT2JqZWN0LnByb3RvdHlwZTtcblxuLyoqXG4gKiBVc2VkIHRvIHJlc29sdmUgdGhlXG4gKiBbYHRvU3RyaW5nVGFnYF0oaHR0cDovL2VjbWEtaW50ZXJuYXRpb25hbC5vcmcvZWNtYS0yNjIvNy4wLyNzZWMtb2JqZWN0LnByb3RvdHlwZS50b3N0cmluZylcbiAqIG9mIHZhbHVlcy5cbiAqL1xudmFyIG9iamVjdFRvU3RyaW5nID0gb2JqZWN0UHJvdG8udG9TdHJpbmc7XG5cbi8qIEJ1aWx0LWluIG1ldGhvZCByZWZlcmVuY2VzIGZvciB0aG9zZSB3aXRoIHRoZSBzYW1lIG5hbWUgYXMgb3RoZXIgYGxvZGFzaGAgbWV0aG9kcy4gKi9cbnZhciBuYXRpdmVNYXggPSBNYXRoLm1heCxcbiAgICBuYXRpdmVNaW4gPSBNYXRoLm1pbjtcblxuLyoqXG4gKiBHZXRzIHRoZSB0aW1lc3RhbXAgb2YgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdGhhdCBoYXZlIGVsYXBzZWQgc2luY2VcbiAqIHRoZSBVbml4IGVwb2NoICgxIEphbnVhcnkgMTk3MCAwMDowMDowMCBVVEMpLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMi40LjBcbiAqIEBjYXRlZ29yeSBEYXRlXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBSZXR1cm5zIHRoZSB0aW1lc3RhbXAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uZGVmZXIoZnVuY3Rpb24oc3RhbXApIHtcbiAqICAgY29uc29sZS5sb2coXy5ub3coKSAtIHN0YW1wKTtcbiAqIH0sIF8ubm93KCkpO1xuICogLy8gPT4gTG9ncyB0aGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBpdCB0b29rIGZvciB0aGUgZGVmZXJyZWQgaW52b2NhdGlvbi5cbiAqL1xudmFyIG5vdyA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gcm9vdC5EYXRlLm5vdygpO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVib3VuY2VkIGZ1bmN0aW9uIHRoYXQgZGVsYXlzIGludm9raW5nIGBmdW5jYCB1bnRpbCBhZnRlciBgd2FpdGBcbiAqIG1pbGxpc2Vjb25kcyBoYXZlIGVsYXBzZWQgc2luY2UgdGhlIGxhc3QgdGltZSB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHdhc1xuICogaW52b2tlZC4gVGhlIGRlYm91bmNlZCBmdW5jdGlvbiBjb21lcyB3aXRoIGEgYGNhbmNlbGAgbWV0aG9kIHRvIGNhbmNlbFxuICogZGVsYXllZCBgZnVuY2AgaW52b2NhdGlvbnMgYW5kIGEgYGZsdXNoYCBtZXRob2QgdG8gaW1tZWRpYXRlbHkgaW52b2tlIHRoZW0uXG4gKiBQcm92aWRlIGBvcHRpb25zYCB0byBpbmRpY2F0ZSB3aGV0aGVyIGBmdW5jYCBzaG91bGQgYmUgaW52b2tlZCBvbiB0aGVcbiAqIGxlYWRpbmcgYW5kL29yIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIGB3YWl0YCB0aW1lb3V0LiBUaGUgYGZ1bmNgIGlzIGludm9rZWRcbiAqIHdpdGggdGhlIGxhc3QgYXJndW1lbnRzIHByb3ZpZGVkIHRvIHRoZSBkZWJvdW5jZWQgZnVuY3Rpb24uIFN1YnNlcXVlbnRcbiAqIGNhbGxzIHRvIHRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gcmV0dXJuIHRoZSByZXN1bHQgb2YgdGhlIGxhc3QgYGZ1bmNgXG4gKiBpbnZvY2F0aW9uLlxuICpcbiAqICoqTm90ZToqKiBJZiBgbGVhZGluZ2AgYW5kIGB0cmFpbGluZ2Agb3B0aW9ucyBhcmUgYHRydWVgLCBgZnVuY2AgaXNcbiAqIGludm9rZWQgb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQgb25seSBpZiB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uXG4gKiBpcyBpbnZva2VkIG1vcmUgdGhhbiBvbmNlIGR1cmluZyB0aGUgYHdhaXRgIHRpbWVvdXQuXG4gKlxuICogSWYgYHdhaXRgIGlzIGAwYCBhbmQgYGxlYWRpbmdgIGlzIGBmYWxzZWAsIGBmdW5jYCBpbnZvY2F0aW9uIGlzIGRlZmVycmVkXG4gKiB1bnRpbCB0byB0aGUgbmV4dCB0aWNrLCBzaW1pbGFyIHRvIGBzZXRUaW1lb3V0YCB3aXRoIGEgdGltZW91dCBvZiBgMGAuXG4gKlxuICogU2VlIFtEYXZpZCBDb3JiYWNobydzIGFydGljbGVdKGh0dHBzOi8vY3NzLXRyaWNrcy5jb20vZGVib3VuY2luZy10aHJvdHRsaW5nLWV4cGxhaW5lZC1leGFtcGxlcy8pXG4gKiBmb3IgZGV0YWlscyBvdmVyIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGBfLmRlYm91bmNlYCBhbmQgYF8udGhyb3R0bGVgLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBGdW5jdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gZGVib3VuY2UuXG4gKiBAcGFyYW0ge251bWJlcn0gW3dhaXQ9MF0gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gZGVsYXkuXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnM9e31dIFRoZSBvcHRpb25zIG9iamVjdC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMubGVhZGluZz1mYWxzZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMubWF4V2FpdF1cbiAqICBUaGUgbWF4aW11bSB0aW1lIGBmdW5jYCBpcyBhbGxvd2VkIHRvIGJlIGRlbGF5ZWQgYmVmb3JlIGl0J3MgaW52b2tlZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMudHJhaWxpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgZGVib3VuY2VkIGZ1bmN0aW9uLlxuICogQGV4YW1wbGVcbiAqXG4gKiAvLyBBdm9pZCBjb3N0bHkgY2FsY3VsYXRpb25zIHdoaWxlIHRoZSB3aW5kb3cgc2l6ZSBpcyBpbiBmbHV4LlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3Jlc2l6ZScsIF8uZGVib3VuY2UoY2FsY3VsYXRlTGF5b3V0LCAxNTApKTtcbiAqXG4gKiAvLyBJbnZva2UgYHNlbmRNYWlsYCB3aGVuIGNsaWNrZWQsIGRlYm91bmNpbmcgc3Vic2VxdWVudCBjYWxscy5cbiAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCBfLmRlYm91bmNlKHNlbmRNYWlsLCAzMDAsIHtcbiAqICAgJ2xlYWRpbmcnOiB0cnVlLFxuICogICAndHJhaWxpbmcnOiBmYWxzZVxuICogfSkpO1xuICpcbiAqIC8vIEVuc3VyZSBgYmF0Y2hMb2dgIGlzIGludm9rZWQgb25jZSBhZnRlciAxIHNlY29uZCBvZiBkZWJvdW5jZWQgY2FsbHMuXG4gKiB2YXIgZGVib3VuY2VkID0gXy5kZWJvdW5jZShiYXRjaExvZywgMjUwLCB7ICdtYXhXYWl0JzogMTAwMCB9KTtcbiAqIHZhciBzb3VyY2UgPSBuZXcgRXZlbnRTb3VyY2UoJy9zdHJlYW0nKTtcbiAqIGpRdWVyeShzb3VyY2UpLm9uKCdtZXNzYWdlJywgZGVib3VuY2VkKTtcbiAqXG4gKiAvLyBDYW5jZWwgdGhlIHRyYWlsaW5nIGRlYm91bmNlZCBpbnZvY2F0aW9uLlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3BvcHN0YXRlJywgZGVib3VuY2VkLmNhbmNlbCk7XG4gKi9cbmZ1bmN0aW9uIGRlYm91bmNlKGZ1bmMsIHdhaXQsIG9wdGlvbnMpIHtcbiAgdmFyIGxhc3RBcmdzLFxuICAgICAgbGFzdFRoaXMsXG4gICAgICBtYXhXYWl0LFxuICAgICAgcmVzdWx0LFxuICAgICAgdGltZXJJZCxcbiAgICAgIGxhc3RDYWxsVGltZSxcbiAgICAgIGxhc3RJbnZva2VUaW1lID0gMCxcbiAgICAgIGxlYWRpbmcgPSBmYWxzZSxcbiAgICAgIG1heGluZyA9IGZhbHNlLFxuICAgICAgdHJhaWxpbmcgPSB0cnVlO1xuXG4gIGlmICh0eXBlb2YgZnVuYyAhPSAnZnVuY3Rpb24nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihGVU5DX0VSUk9SX1RFWFQpO1xuICB9XG4gIHdhaXQgPSB0b051bWJlcih3YWl0KSB8fCAwO1xuICBpZiAoaXNPYmplY3Qob3B0aW9ucykpIHtcbiAgICBsZWFkaW5nID0gISFvcHRpb25zLmxlYWRpbmc7XG4gICAgbWF4aW5nID0gJ21heFdhaXQnIGluIG9wdGlvbnM7XG4gICAgbWF4V2FpdCA9IG1heGluZyA/IG5hdGl2ZU1heCh0b051bWJlcihvcHRpb25zLm1heFdhaXQpIHx8IDAsIHdhaXQpIDogbWF4V2FpdDtcbiAgICB0cmFpbGluZyA9ICd0cmFpbGluZycgaW4gb3B0aW9ucyA/ICEhb3B0aW9ucy50cmFpbGluZyA6IHRyYWlsaW5nO1xuICB9XG5cbiAgZnVuY3Rpb24gaW52b2tlRnVuYyh0aW1lKSB7XG4gICAgdmFyIGFyZ3MgPSBsYXN0QXJncyxcbiAgICAgICAgdGhpc0FyZyA9IGxhc3RUaGlzO1xuXG4gICAgbGFzdEFyZ3MgPSBsYXN0VGhpcyA9IHVuZGVmaW5lZDtcbiAgICBsYXN0SW52b2tlVGltZSA9IHRpbWU7XG4gICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzQXJnLCBhcmdzKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gbGVhZGluZ0VkZ2UodGltZSkge1xuICAgIC8vIFJlc2V0IGFueSBgbWF4V2FpdGAgdGltZXIuXG4gICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgIC8vIFN0YXJ0IHRoZSB0aW1lciBmb3IgdGhlIHRyYWlsaW5nIGVkZ2UuXG4gICAgdGltZXJJZCA9IHNldFRpbWVvdXQodGltZXJFeHBpcmVkLCB3YWl0KTtcbiAgICAvLyBJbnZva2UgdGhlIGxlYWRpbmcgZWRnZS5cbiAgICByZXR1cm4gbGVhZGluZyA/IGludm9rZUZ1bmModGltZSkgOiByZXN1bHQ7XG4gIH1cblxuICBmdW5jdGlvbiByZW1haW5pbmdXYWl0KHRpbWUpIHtcbiAgICB2YXIgdGltZVNpbmNlTGFzdENhbGwgPSB0aW1lIC0gbGFzdENhbGxUaW1lLFxuICAgICAgICB0aW1lU2luY2VMYXN0SW52b2tlID0gdGltZSAtIGxhc3RJbnZva2VUaW1lLFxuICAgICAgICByZXN1bHQgPSB3YWl0IC0gdGltZVNpbmNlTGFzdENhbGw7XG5cbiAgICByZXR1cm4gbWF4aW5nID8gbmF0aXZlTWluKHJlc3VsdCwgbWF4V2FpdCAtIHRpbWVTaW5jZUxhc3RJbnZva2UpIDogcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gc2hvdWxkSW52b2tlKHRpbWUpIHtcbiAgICB2YXIgdGltZVNpbmNlTGFzdENhbGwgPSB0aW1lIC0gbGFzdENhbGxUaW1lLFxuICAgICAgICB0aW1lU2luY2VMYXN0SW52b2tlID0gdGltZSAtIGxhc3RJbnZva2VUaW1lO1xuXG4gICAgLy8gRWl0aGVyIHRoaXMgaXMgdGhlIGZpcnN0IGNhbGwsIGFjdGl2aXR5IGhhcyBzdG9wcGVkIGFuZCB3ZSdyZSBhdCB0aGVcbiAgICAvLyB0cmFpbGluZyBlZGdlLCB0aGUgc3lzdGVtIHRpbWUgaGFzIGdvbmUgYmFja3dhcmRzIGFuZCB3ZSdyZSB0cmVhdGluZ1xuICAgIC8vIGl0IGFzIHRoZSB0cmFpbGluZyBlZGdlLCBvciB3ZSd2ZSBoaXQgdGhlIGBtYXhXYWl0YCBsaW1pdC5cbiAgICByZXR1cm4gKGxhc3RDYWxsVGltZSA9PT0gdW5kZWZpbmVkIHx8ICh0aW1lU2luY2VMYXN0Q2FsbCA+PSB3YWl0KSB8fFxuICAgICAgKHRpbWVTaW5jZUxhc3RDYWxsIDwgMCkgfHwgKG1heGluZyAmJiB0aW1lU2luY2VMYXN0SW52b2tlID49IG1heFdhaXQpKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHRpbWVyRXhwaXJlZCgpIHtcbiAgICB2YXIgdGltZSA9IG5vdygpO1xuICAgIGlmIChzaG91bGRJbnZva2UodGltZSkpIHtcbiAgICAgIHJldHVybiB0cmFpbGluZ0VkZ2UodGltZSk7XG4gICAgfVxuICAgIC8vIFJlc3RhcnQgdGhlIHRpbWVyLlxuICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgcmVtYWluaW5nV2FpdCh0aW1lKSk7XG4gIH1cblxuICBmdW5jdGlvbiB0cmFpbGluZ0VkZ2UodGltZSkge1xuICAgIHRpbWVySWQgPSB1bmRlZmluZWQ7XG5cbiAgICAvLyBPbmx5IGludm9rZSBpZiB3ZSBoYXZlIGBsYXN0QXJnc2Agd2hpY2ggbWVhbnMgYGZ1bmNgIGhhcyBiZWVuXG4gICAgLy8gZGVib3VuY2VkIGF0IGxlYXN0IG9uY2UuXG4gICAgaWYgKHRyYWlsaW5nICYmIGxhc3RBcmdzKSB7XG4gICAgICByZXR1cm4gaW52b2tlRnVuYyh0aW1lKTtcbiAgICB9XG4gICAgbGFzdEFyZ3MgPSBsYXN0VGhpcyA9IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gY2FuY2VsKCkge1xuICAgIGlmICh0aW1lcklkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aW1lcklkKTtcbiAgICB9XG4gICAgbGFzdEludm9rZVRpbWUgPSAwO1xuICAgIGxhc3RBcmdzID0gbGFzdENhbGxUaW1lID0gbGFzdFRoaXMgPSB0aW1lcklkID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgZnVuY3Rpb24gZmx1c2goKSB7XG4gICAgcmV0dXJuIHRpbWVySWQgPT09IHVuZGVmaW5lZCA/IHJlc3VsdCA6IHRyYWlsaW5nRWRnZShub3coKSk7XG4gIH1cblxuICBmdW5jdGlvbiBkZWJvdW5jZWQoKSB7XG4gICAgdmFyIHRpbWUgPSBub3coKSxcbiAgICAgICAgaXNJbnZva2luZyA9IHNob3VsZEludm9rZSh0aW1lKTtcblxuICAgIGxhc3RBcmdzID0gYXJndW1lbnRzO1xuICAgIGxhc3RUaGlzID0gdGhpcztcbiAgICBsYXN0Q2FsbFRpbWUgPSB0aW1lO1xuXG4gICAgaWYgKGlzSW52b2tpbmcpIHtcbiAgICAgIGlmICh0aW1lcklkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIGxlYWRpbmdFZGdlKGxhc3RDYWxsVGltZSk7XG4gICAgICB9XG4gICAgICBpZiAobWF4aW5nKSB7XG4gICAgICAgIC8vIEhhbmRsZSBpbnZvY2F0aW9ucyBpbiBhIHRpZ2h0IGxvb3AuXG4gICAgICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgICAgIHJldHVybiBpbnZva2VGdW5jKGxhc3RDYWxsVGltZSk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICh0aW1lcklkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgZGVib3VuY2VkLmNhbmNlbCA9IGNhbmNlbDtcbiAgZGVib3VuY2VkLmZsdXNoID0gZmx1c2g7XG4gIHJldHVybiBkZWJvdW5jZWQ7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHRocm90dGxlZCBmdW5jdGlvbiB0aGF0IG9ubHkgaW52b2tlcyBgZnVuY2AgYXQgbW9zdCBvbmNlIHBlclxuICogZXZlcnkgYHdhaXRgIG1pbGxpc2Vjb25kcy4gVGhlIHRocm90dGxlZCBmdW5jdGlvbiBjb21lcyB3aXRoIGEgYGNhbmNlbGBcbiAqIG1ldGhvZCB0byBjYW5jZWwgZGVsYXllZCBgZnVuY2AgaW52b2NhdGlvbnMgYW5kIGEgYGZsdXNoYCBtZXRob2QgdG9cbiAqIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLiBQcm92aWRlIGBvcHRpb25zYCB0byBpbmRpY2F0ZSB3aGV0aGVyIGBmdW5jYFxuICogc2hvdWxkIGJlIGludm9rZWQgb24gdGhlIGxlYWRpbmcgYW5kL29yIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIGB3YWl0YFxuICogdGltZW91dC4gVGhlIGBmdW5jYCBpcyBpbnZva2VkIHdpdGggdGhlIGxhc3QgYXJndW1lbnRzIHByb3ZpZGVkIHRvIHRoZVxuICogdGhyb3R0bGVkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50IGNhbGxzIHRvIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gcmV0dXJuIHRoZVxuICogcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYCBpbnZvY2F0aW9uLlxuICpcbiAqICoqTm90ZToqKiBJZiBgbGVhZGluZ2AgYW5kIGB0cmFpbGluZ2Agb3B0aW9ucyBhcmUgYHRydWVgLCBgZnVuY2AgaXNcbiAqIGludm9rZWQgb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQgb25seSBpZiB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uXG4gKiBpcyBpbnZva2VkIG1vcmUgdGhhbiBvbmNlIGR1cmluZyB0aGUgYHdhaXRgIHRpbWVvdXQuXG4gKlxuICogSWYgYHdhaXRgIGlzIGAwYCBhbmQgYGxlYWRpbmdgIGlzIGBmYWxzZWAsIGBmdW5jYCBpbnZvY2F0aW9uIGlzIGRlZmVycmVkXG4gKiB1bnRpbCB0byB0aGUgbmV4dCB0aWNrLCBzaW1pbGFyIHRvIGBzZXRUaW1lb3V0YCB3aXRoIGEgdGltZW91dCBvZiBgMGAuXG4gKlxuICogU2VlIFtEYXZpZCBDb3JiYWNobydzIGFydGljbGVdKGh0dHBzOi8vY3NzLXRyaWNrcy5jb20vZGVib3VuY2luZy10aHJvdHRsaW5nLWV4cGxhaW5lZC1leGFtcGxlcy8pXG4gKiBmb3IgZGV0YWlscyBvdmVyIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGBfLnRocm90dGxlYCBhbmQgYF8uZGVib3VuY2VgLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBGdW5jdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gdGhyb3R0bGUuXG4gKiBAcGFyYW0ge251bWJlcn0gW3dhaXQ9MF0gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gdGhyb3R0bGUgaW52b2NhdGlvbnMgdG8uXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnM9e31dIFRoZSBvcHRpb25zIG9iamVjdC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMubGVhZGluZz10cnVlXVxuICogIFNwZWNpZnkgaW52b2tpbmcgb24gdGhlIGxlYWRpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMudHJhaWxpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgdGhyb3R0bGVkIGZ1bmN0aW9uLlxuICogQGV4YW1wbGVcbiAqXG4gKiAvLyBBdm9pZCBleGNlc3NpdmVseSB1cGRhdGluZyB0aGUgcG9zaXRpb24gd2hpbGUgc2Nyb2xsaW5nLlxuICogalF1ZXJ5KHdpbmRvdykub24oJ3Njcm9sbCcsIF8udGhyb3R0bGUodXBkYXRlUG9zaXRpb24sIDEwMCkpO1xuICpcbiAqIC8vIEludm9rZSBgcmVuZXdUb2tlbmAgd2hlbiB0aGUgY2xpY2sgZXZlbnQgaXMgZmlyZWQsIGJ1dCBub3QgbW9yZSB0aGFuIG9uY2UgZXZlcnkgNSBtaW51dGVzLlxuICogdmFyIHRocm90dGxlZCA9IF8udGhyb3R0bGUocmVuZXdUb2tlbiwgMzAwMDAwLCB7ICd0cmFpbGluZyc6IGZhbHNlIH0pO1xuICogalF1ZXJ5KGVsZW1lbnQpLm9uKCdjbGljaycsIHRocm90dGxlZCk7XG4gKlxuICogLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyB0aHJvdHRsZWQgaW52b2NhdGlvbi5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIHRocm90dGxlZC5jYW5jZWwpO1xuICovXG5mdW5jdGlvbiB0aHJvdHRsZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIHZhciBsZWFkaW5nID0gdHJ1ZSxcbiAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoRlVOQ19FUlJPUl9URVhUKTtcbiAgfVxuICBpZiAoaXNPYmplY3Qob3B0aW9ucykpIHtcbiAgICBsZWFkaW5nID0gJ2xlYWRpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMubGVhZGluZyA6IGxlYWRpbmc7XG4gICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgfVxuICByZXR1cm4gZGVib3VuY2UoZnVuYywgd2FpdCwge1xuICAgICdsZWFkaW5nJzogbGVhZGluZyxcbiAgICAnbWF4V2FpdCc6IHdhaXQsXG4gICAgJ3RyYWlsaW5nJzogdHJhaWxpbmdcbiAgfSk7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgdGhlXG4gKiBbbGFuZ3VhZ2UgdHlwZV0oaHR0cDovL3d3dy5lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLWVjbWFzY3JpcHQtbGFuZ3VhZ2UtdHlwZXMpXG4gKiBvZiBgT2JqZWN0YC4gKGUuZy4gYXJyYXlzLCBmdW5jdGlvbnMsIG9iamVjdHMsIHJlZ2V4ZXMsIGBuZXcgTnVtYmVyKDApYCwgYW5kIGBuZXcgU3RyaW5nKCcnKWApXG4gKlxuICogQHN0YXRpY1xuICogQG1lbWJlck9mIF9cbiAqIEBzaW5jZSAwLjEuMFxuICogQGNhdGVnb3J5IExhbmdcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYW4gb2JqZWN0LCBlbHNlIGBmYWxzZWAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uaXNPYmplY3Qoe30pO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3QoWzEsIDIsIDNdKTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0KF8ubm9vcCk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdChudWxsKTtcbiAqIC8vID0+IGZhbHNlXG4gKi9cbmZ1bmN0aW9uIGlzT2JqZWN0KHZhbHVlKSB7XG4gIHZhciB0eXBlID0gdHlwZW9mIHZhbHVlO1xuICByZXR1cm4gISF2YWx1ZSAmJiAodHlwZSA9PSAnb2JqZWN0JyB8fCB0eXBlID09ICdmdW5jdGlvbicpO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIG9iamVjdC1saWtlLiBBIHZhbHVlIGlzIG9iamVjdC1saWtlIGlmIGl0J3Mgbm90IGBudWxsYFxuICogYW5kIGhhcyBhIGB0eXBlb2ZgIHJlc3VsdCBvZiBcIm9iamVjdFwiLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgNC4wLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIG9iamVjdC1saWtlLCBlbHNlIGBmYWxzZWAuXG4gKiBAZXhhbXBsZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKHt9KTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShbMSwgMiwgM10pO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKF8ubm9vcCk7XG4gKiAvLyA9PiBmYWxzZVxuICpcbiAqIF8uaXNPYmplY3RMaWtlKG51bGwpO1xuICogLy8gPT4gZmFsc2VcbiAqL1xuZnVuY3Rpb24gaXNPYmplY3RMaWtlKHZhbHVlKSB7XG4gIHJldHVybiAhIXZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0Jztcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBjbGFzc2lmaWVkIGFzIGEgYFN5bWJvbGAgcHJpbWl0aXZlIG9yIG9iamVjdC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBhIHN5bWJvbCwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzU3ltYm9sKFN5bWJvbC5pdGVyYXRvcik7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc1N5bWJvbCgnYWJjJyk7XG4gKiAvLyA9PiBmYWxzZVxuICovXG5mdW5jdGlvbiBpc1N5bWJvbCh2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdzeW1ib2wnIHx8XG4gICAgKGlzT2JqZWN0TGlrZSh2YWx1ZSkgJiYgb2JqZWN0VG9TdHJpbmcuY2FsbCh2YWx1ZSkgPT0gc3ltYm9sVGFnKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBgdmFsdWVgIHRvIGEgbnVtYmVyLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgNC4wLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBwcm9jZXNzLlxuICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgbnVtYmVyLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLnRvTnVtYmVyKDMuMik7XG4gKiAvLyA9PiAzLjJcbiAqXG4gKiBfLnRvTnVtYmVyKE51bWJlci5NSU5fVkFMVUUpO1xuICogLy8gPT4gNWUtMzI0XG4gKlxuICogXy50b051bWJlcihJbmZpbml0eSk7XG4gKiAvLyA9PiBJbmZpbml0eVxuICpcbiAqIF8udG9OdW1iZXIoJzMuMicpO1xuICogLy8gPT4gMy4yXG4gKi9cbmZ1bmN0aW9uIHRvTnVtYmVyKHZhbHVlKSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cbiAgaWYgKGlzU3ltYm9sKHZhbHVlKSkge1xuICAgIHJldHVybiBOQU47XG4gIH1cbiAgaWYgKGlzT2JqZWN0KHZhbHVlKSkge1xuICAgIHZhciBvdGhlciA9IHR5cGVvZiB2YWx1ZS52YWx1ZU9mID09ICdmdW5jdGlvbicgPyB2YWx1ZS52YWx1ZU9mKCkgOiB2YWx1ZTtcbiAgICB2YWx1ZSA9IGlzT2JqZWN0KG90aGVyKSA/IChvdGhlciArICcnKSA6IG90aGVyO1xuICB9XG4gIGlmICh0eXBlb2YgdmFsdWUgIT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gdmFsdWUgPT09IDAgPyB2YWx1ZSA6ICt2YWx1ZTtcbiAgfVxuICB2YWx1ZSA9IHZhbHVlLnJlcGxhY2UocmVUcmltLCAnJyk7XG4gIHZhciBpc0JpbmFyeSA9IHJlSXNCaW5hcnkudGVzdCh2YWx1ZSk7XG4gIHJldHVybiAoaXNCaW5hcnkgfHwgcmVJc09jdGFsLnRlc3QodmFsdWUpKVxuICAgID8gZnJlZVBhcnNlSW50KHZhbHVlLnNsaWNlKDIpLCBpc0JpbmFyeSA/IDIgOiA4KVxuICAgIDogKHJlSXNCYWRIZXgudGVzdCh2YWx1ZSkgPyBOQU4gOiArdmFsdWUpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHRocm90dGxlO1xuIiwidmFyIGc7XHJcblxyXG4vLyBUaGlzIHdvcmtzIGluIG5vbi1zdHJpY3QgbW9kZVxyXG5nID0gKGZ1bmN0aW9uKCkge1xyXG5cdHJldHVybiB0aGlzO1xyXG59KSgpO1xyXG5cclxudHJ5IHtcclxuXHQvLyBUaGlzIHdvcmtzIGlmIGV2YWwgaXMgYWxsb3dlZCAoc2VlIENTUClcclxuXHRnID0gZyB8fCBGdW5jdGlvbihcInJldHVybiB0aGlzXCIpKCkgfHwgKDEsIGV2YWwpKFwidGhpc1wiKTtcclxufSBjYXRjaCAoZSkge1xyXG5cdC8vIFRoaXMgd29ya3MgaWYgdGhlIHdpbmRvdyByZWZlcmVuY2UgaXMgYXZhaWxhYmxlXHJcblx0aWYgKHR5cGVvZiB3aW5kb3cgPT09IFwib2JqZWN0XCIpIGcgPSB3aW5kb3c7XHJcbn1cclxuXHJcbi8vIGcgY2FuIHN0aWxsIGJlIHVuZGVmaW5lZCwgYnV0IG5vdGhpbmcgdG8gZG8gYWJvdXQgaXQuLi5cclxuLy8gV2UgcmV0dXJuIHVuZGVmaW5lZCwgaW5zdGVhZCBvZiBub3RoaW5nIGhlcmUsIHNvIGl0J3NcclxuLy8gZWFzaWVyIHRvIGhhbmRsZSB0aGlzIGNhc2UuIGlmKCFnbG9iYWwpIHsgLi4ufVxyXG5cclxubW9kdWxlLmV4cG9ydHMgPSBnO1xyXG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuY29uc3Qgc2Nyb2xsX3N5bmNfMSA9IHJlcXVpcmUoXCIuL3Njcm9sbC1zeW5jXCIpO1xuY2xhc3MgQWN0aXZlTGluZU1hcmtlciB7XG4gICAgb25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGxpbmUpIHtcbiAgICAgICAgY29uc3QgeyBwcmV2aW91cyB9ID0gc2Nyb2xsX3N5bmNfMS5nZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUobGluZSk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZShwcmV2aW91cyAmJiBwcmV2aW91cy5lbGVtZW50KTtcbiAgICB9XG4gICAgX3VwZGF0ZShiZWZvcmUpIHtcbiAgICAgICAgdGhpcy5fdW5tYXJrQWN0aXZlRWxlbWVudCh0aGlzLl9jdXJyZW50KTtcbiAgICAgICAgdGhpcy5fbWFya0FjdGl2ZUVsZW1lbnQoYmVmb3JlKTtcbiAgICAgICAgdGhpcy5fY3VycmVudCA9IGJlZm9yZTtcbiAgICB9XG4gICAgX3VubWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSA9IGVsZW1lbnQuY2xhc3NOYW1lLnJlcGxhY2UoL1xcYmNvZGUtYWN0aXZlLWxpbmVcXGIvZywgJycpO1xuICAgIH1cbiAgICBfbWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSArPSAnIGNvZGUtYWN0aXZlLWxpbmUnO1xuICAgIH1cbn1cbmV4cG9ydHMuQWN0aXZlTGluZU1hcmtlciA9IEFjdGl2ZUxpbmVNYXJrZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gb25jZURvY3VtZW50TG9hZGVkKGYpIHtcbiAgICBpZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnIHx8IGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICd1bmluaXRpYWxpemVkJykge1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBmKCk7XG4gICAgfVxufVxuZXhwb3J0cy5vbmNlRG9jdW1lbnRMb2FkZWQgPSBvbmNlRG9jdW1lbnRMb2FkZWQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgYWN0aXZlTGluZU1hcmtlcl8xID0gcmVxdWlyZShcIi4vYWN0aXZlTGluZU1hcmtlclwiKTtcbmNvbnN0IGV2ZW50c18xID0gcmVxdWlyZShcIi4vZXZlbnRzXCIpO1xuY29uc3QgbWVzc2FnaW5nXzEgPSByZXF1aXJlKFwiLi9tZXNzYWdpbmdcIik7XG5jb25zdCBzY3JvbGxfc3luY18xID0gcmVxdWlyZShcIi4vc2Nyb2xsLXN5bmNcIik7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5jb25zdCB0aHJvdHRsZSA9IHJlcXVpcmUoXCJsb2Rhc2gudGhyb3R0bGVcIik7XG5sZXQgc2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuY29uc3QgbWFya2VyID0gbmV3IGFjdGl2ZUxpbmVNYXJrZXJfMS5BY3RpdmVMaW5lTWFya2VyKCk7XG5jb25zdCBzZXR0aW5ncyA9IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKTtcbmNvbnN0IHZzY29kZSA9IGFjcXVpcmVWc0NvZGVBcGkoKTtcbi8vIFNldCBWUyBDb2RlIHN0YXRlXG5sZXQgc3RhdGUgPSBzZXR0aW5nc18xLmdldERhdGEoJ2RhdGEtc3RhdGUnKTtcbnZzY29kZS5zZXRTdGF0ZShzdGF0ZSk7XG5jb25zdCBtZXNzYWdpbmcgPSBtZXNzYWdpbmdfMS5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUodnNjb2RlKTtcbndpbmRvdy5jc3BBbGVydGVyLnNldFBvc3RlcihtZXNzYWdpbmcpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3Iuc2V0UG9zdGVyKG1lc3NhZ2luZyk7XG53aW5kb3cub25sb2FkID0gKCkgPT4ge1xuICAgIHVwZGF0ZUltYWdlU2l6ZXMoKTtcbn07XG5ldmVudHNfMS5vbmNlRG9jdW1lbnRMb2FkZWQoKCkgPT4ge1xuICAgIGlmIChzZXR0aW5ncy5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIC8vIFRyeSB0byBzY3JvbGwgdG8gZnJhZ21lbnQgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBpZiAoc3RhdGUuZnJhZ21lbnQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gc2Nyb2xsX3N5bmNfMS5nZXRMaW5lRWxlbWVudEZvckZyYWdtZW50KHN0YXRlLmZyYWdtZW50KTtcbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGVsZW1lbnQubGluZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5pdGlhbExpbmUgPSArc2V0dGluZ3MubGluZTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGluaXRpYWxMaW5lKSkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGluaXRpYWxMaW5lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDApO1xuICAgIH1cbn0pO1xuY29uc3Qgb25VcGRhdGVWaWV3ID0gKCgpID0+IHtcbiAgICBjb25zdCBkb1Njcm9sbCA9IHRocm90dGxlKChsaW5lKSA9PiB7XG4gICAgICAgIHNjcm9sbERpc2FibGVkID0gdHJ1ZTtcbiAgICAgICAgc2Nyb2xsX3N5bmNfMS5zY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUobGluZSk7XG4gICAgfSwgNTApO1xuICAgIHJldHVybiAobGluZSwgc2V0dGluZ3MpID0+IHtcbiAgICAgICAgaWYgKCFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgc2V0dGluZ3MubGluZSA9IGxpbmU7XG4gICAgICAgICAgICBkb1Njcm9sbChsaW5lKTtcbiAgICAgICAgfVxuICAgIH07XG59KSgpO1xubGV0IHVwZGF0ZUltYWdlU2l6ZXMgPSB0aHJvdHRsZSgoKSA9PiB7XG4gICAgY29uc3QgaW1hZ2VJbmZvID0gW107XG4gICAgbGV0IGltYWdlcyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbWcnKTtcbiAgICBpZiAoaW1hZ2VzKSB7XG4gICAgICAgIGxldCBpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgaW1hZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBpbWcgPSBpbWFnZXNbaV07XG4gICAgICAgICAgICBpZiAoaW1nLmNsYXNzTGlzdC5jb250YWlucygnbG9hZGluZycpKSB7XG4gICAgICAgICAgICAgICAgaW1nLmNsYXNzTGlzdC5yZW1vdmUoJ2xvYWRpbmcnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGltYWdlSW5mby5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogaW1nLmlkLFxuICAgICAgICAgICAgICAgIGhlaWdodDogaW1nLmhlaWdodCxcbiAgICAgICAgICAgICAgICB3aWR0aDogaW1nLndpZHRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NhY2hlSW1hZ2VTaXplcycsIGltYWdlSW5mbyk7XG4gICAgfVxufSwgNTApO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgdXBkYXRlSW1hZ2VTaXplcygpO1xufSwgdHJ1ZSk7XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGV2ZW50ID0+IHtcbiAgICBpZiAoZXZlbnQuZGF0YS5zb3VyY2UgIT09IHNldHRpbmdzLnNvdXJjZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHN3aXRjaCAoZXZlbnQuZGF0YS50eXBlKSB7XG4gICAgICAgIGNhc2UgJ29uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbic6XG4gICAgICAgICAgICBtYXJrZXIub25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGV2ZW50LmRhdGEubGluZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndXBkYXRlVmlldyc6XG4gICAgICAgICAgICBvblVwZGF0ZVZpZXcoZXZlbnQuZGF0YS5saW5lLCBzZXR0aW5ncyk7XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG59LCBmYWxzZSk7XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIGV2ZW50ID0+IHtcbiAgICBpZiAoIXNldHRpbmdzLmRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIElnbm9yZSBjbGlja3Mgb24gbGlua3NcbiAgICBmb3IgKGxldCBub2RlID0gZXZlbnQudGFyZ2V0OyBub2RlOyBub2RlID0gbm9kZS5wYXJlbnROb2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgPT09ICdBJykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IG9mZnNldCA9IGV2ZW50LnBhZ2VZO1xuICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgbWVzc2FnaW5nLnBvc3RNZXNzYWdlKCdkaWRDbGljaycsIHsgbGluZTogTWF0aC5mbG9vcihsaW5lKSB9KTtcbiAgICB9XG59KTtcbmRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZXZlbnQgPT4ge1xuICAgIGlmICghZXZlbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgbm9kZSA9IGV2ZW50LnRhcmdldDtcbiAgICB3aGlsZSAobm9kZSkge1xuICAgICAgICBpZiAobm9kZS50YWdOYW1lICYmIG5vZGUudGFnTmFtZSA9PT0gJ0EnICYmIG5vZGUuaHJlZikge1xuICAgICAgICAgICAgaWYgKG5vZGUuZ2V0QXR0cmlidXRlKCdocmVmJykuc3RhcnRzV2l0aCgnIycpKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobm9kZS5ocmVmLnN0YXJ0c1dpdGgoJ2ZpbGU6Ly8nKSB8fCBub2RlLmhyZWYuc3RhcnRzV2l0aCgndnNjb2RlLXJlc291cmNlOicpIHx8IG5vZGUuaHJlZi5zdGFydHNXaXRoKHNldHRpbmdzLndlYnZpZXdSZXNvdXJjZVJvb3QpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgW3BhdGgsIGZyYWdtZW50XSA9IG5vZGUuaHJlZi5yZXBsYWNlKC9eKGZpbGU6XFwvXFwvfHZzY29kZS1yZXNvdXJjZTopL2ksICcnKS5yZXBsYWNlKG5ldyBSZWdFeHAoYF4ke2VzY2FwZVJlZ0V4cChzZXR0aW5ncy53ZWJ2aWV3UmVzb3VyY2VSb290KX1gKSkuc3BsaXQoJyMnKTtcbiAgICAgICAgICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NsaWNrTGluaycsIHsgcGF0aCwgZnJhZ21lbnQgfSk7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIG5vZGUgPSBub2RlLnBhcmVudE5vZGU7XG4gICAgfVxufSwgdHJ1ZSk7XG5pZiAoc2V0dGluZ3Muc2Nyb2xsRWRpdG9yV2l0aFByZXZpZXcpIHtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhyb3R0bGUoKCkgPT4ge1xuICAgICAgICBpZiAoc2Nyb2xsRGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHNjcm9sbERpc2FibGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBsaW5lID0gc2Nyb2xsX3N5bmNfMS5nZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCh3aW5kb3cuc2Nyb2xsWSk7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGxpbmUgPT09ICdudW1iZXInICYmICFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2luZy5wb3N0TWVzc2FnZSgncmV2ZWFsTGluZScsIHsgbGluZSB9KTtcbiAgICAgICAgICAgICAgICBzdGF0ZS5saW5lID0gbGluZTtcbiAgICAgICAgICAgICAgICB2c2NvZGUuc2V0U3RhdGUoc3RhdGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSwgNTApKTtcbn1cbmZ1bmN0aW9uIGVzY2FwZVJlZ0V4cCh0ZXh0KSB7XG4gICAgcmV0dXJuIHRleHQucmVwbGFjZSgvWy1bXFxde30oKSorPy4sXFxcXF4kfCNcXHNdL2csICdcXFxcJCYnKTtcbn1cbiIsIlwidXNlIHN0cmljdFwiO1xuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5leHBvcnRzLmNyZWF0ZVBvc3RlckZvclZzQ29kZSA9ICh2c2NvZGUpID0+IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIHtcbiAgICAgICAgcG9zdE1lc3NhZ2UodHlwZSwgYm9keSkge1xuICAgICAgICAgICAgdnNjb2RlLnBvc3RNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICB0eXBlLFxuICAgICAgICAgICAgICAgIHNvdXJjZTogc2V0dGluZ3NfMS5nZXRTZXR0aW5ncygpLnNvdXJjZSxcbiAgICAgICAgICAgICAgICBib2R5XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmNvbnN0IHNldHRpbmdzXzEgPSByZXF1aXJlKFwiLi9zZXR0aW5nc1wiKTtcbmZ1bmN0aW9uIGNsYW1wKG1pbiwgbWF4LCB2YWx1ZSkge1xuICAgIHJldHVybiBNYXRoLm1pbihtYXgsIE1hdGgubWF4KG1pbiwgdmFsdWUpKTtcbn1cbmZ1bmN0aW9uIGNsYW1wTGluZShsaW5lKSB7XG4gICAgcmV0dXJuIGNsYW1wKDAsIHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5saW5lQ291bnQgLSAxLCBsaW5lKTtcbn1cbmNvbnN0IGdldENvZGVMaW5lRWxlbWVudHMgPSAoKCkgPT4ge1xuICAgIGxldCBlbGVtZW50cztcbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBpZiAoIWVsZW1lbnRzKSB7XG4gICAgICAgICAgICBlbGVtZW50cyA9IFt7IGVsZW1lbnQ6IGRvY3VtZW50LmJvZHksIGxpbmU6IDAgfV07XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgnY29kZS1saW5lJykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBsaW5lID0gK2VsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLWxpbmUnKTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGxpbmUpKSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzLnB1c2goeyBlbGVtZW50OiBlbGVtZW50LCBsaW5lIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZWxlbWVudHM7XG4gICAgfTtcbn0pKCk7XG4vKipcbiAqIEZpbmQgdGhlIGh0bWwgZWxlbWVudHMgdGhhdCBtYXAgdG8gYSBzcGVjaWZpYyB0YXJnZXQgbGluZSBpbiB0aGUgZWRpdG9yLlxuICpcbiAqIElmIGFuIGV4YWN0IG1hdGNoLCByZXR1cm5zIGEgc2luZ2xlIGVsZW1lbnQuIElmIHRoZSBsaW5lIGlzIGJldHdlZW4gZWxlbWVudHMsXG4gKiByZXR1cm5zIHRoZSBlbGVtZW50IHByaW9yIHRvIGFuZCB0aGUgZWxlbWVudCBhZnRlciB0aGUgZ2l2ZW4gbGluZS5cbiAqL1xuZnVuY3Rpb24gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lKHRhcmdldExpbmUpIHtcbiAgICBjb25zdCBsaW5lTnVtYmVyID0gTWF0aC5mbG9vcih0YXJnZXRMaW5lKTtcbiAgICBjb25zdCBsaW5lcyA9IGdldENvZGVMaW5lRWxlbWVudHMoKTtcbiAgICBsZXQgcHJldmlvdXMgPSBsaW5lc1swXSB8fCBudWxsO1xuICAgIGZvciAoY29uc3QgZW50cnkgb2YgbGluZXMpIHtcbiAgICAgICAgaWYgKGVudHJ5LmxpbmUgPT09IGxpbmVOdW1iZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHByZXZpb3VzOiBlbnRyeSwgbmV4dDogdW5kZWZpbmVkIH07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZW50cnkubGluZSA+IGxpbmVOdW1iZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHByZXZpb3VzLCBuZXh0OiBlbnRyeSB9O1xuICAgICAgICB9XG4gICAgICAgIHByZXZpb3VzID0gZW50cnk7XG4gICAgfVxuICAgIHJldHVybiB7IHByZXZpb3VzIH07XG59XG5leHBvcnRzLmdldEVsZW1lbnRzRm9yU291cmNlTGluZSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZTtcbi8qKlxuICogRmluZCB0aGUgaHRtbCBlbGVtZW50cyB0aGF0IGFyZSBhdCBhIHNwZWNpZmljIHBpeGVsIG9mZnNldCBvbiB0aGUgcGFnZS5cbiAqL1xuZnVuY3Rpb24gZ2V0TGluZUVsZW1lbnRzQXRQYWdlT2Zmc2V0KG9mZnNldCkge1xuICAgIGNvbnN0IGxpbmVzID0gZ2V0Q29kZUxpbmVFbGVtZW50cygpO1xuICAgIGNvbnN0IHBvc2l0aW9uID0gb2Zmc2V0IC0gd2luZG93LnNjcm9sbFk7XG4gICAgbGV0IGxvID0gLTE7XG4gICAgbGV0IGhpID0gbGluZXMubGVuZ3RoIC0gMTtcbiAgICB3aGlsZSAobG8gKyAxIDwgaGkpIHtcbiAgICAgICAgY29uc3QgbWlkID0gTWF0aC5mbG9vcigobG8gKyBoaSkgLyAyKTtcbiAgICAgICAgY29uc3QgYm91bmRzID0gbGluZXNbbWlkXS5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBpZiAoYm91bmRzLnRvcCArIGJvdW5kcy5oZWlnaHQgPj0gcG9zaXRpb24pIHtcbiAgICAgICAgICAgIGhpID0gbWlkO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbG8gPSBtaWQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgaGlFbGVtZW50ID0gbGluZXNbaGldO1xuICAgIGNvbnN0IGhpQm91bmRzID0gaGlFbGVtZW50LmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgaWYgKGhpID49IDEgJiYgaGlCb3VuZHMudG9wID4gcG9zaXRpb24pIHtcbiAgICAgICAgY29uc3QgbG9FbGVtZW50ID0gbGluZXNbbG9dO1xuICAgICAgICByZXR1cm4geyBwcmV2aW91czogbG9FbGVtZW50LCBuZXh0OiBoaUVsZW1lbnQgfTtcbiAgICB9XG4gICAgcmV0dXJuIHsgcHJldmlvdXM6IGhpRWxlbWVudCB9O1xufVxuZXhwb3J0cy5nZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQgPSBnZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQ7XG4vKipcbiAqIEF0dGVtcHQgdG8gcmV2ZWFsIHRoZSBlbGVtZW50IGZvciBhIHNvdXJjZSBsaW5lIGluIHRoZSBlZGl0b3IuXG4gKi9cbmZ1bmN0aW9uIHNjcm9sbFRvUmV2ZWFsU291cmNlTGluZShsaW5lKSB7XG4gICAgaWYgKCFzZXR0aW5nc18xLmdldFNldHRpbmdzKCkuc2Nyb2xsUHJldmlld1dpdGhFZGl0b3IpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAobGluZSA8PSAwKSB7XG4gICAgICAgIHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIDApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHsgcHJldmlvdXMsIG5leHQgfSA9IGdldEVsZW1lbnRzRm9yU291cmNlTGluZShsaW5lKTtcbiAgICBpZiAoIXByZXZpb3VzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IHNjcm9sbFRvID0gMDtcbiAgICBjb25zdCByZWN0ID0gcHJldmlvdXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBwcmV2aW91c1RvcCA9IHJlY3QudG9wO1xuICAgIGlmIChuZXh0ICYmIG5leHQubGluZSAhPT0gcHJldmlvdXMubGluZSkge1xuICAgICAgICAvLyBCZXR3ZWVuIHR3byBlbGVtZW50cy4gR28gdG8gcGVyY2VudGFnZSBvZmZzZXQgYmV0d2VlbiB0aGVtLlxuICAgICAgICBjb25zdCBiZXR3ZWVuUHJvZ3Jlc3MgPSAobGluZSAtIHByZXZpb3VzLmxpbmUpIC8gKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuICAgICAgICBjb25zdCBlbGVtZW50T2Zmc2V0ID0gbmV4dC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIHByZXZpb3VzVG9wO1xuICAgICAgICBzY3JvbGxUbyA9IHByZXZpb3VzVG9wICsgYmV0d2VlblByb2dyZXNzICogZWxlbWVudE9mZnNldDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IHByb2dyZXNzSW5FbGVtZW50ID0gbGluZSAtIE1hdGguZmxvb3IobGluZSk7XG4gICAgICAgIHNjcm9sbFRvID0gcHJldmlvdXNUb3AgKyAocmVjdC5oZWlnaHQgKiBwcm9ncmVzc0luRWxlbWVudCk7XG4gICAgfVxuICAgIHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIE1hdGgubWF4KDEsIHdpbmRvdy5zY3JvbGxZICsgc2Nyb2xsVG8pKTtcbn1cbmV4cG9ydHMuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lID0gc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lO1xuZnVuY3Rpb24gZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQob2Zmc2V0KSB7XG4gICAgY29uc3QgeyBwcmV2aW91cywgbmV4dCB9ID0gZ2V0TGluZUVsZW1lbnRzQXRQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHByZXZpb3VzKSB7XG4gICAgICAgIGNvbnN0IHByZXZpb3VzQm91bmRzID0gcHJldmlvdXMuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgY29uc3Qgb2Zmc2V0RnJvbVByZXZpb3VzID0gKG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZIC0gcHJldmlvdXNCb3VuZHMudG9wKTtcbiAgICAgICAgaWYgKG5leHQpIHtcbiAgICAgICAgICAgIGNvbnN0IHByb2dyZXNzQmV0d2VlbkVsZW1lbnRzID0gb2Zmc2V0RnJvbVByZXZpb3VzIC8gKG5leHQuZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AgLSBwcmV2aW91c0JvdW5kcy50b3ApO1xuICAgICAgICAgICAgY29uc3QgbGluZSA9IHByZXZpb3VzLmxpbmUgKyBwcm9ncmVzc0JldHdlZW5FbGVtZW50cyAqIChuZXh0LmxpbmUgLSBwcmV2aW91cy5saW5lKTtcbiAgICAgICAgICAgIHJldHVybiBjbGFtcExpbmUobGluZSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBwcm9ncmVzc1dpdGhpbkVsZW1lbnQgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAocHJldmlvdXNCb3VuZHMuaGVpZ2h0KTtcbiAgICAgICAgICAgIGNvbnN0IGxpbmUgPSBwcmV2aW91cy5saW5lICsgcHJvZ3Jlc3NXaXRoaW5FbGVtZW50O1xuICAgICAgICAgICAgcmV0dXJuIGNsYW1wTGluZShsaW5lKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbn1cbmV4cG9ydHMuZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQgPSBnZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldDtcbi8qKlxuICogVHJ5IHRvIGZpbmQgdGhlIGh0bWwgZWxlbWVudCBieSB1c2luZyBhIGZyYWdtZW50IGlkXG4gKi9cbmZ1bmN0aW9uIGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQoZnJhZ21lbnQpIHtcbiAgICByZXR1cm4gZ2V0Q29kZUxpbmVFbGVtZW50cygpLmZpbmQoKGVsZW1lbnQpID0+IHtcbiAgICAgICAgcmV0dXJuIGVsZW1lbnQuZWxlbWVudC5pZCA9PT0gZnJhZ21lbnQ7XG4gICAgfSk7XG59XG5leHBvcnRzLmdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQgPSBnZXRMaW5lRWxlbWVudEZvckZyYWdtZW50O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmxldCBjYWNoZWRTZXR0aW5ncyA9IHVuZGVmaW5lZDtcbmZ1bmN0aW9uIGdldERhdGEoa2V5KSB7XG4gICAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZGF0YSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKGtleSk7XG4gICAgICAgIGlmIChkYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShkYXRhKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBsb2FkIGRhdGEgZm9yICR7a2V5fWApO1xufVxuZXhwb3J0cy5nZXREYXRhID0gZ2V0RGF0YTtcbmZ1bmN0aW9uIGdldFNldHRpbmdzKCkge1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIGNhY2hlZFNldHRpbmdzID0gZ2V0RGF0YSgnZGF0YS1zZXR0aW5ncycpO1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGxvYWQgc2V0dGluZ3MnKTtcbn1cbmV4cG9ydHMuZ2V0U2V0dGluZ3MgPSBnZXRTZXR0aW5ncztcbiJdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file +!function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=2)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});let o=void 0;function i(e){const t=document.getElementById("vscode-markdown-preview-data");if(t){const n=t.getAttribute(e);if(n)return JSON.parse(n)}throw new Error(`Could not load data for ${e}`)}t.getData=i,t.getSettings=function(){if(o)return o;if(o=i("data-settings"))return o;throw new Error("Could not load settings")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(0);function i(e){return t=0,n=o.getSettings().lineCount-1,i=e,Math.min(n,Math.max(t,i));var t,n,i}const r=(()=>{let e;return()=>{if(!e){e=[{element:document.body,line:0}];for(const t of document.getElementsByClassName("code-line")){const n=+t.getAttribute("data-line");isNaN(n)||("CODE"===t.tagName&&t.parentElement&&"PRE"===t.parentElement.tagName?e.push({element:t.parentElement,line:n}):e.push({element:t,line:n}))}}return e}})();function s(e){const t=Math.floor(e),n=r();let o=n[0]||null;for(const e of n){if(e.line===t)return{previous:e,next:void 0};if(e.line>t)return{previous:o,next:e};o=e}return{previous:o}}function c(e){const t=r(),n=e-window.scrollY;let o=-1,i=t.length-1;for(;o+1=n?i=e:o=e}const s=t[i],c=s.element.getBoundingClientRect();if(i>=1&&c.top>n){return{previous:t[o],next:s}}return i>1&&in?{previous:s,next:t[i+1]}:{previous:s}}t.getElementsForSourceLine=s,t.getLineElementsAtPageOffset=c,t.scrollToRevealSourceLine=function(e){if(!o.getSettings().scrollPreviewWithEditor)return;if(e<=0)return void window.scroll(window.scrollX,0);const{previous:t,next:n}=s(e);if(!t)return;let i=0;const r=t.element.getBoundingClientRect(),c=r.top;if(n&&n.line!==t.line){i=c+(e-t.line)/(n.line-t.line)*(n.element.getBoundingClientRect().top-c)}else{const t=e-Math.floor(e);i=c+r.height*t}window.scroll(window.scrollX,Math.max(1,window.scrollY+i))},t.getEditorLineNumberForPageOffset=function(e){const{previous:t,next:n}=c(e);if(t){const o=t.element.getBoundingClientRect(),r=e-window.scrollY-o.top;if(n){const e=r/(n.element.getBoundingClientRect().top-o.top);return i(t.line+e*(n.line-t.line))}{const e=r/o.height;return i(t.line+e)}}return null},t.getLineElementForFragment=function(e){return r().find(t=>t.element.id===e)}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(3),i=n(4),r=n(5),s=n(1),c=n(0),a=n(6);let u=!0;const l=new o.ActiveLineMarker,d=c.getSettings(),f=acquireVsCodeApi();let g=c.getData("data-state");f.setState(g);const p=r.createPosterForVsCode(f);window.cspAlerter.setPoster(p),window.styleLoadingMonitor.setPoster(p),window.onload=()=>{v()},i.onceDocumentLoaded(()=>{d.scrollPreviewWithEditor&&setTimeout(()=>{if(g.fragment){const e=s.getLineElementForFragment(g.fragment);e&&(u=!0,s.scrollToRevealSourceLine(e.line))}else{const e=+d.line;isNaN(e)||(u=!0,s.scrollToRevealSourceLine(e))}},0)});const m=(()=>{const e=a(e=>{u=!0,s.scrollToRevealSourceLine(e)},50);return(t,n)=>{isNaN(t)||(n.line=t,e(t))}})();let v=a(()=>{const e=[];let t=document.getElementsByTagName("img");if(t){let n;for(n=0;n{u=!0,v()},!0),window.addEventListener("message",e=>{if(e.data.source===d.source)switch(e.data.type){case"onDidChangeTextEditorSelection":l.onDidChangeTextEditorSelection(e.data.line);break;case"updateView":m(e.data.line,d)}},!1),document.addEventListener("dblclick",e=>{if(!d.doubleClickToSwitchToEditor)return;for(let t=e.target;t;t=t.parentNode)if("A"===t.tagName)return;const t=e.pageY,n=s.getEditorLineNumberForPageOffset(t);"number"!=typeof n||isNaN(n)||p.postMessage("didClick",{line:Math.floor(n)})});const h=["http:","https:","mailto:","vscode:","vscode-insiders:"];document.addEventListener("click",e=>{if(!e)return;let t=e.target;for(;t;){if(t.tagName&&"A"===t.tagName&&t.href){if(t.getAttribute("href").startsWith("#"))return;if(h.some(e=>t.href.startsWith(e)))return;const n=t.getAttribute("data-href")||t.getAttribute("href");return/^[a-z\-]+:/i.test(n)?void 0:(p.postMessage("openLink",{href:n}),e.preventDefault(),void e.stopPropagation())}t=t.parentNode}},!0),window.addEventListener("scroll",a(()=>{if(u)u=!1;else{const e=s.getEditorLineNumberForPageOffset(window.scrollY);"number"!=typeof e||isNaN(e)||(p.postMessage("revealLine",{line:e}),g.line=e,f.setState(g))}},50))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(1);t.ActiveLineMarker=class{onDidChangeTextEditorSelection(e){const{previous:t}=o.getElementsForSourceLine(e);this._update(t&&t.element)}_update(e){this._unmarkActiveElement(this._current),this._markActiveElement(e),this._current=e}_unmarkActiveElement(e){e&&(e.className=e.className.replace(/\bcode-active-line\b/g,""))}_markActiveElement(e){e&&(e.className+=" code-active-line")}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.onceDocumentLoaded=function(e){"loading"===document.readyState||"uninitialized"===document.readyState?document.addEventListener("DOMContentLoaded",e):e()}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(0);t.createPosterForVsCode=e=>new class{postMessage(t,n){e.postMessage({type:t,source:o.getSettings().source,body:n})}}},function(e,t,n){(function(t){var n="Expected a function",o=NaN,i="[object Symbol]",r=/^\s+|\s+$/g,s=/^[-+]0x[0-9a-f]+$/i,c=/^0b[01]+$/i,a=/^0o[0-7]+$/i,u=parseInt,l="object"==typeof t&&t&&t.Object===Object&&t,d="object"==typeof self&&self&&self.Object===Object&&self,f=l||d||Function("return this")(),g=Object.prototype.toString,p=Math.max,m=Math.min,v=function(){return f.Date.now()};function h(e,t,o){var i,r,s,c,a,u,l=0,d=!1,f=!1,g=!0;if("function"!=typeof e)throw new TypeError(n);function h(t){var n=i,o=r;return i=r=void 0,l=t,c=e.apply(o,n)}function y(e){var n=e-u;return void 0===u||n>=t||n<0||f&&e-l>=s}function E(){var e=v();if(y(e))return M(e);a=setTimeout(E,function(e){var n=t-(e-u);return f?m(n,s-(e-l)):n}(e))}function M(e){return a=void 0,g&&i?h(e):(i=r=void 0,c)}function L(){var e=v(),n=y(e);if(i=arguments,r=this,u=e,n){if(void 0===a)return function(e){return l=e,a=setTimeout(E,t),d?h(e):c}(u);if(f)return a=setTimeout(E,t),h(u)}return void 0===a&&(a=setTimeout(E,t)),c}return t=b(t)||0,w(o)&&(d=!!o.leading,s=(f="maxWait"in o)?p(b(o.maxWait)||0,t):s,g="trailing"in o?!!o.trailing:g),L.cancel=function(){void 0!==a&&clearTimeout(a),l=0,i=u=r=a=void 0},L.flush=function(){return void 0===a?c:M(v())},L}function w(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function b(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&g.call(e)==i}(e))return o;if(w(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=w(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(r,"");var n=c.test(e);return n||a.test(e)?u(e.slice(2),n?2:8):s.test(e)?o:+e}e.exports=function(e,t,o){var i=!0,r=!0;if("function"!=typeof e)throw new TypeError(n);return w(o)&&(i="leading"in o?!!o.leading:i,r="trailing"in o?!!o.trailing:r),h(e,t,{leading:i,maxWait:t,trailing:r})}}).call(this,n(7))},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n}]); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvc2V0dGluZ3MudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvc2Nyb2xsLXN5bmMudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvYWN0aXZlTGluZU1hcmtlci50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9ldmVudHMudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvbWVzc2FnaW5nLnRzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9sb2Rhc2gudGhyb3R0bGUvaW5kZXguanMiLCJ3ZWJwYWNrOi8vLyh3ZWJwYWNrKS9idWlsZGluL2dsb2JhbC5qcyJdLCJuYW1lcyI6WyJpbnN0YWxsZWRNb2R1bGVzIiwiX193ZWJwYWNrX3JlcXVpcmVfXyIsIm1vZHVsZUlkIiwiZXhwb3J0cyIsIm1vZHVsZSIsImkiLCJsIiwibW9kdWxlcyIsImNhbGwiLCJtIiwiYyIsImQiLCJuYW1lIiwiZ2V0dGVyIiwibyIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZW51bWVyYWJsZSIsImdldCIsInIiLCJTeW1ib2wiLCJ0b1N0cmluZ1RhZyIsInZhbHVlIiwidCIsIm1vZGUiLCJfX2VzTW9kdWxlIiwibnMiLCJjcmVhdGUiLCJrZXkiLCJiaW5kIiwibiIsIm9iamVjdCIsInByb3BlcnR5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJwIiwicyIsImNhY2hlZFNldHRpbmdzIiwidW5kZWZpbmVkIiwiZ2V0RGF0YSIsImVsZW1lbnQiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwiZGF0YSIsImdldEF0dHJpYnV0ZSIsIkpTT04iLCJwYXJzZSIsIkVycm9yIiwiZ2V0U2V0dGluZ3MiLCJzZXR0aW5nc18xIiwiY2xhbXBMaW5lIiwibGluZSIsIm1pbiIsIm1heCIsImxpbmVDb3VudCIsIk1hdGgiLCJnZXRDb2RlTGluZUVsZW1lbnRzIiwiZWxlbWVudHMiLCJib2R5IiwiZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSIsImlzTmFOIiwidGFnTmFtZSIsInBhcmVudEVsZW1lbnQiLCJwdXNoIiwiZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lIiwidGFyZ2V0TGluZSIsImxpbmVOdW1iZXIiLCJmbG9vciIsImxpbmVzIiwicHJldmlvdXMiLCJlbnRyeSIsIm5leHQiLCJnZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQiLCJvZmZzZXQiLCJwb3NpdGlvbiIsIndpbmRvdyIsInNjcm9sbFkiLCJsbyIsImhpIiwibGVuZ3RoIiwibWlkIiwiYm91bmRzIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidG9wIiwiaGVpZ2h0IiwiaGlFbGVtZW50IiwiaGlCb3VuZHMiLCJzY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUiLCJzY3JvbGxQcmV2aWV3V2l0aEVkaXRvciIsInNjcm9sbCIsInNjcm9sbFgiLCJzY3JvbGxUbyIsInJlY3QiLCJwcmV2aW91c1RvcCIsInByb2dyZXNzSW5FbGVtZW50IiwiZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQiLCJwcmV2aW91c0JvdW5kcyIsIm9mZnNldEZyb21QcmV2aW91cyIsInByb2dyZXNzQmV0d2VlbkVsZW1lbnRzIiwicHJvZ3Jlc3NXaXRoaW5FbGVtZW50IiwiZ2V0TGluZUVsZW1lbnRGb3JGcmFnbWVudCIsImZyYWdtZW50IiwiZmluZCIsImlkIiwiYWN0aXZlTGluZU1hcmtlcl8xIiwiZXZlbnRzXzEiLCJtZXNzYWdpbmdfMSIsInNjcm9sbF9zeW5jXzEiLCJ0aHJvdHRsZSIsInNjcm9sbERpc2FibGVkIiwibWFya2VyIiwiQWN0aXZlTGluZU1hcmtlciIsInNldHRpbmdzIiwidnNjb2RlIiwiYWNxdWlyZVZzQ29kZUFwaSIsInN0YXRlIiwic2V0U3RhdGUiLCJtZXNzYWdpbmciLCJjcmVhdGVQb3N0ZXJGb3JWc0NvZGUiLCJjc3BBbGVydGVyIiwic2V0UG9zdGVyIiwic3R5bGVMb2FkaW5nTW9uaXRvciIsIm9ubG9hZCIsInVwZGF0ZUltYWdlU2l6ZXMiLCJvbmNlRG9jdW1lbnRMb2FkZWQiLCJzZXRUaW1lb3V0IiwiaW5pdGlhbExpbmUiLCJvblVwZGF0ZVZpZXciLCJkb1Njcm9sbCIsImltYWdlSW5mbyIsImltYWdlcyIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwiaW1nIiwiY2xhc3NMaXN0IiwiY29udGFpbnMiLCJyZW1vdmUiLCJ3aWR0aCIsInBvc3RNZXNzYWdlIiwiYWRkRXZlbnRMaXN0ZW5lciIsImV2ZW50Iiwic291cmNlIiwidHlwZSIsIm9uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbiIsImRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvciIsIm5vZGUiLCJ0YXJnZXQiLCJwYXJlbnROb2RlIiwicGFnZVkiLCJwYXNzVGhyb3VnaExpbmtTY2hlbWVzIiwiaHJlZiIsInN0YXJ0c1dpdGgiLCJzb21lIiwic2NoZW1lIiwiaHJlZlRleHQiLCJ0ZXN0IiwicHJldmVudERlZmF1bHQiLCJzdG9wUHJvcGFnYXRpb24iLCJ0aGlzIiwiX3VwZGF0ZSIsImJlZm9yZSIsIl91bm1hcmtBY3RpdmVFbGVtZW50IiwiX2N1cnJlbnQiLCJfbWFya0FjdGl2ZUVsZW1lbnQiLCJjbGFzc05hbWUiLCJyZXBsYWNlIiwiZiIsInJlYWR5U3RhdGUiLCJGVU5DX0VSUk9SX1RFWFQiLCJOQU4iLCJzeW1ib2xUYWciLCJyZVRyaW0iLCJyZUlzQmFkSGV4IiwicmVJc0JpbmFyeSIsInJlSXNPY3RhbCIsImZyZWVQYXJzZUludCIsInBhcnNlSW50IiwiZnJlZUdsb2JhbCIsImdsb2JhbCIsImZyZWVTZWxmIiwic2VsZiIsInJvb3QiLCJGdW5jdGlvbiIsIm9iamVjdFRvU3RyaW5nIiwidG9TdHJpbmciLCJuYXRpdmVNYXgiLCJuYXRpdmVNaW4iLCJub3ciLCJEYXRlIiwiZGVib3VuY2UiLCJmdW5jIiwid2FpdCIsIm9wdGlvbnMiLCJsYXN0QXJncyIsImxhc3RUaGlzIiwibWF4V2FpdCIsInJlc3VsdCIsInRpbWVySWQiLCJsYXN0Q2FsbFRpbWUiLCJsYXN0SW52b2tlVGltZSIsImxlYWRpbmciLCJtYXhpbmciLCJ0cmFpbGluZyIsIlR5cGVFcnJvciIsImludm9rZUZ1bmMiLCJ0aW1lIiwiYXJncyIsInRoaXNBcmciLCJhcHBseSIsInNob3VsZEludm9rZSIsInRpbWVTaW5jZUxhc3RDYWxsIiwidGltZXJFeHBpcmVkIiwidHJhaWxpbmdFZGdlIiwicmVtYWluaW5nV2FpdCIsImRlYm91bmNlZCIsImlzSW52b2tpbmciLCJhcmd1bWVudHMiLCJsZWFkaW5nRWRnZSIsInRvTnVtYmVyIiwiaXNPYmplY3QiLCJjYW5jZWwiLCJjbGVhclRpbWVvdXQiLCJmbHVzaCIsImlzT2JqZWN0TGlrZSIsImlzU3ltYm9sIiwib3RoZXIiLCJ2YWx1ZU9mIiwiaXNCaW5hcnkiLCJzbGljZSIsImciLCJlIl0sIm1hcHBpbmdzIjoiYUFDRSxJQUFJQSxFQUFtQixHQUd2QixTQUFTQyxFQUFvQkMsR0FHNUIsR0FBR0YsRUFBaUJFLEdBQ25CLE9BQU9GLEVBQWlCRSxHQUFVQyxRQUduQyxJQUFJQyxFQUFTSixFQUFpQkUsR0FBWSxDQUN6Q0csRUFBR0gsRUFDSEksR0FBRyxFQUNISCxRQUFTLElBVVYsT0FOQUksRUFBUUwsR0FBVU0sS0FBS0osRUFBT0QsUUFBU0MsRUFBUUEsRUFBT0QsUUFBU0YsR0FHL0RHLEVBQU9FLEdBQUksRUFHSkYsRUFBT0QsUUFLZkYsRUFBb0JRLEVBQUlGLEVBR3hCTixFQUFvQlMsRUFBSVYsRUFHeEJDLEVBQW9CVSxFQUFJLFNBQVNSLEVBQVNTLEVBQU1DLEdBQzNDWixFQUFvQmEsRUFBRVgsRUFBU1MsSUFDbENHLE9BQU9DLGVBQWViLEVBQVNTLEVBQU0sQ0FBRUssWUFBWSxFQUFNQyxJQUFLTCxLQUtoRVosRUFBb0JrQixFQUFJLFNBQVNoQixHQUNYLG9CQUFYaUIsUUFBMEJBLE9BQU9DLGFBQzFDTixPQUFPQyxlQUFlYixFQUFTaUIsT0FBT0MsWUFBYSxDQUFFQyxNQUFPLFdBRTdEUCxPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sS0FRdkRyQixFQUFvQnNCLEVBQUksU0FBU0QsRUFBT0UsR0FFdkMsR0FEVSxFQUFQQSxJQUFVRixFQUFRckIsRUFBb0JxQixJQUMvQixFQUFQRSxFQUFVLE9BQU9GLEVBQ3BCLEdBQVcsRUFBUEUsR0FBOEIsaUJBQVZGLEdBQXNCQSxHQUFTQSxFQUFNRyxXQUFZLE9BQU9ILEVBQ2hGLElBQUlJLEVBQUtYLE9BQU9ZLE9BQU8sTUFHdkIsR0FGQTFCLEVBQW9Ca0IsRUFBRU8sR0FDdEJYLE9BQU9DLGVBQWVVLEVBQUksVUFBVyxDQUFFVCxZQUFZLEVBQU1LLE1BQU9BLElBQ3RELEVBQVBFLEdBQTRCLGlCQUFURixFQUFtQixJQUFJLElBQUlNLEtBQU9OLEVBQU9yQixFQUFvQlUsRUFBRWUsRUFBSUUsRUFBSyxTQUFTQSxHQUFPLE9BQU9OLEVBQU1NLElBQVFDLEtBQUssS0FBTUQsSUFDOUksT0FBT0YsR0FJUnpCLEVBQW9CNkIsRUFBSSxTQUFTMUIsR0FDaEMsSUFBSVMsRUFBU1QsR0FBVUEsRUFBT3FCLFdBQzdCLFdBQXdCLE9BQU9yQixFQUFnQixTQUMvQyxXQUE4QixPQUFPQSxHQUV0QyxPQURBSCxFQUFvQlUsRUFBRUUsRUFBUSxJQUFLQSxHQUM1QkEsR0FJUlosRUFBb0JhLEVBQUksU0FBU2lCLEVBQVFDLEdBQVksT0FBT2pCLE9BQU9rQixVQUFVQyxlQUFlMUIsS0FBS3VCLEVBQVFDLElBR3pHL0IsRUFBb0JrQyxFQUFJLEdBSWpCbEMsRUFBb0JBLEVBQW9CbUMsRUFBSSxHLCtCQzdFckRyQixPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sSUFDdEQsSUFBSWUsT0FBaUJDLEVBQ3JCLFNBQVNDLEVBQVFYLEdBQ2IsTUFBTVksRUFBVUMsU0FBU0MsZUFBZSxnQ0FDeEMsR0FBSUYsRUFBUyxDQUNULE1BQU1HLEVBQU9ILEVBQVFJLGFBQWFoQixHQUNsQyxHQUFJZSxFQUNBLE9BQU9FLEtBQUtDLE1BQU1ILEdBRzFCLE1BQU0sSUFBSUksTUFBTSwyQkFBMkJuQixLQUUvQ3pCLEVBQVFvQyxRQUFVQSxFQVdsQnBDLEVBQVE2QyxZQVZSLFdBQ0ksR0FBSVgsRUFDQSxPQUFPQSxFQUdYLEdBREFBLEVBQWlCRSxFQUFRLGlCQUVyQixPQUFPRixFQUVYLE1BQU0sSUFBSVUsTUFBTSw2Qiw2QkNyQnBCaEMsT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBQ3RELE1BQU0yQixFQUFhLEVBQVEsR0FJM0IsU0FBU0MsRUFBVUMsR0FDZixPQUpXQyxFQUlFLEVBSkdDLEVBSUFKLEVBQVdELGNBQWNNLFVBQVksRUFKaENoQyxFQUltQzZCLEVBSGpESSxLQUFLSCxJQUFJQyxFQUFLRSxLQUFLRixJQUFJRCxFQUFLOUIsSUFEdkMsSUFBZThCLEVBQUtDLEVBQUsvQixFQU16QixNQUFNa0MsRUFBc0IsTUFDeEIsSUFBSUMsRUFDSixNQUFPLEtBQ0gsSUFBS0EsRUFBVSxDQUNYQSxFQUFXLENBQUMsQ0FBRWpCLFFBQVNDLFNBQVNpQixLQUFNUCxLQUFNLElBQzVDLElBQUssTUFBTVgsS0FBV0MsU0FBU2tCLHVCQUF1QixhQUFjLENBQ2hFLE1BQU1SLEdBQVFYLEVBQVFJLGFBQWEsYUFDL0JnQixNQUFNVCxLQUdjLFNBQXBCWCxFQUFRcUIsU0FBc0JyQixFQUFRc0IsZUFBbUQsUUFBbEN0QixFQUFRc0IsY0FBY0QsUUFHN0VKLEVBQVNNLEtBQUssQ0FBRXZCLFFBQVNBLEVBQVFzQixjQUFlWCxTQUdoRE0sRUFBU00sS0FBSyxDQUFFdkIsUUFBU0EsRUFBU1csV0FJOUMsT0FBT00sSUFwQmEsR0E2QjVCLFNBQVNPLEVBQXlCQyxHQUM5QixNQUFNQyxFQUFhWCxLQUFLWSxNQUFNRixHQUN4QkcsRUFBUVosSUFDZCxJQUFJYSxFQUFXRCxFQUFNLElBQU0sS0FDM0IsSUFBSyxNQUFNRSxLQUFTRixFQUFPLENBQ3ZCLEdBQUlFLEVBQU1uQixPQUFTZSxFQUNmLE1BQU8sQ0FBRUcsU0FBVUMsRUFBT0MsVUFBTWpDLEdBRS9CLEdBQUlnQyxFQUFNbkIsS0FBT2UsRUFDbEIsTUFBTyxDQUFFRyxXQUFVRSxLQUFNRCxHQUU3QkQsRUFBV0MsRUFFZixNQUFPLENBQUVELFlBTWIsU0FBU0csRUFBNEJDLEdBQ2pDLE1BQU1MLEVBQVFaLElBQ1JrQixFQUFXRCxFQUFTRSxPQUFPQyxRQUNqQyxJQUFJQyxHQUFNLEVBQ05DLEVBQUtWLEVBQU1XLE9BQVMsRUFDeEIsS0FBT0YsRUFBSyxFQUFJQyxHQUFJLENBQ2hCLE1BQU1FLEVBQU16QixLQUFLWSxPQUFPVSxFQUFLQyxHQUFNLEdBQzdCRyxFQUFTYixFQUFNWSxHQUFLeEMsUUFBUTBDLHdCQUM5QkQsRUFBT0UsSUFBTUYsRUFBT0csUUFBVVYsRUFDOUJJLEVBQUtFLEVBR0xILEVBQUtHLEVBR2IsTUFBTUssRUFBWWpCLEVBQU1VLEdBQ2xCUSxFQUFXRCxFQUFVN0MsUUFBUTBDLHdCQUNuQyxHQUFJSixHQUFNLEdBQUtRLEVBQVNILElBQU1ULEVBQVUsQ0FFcEMsTUFBTyxDQUFFTCxTQURTRCxFQUFNUyxHQUNNTixLQUFNYyxHQUV4QyxPQUFJUCxFQUFLLEdBQUtBLEVBQUtWLEVBQU1XLFFBQVVPLEVBQVNILElBQU1HLEVBQVNGLE9BQVNWLEVBQ3pELENBQUVMLFNBQVVnQixFQUFXZCxLQUFNSCxFQUFNVSxFQUFLLElBRTVDLENBQUVULFNBQVVnQixHQTVCdkJsRixFQUFRNkQseUJBQTJCQSxFQThCbkM3RCxFQUFRcUUsNEJBQThCQSxFQStCdENyRSxFQUFRb0YseUJBM0JSLFNBQWtDcEMsR0FDOUIsSUFBS0YsRUFBV0QsY0FBY3dDLHdCQUMxQixPQUVKLEdBQUlyQyxHQUFRLEVBRVIsWUFEQXdCLE9BQU9jLE9BQU9kLE9BQU9lLFFBQVMsR0FHbEMsTUFBTSxTQUFFckIsRUFBUSxLQUFFRSxHQUFTUCxFQUF5QmIsR0FDcEQsSUFBS2tCLEVBQ0QsT0FFSixJQUFJc0IsRUFBVyxFQUNmLE1BQU1DLEVBQU92QixFQUFTN0IsUUFBUTBDLHdCQUN4QlcsRUFBY0QsRUFBS1QsSUFDekIsR0FBSVosR0FBUUEsRUFBS3BCLE9BQVNrQixFQUFTbEIsS0FBTSxDQUlyQ3dDLEVBQVdFLEdBRmMxQyxFQUFPa0IsRUFBU2xCLE9BQVNvQixFQUFLcEIsS0FBT2tCLEVBQVNsQixPQUNqRG9CLEVBQUsvQixRQUFRMEMsd0JBQXdCQyxJQUFNVSxPQUdoRSxDQUNELE1BQU1DLEVBQW9CM0MsRUFBT0ksS0FBS1ksTUFBTWhCLEdBQzVDd0MsRUFBV0UsRUFBZUQsRUFBS1IsT0FBU1UsRUFFNUNuQixPQUFPYyxPQUFPZCxPQUFPZSxRQUFTbkMsS0FBS0YsSUFBSSxFQUFHc0IsT0FBT0MsUUFBVWUsS0FxQi9EeEYsRUFBUTRGLGlDQWxCUixTQUEwQ3RCLEdBQ3RDLE1BQU0sU0FBRUosRUFBUSxLQUFFRSxHQUFTQyxFQUE0QkMsR0FDdkQsR0FBSUosRUFBVSxDQUNWLE1BQU0yQixFQUFpQjNCLEVBQVM3QixRQUFRMEMsd0JBQ2xDZSxFQUFzQnhCLEVBQVNFLE9BQU9DLFFBQVVvQixFQUFlYixJQUNyRSxHQUFJWixFQUFNLENBQ04sTUFBTTJCLEVBQTBCRCxHQUFzQjFCLEVBQUsvQixRQUFRMEMsd0JBQXdCQyxJQUFNYSxFQUFlYixLQUVoSCxPQUFPakMsRUFETW1CLEVBQVNsQixLQUFPK0MsR0FBMkIzQixFQUFLcEIsS0FBT2tCLEVBQVNsQixPQUc1RSxDQUNELE1BQU1nRCxFQUF3QkYsRUFBc0JELEVBQXFCLE9BRXpFLE9BQU85QyxFQURNbUIsRUFBU2xCLEtBQU9nRCxJQUlyQyxPQUFPLE1BV1hoRyxFQUFRaUcsMEJBTFIsU0FBbUNDLEdBQy9CLE9BQU83QyxJQUFzQjhDLEtBQU05RCxHQUN4QkEsRUFBUUEsUUFBUStELEtBQU9GLEssNkJDMUl0Q3RGLE9BQU9DLGVBQWViLEVBQVMsYUFBYyxDQUFFbUIsT0FBTyxJQUN0RCxNQUFNa0YsRUFBcUIsRUFBUSxHQUM3QkMsRUFBVyxFQUFRLEdBQ25CQyxFQUFjLEVBQVEsR0FDdEJDLEVBQWdCLEVBQVEsR0FDeEIxRCxFQUFhLEVBQVEsR0FDckIyRCxFQUFXLEVBQVEsR0FDekIsSUFBSUMsR0FBaUIsRUFDckIsTUFBTUMsRUFBUyxJQUFJTixFQUFtQk8saUJBQ2hDQyxFQUFXL0QsRUFBV0QsY0FDdEJpRSxFQUFTQyxtQkFFZixJQUFJQyxFQUFRbEUsRUFBV1YsUUFBUSxjQUMvQjBFLEVBQU9HLFNBQVNELEdBQ2hCLE1BQU1FLEVBQVlYLEVBQVlZLHNCQUFzQkwsR0FDcER0QyxPQUFPNEMsV0FBV0MsVUFBVUgsR0FDNUIxQyxPQUFPOEMsb0JBQW9CRCxVQUFVSCxHQUNyQzFDLE9BQU8rQyxPQUFTLEtBQ1pDLEtBRUpsQixFQUFTbUIsbUJBQW1CLEtBQ3BCWixFQUFTeEIseUJBQ1RxQyxXQUFXLEtBRVAsR0FBSVYsRUFBTWQsU0FBVSxDQUNoQixNQUFNN0QsRUFBVW1FLEVBQWNQLDBCQUEwQmUsRUFBTWQsVUFDMUQ3RCxJQUNBcUUsR0FBaUIsRUFDakJGLEVBQWNwQix5QkFBeUIvQyxFQUFRVyxXQUdsRCxDQUNELE1BQU0yRSxHQUFlZCxFQUFTN0QsS0FDekJTLE1BQU1rRSxLQUNQakIsR0FBaUIsRUFDakJGLEVBQWNwQix5QkFBeUJ1QyxNQUdoRCxLQUdYLE1BQU1DLEVBQWUsTUFDakIsTUFBTUMsRUFBV3BCLEVBQVV6RCxJQUN2QjBELEdBQWlCLEVBQ2pCRixFQUFjcEIseUJBQXlCcEMsSUFDeEMsSUFDSCxNQUFPLENBQUNBLEVBQU02RCxLQUNMcEQsTUFBTVQsS0FDUDZELEVBQVM3RCxLQUFPQSxFQUNoQjZFLEVBQVM3RSxNQVJBLEdBWXJCLElBQUl3RSxFQUFtQmYsRUFBUyxLQUM1QixNQUFNcUIsRUFBWSxHQUNsQixJQUFJQyxFQUFTekYsU0FBUzBGLHFCQUFxQixPQUMzQyxHQUFJRCxFQUFRLENBQ1IsSUFBSTdILEVBQ0osSUFBS0EsRUFBSSxFQUFHQSxFQUFJNkgsRUFBT25ELE9BQVExRSxJQUFLLENBQ2hDLE1BQU0rSCxFQUFNRixFQUFPN0gsR0FDZitILEVBQUlDLFVBQVVDLFNBQVMsWUFDdkJGLEVBQUlDLFVBQVVFLE9BQU8sV0FFekJOLEVBQVVsRSxLQUFLLENBQ1h3QyxHQUFJNkIsRUFBSTdCLEdBQ1JuQixPQUFRZ0QsRUFBSWhELE9BQ1pvRCxNQUFPSixFQUFJSSxRQUduQm5CLEVBQVVvQixZQUFZLGtCQUFtQlIsS0FFOUMsSUFDSHRELE9BQU8rRCxpQkFBaUIsU0FBVSxLQUM5QjdCLEdBQWlCLEVBQ2pCYyxNQUNELEdBQ0hoRCxPQUFPK0QsaUJBQWlCLFVBQVdDLElBQy9CLEdBQUlBLEVBQU1oRyxLQUFLaUcsU0FBVzVCLEVBQVM0QixPQUduQyxPQUFRRCxFQUFNaEcsS0FBS2tHLE1BQ2YsSUFBSyxpQ0FDRC9CLEVBQU9nQywrQkFBK0JILEVBQU1oRyxLQUFLUSxNQUNqRCxNQUNKLElBQUssYUFDRDRFLEVBQWFZLEVBQU1oRyxLQUFLUSxLQUFNNkQsTUFHdkMsR0FDSHZFLFNBQVNpRyxpQkFBaUIsV0FBWUMsSUFDbEMsSUFBSzNCLEVBQVMrQiw0QkFDVixPQUdKLElBQUssSUFBSUMsRUFBT0wsRUFBTU0sT0FBUUQsRUFBTUEsRUFBT0EsRUFBS0UsV0FDNUMsR0FBcUIsTUFBakJGLEVBQUtuRixRQUNMLE9BR1IsTUFBTVksRUFBU2tFLEVBQU1RLE1BQ2ZoRyxFQUFPd0QsRUFBY1osaUNBQWlDdEIsR0FDeEMsaUJBQVR0QixHQUFzQlMsTUFBTVQsSUFDbkNrRSxFQUFVb0IsWUFBWSxXQUFZLENBQUV0RixLQUFNSSxLQUFLWSxNQUFNaEIsT0FHN0QsTUFBTWlHLEVBQXlCLENBQUMsUUFBUyxTQUFVLFVBQVcsVUFBVyxvQkFDekUzRyxTQUFTaUcsaUJBQWlCLFFBQVNDLElBQy9CLElBQUtBLEVBQ0QsT0FFSixJQUFJSyxFQUFPTCxFQUFNTSxPQUNqQixLQUFPRCxHQUFNLENBQ1QsR0FBSUEsRUFBS25GLFNBQTRCLE1BQWpCbUYsRUFBS25GLFNBQW1CbUYsRUFBS0ssS0FBTSxDQUNuRCxHQUFJTCxFQUFLcEcsYUFBYSxRQUFRMEcsV0FBVyxLQUNyQyxPQUdKLEdBQUlGLEVBQXVCRyxLQUFLQyxHQUFVUixFQUFLSyxLQUFLQyxXQUFXRSxJQUMzRCxPQUVKLE1BQU1DLEVBQVdULEVBQUtwRyxhQUFhLGNBQWdCb0csRUFBS3BHLGFBQWEsUUFFckUsTUFBSyxjQUFjOEcsS0FBS0QsUUFNeEIsR0FMSXBDLEVBQVVvQixZQUFZLFdBQVksQ0FBRVksS0FBTUksSUFDMUNkLEVBQU1nQixzQkFDTmhCLEVBQU1pQixtQkFLZFosRUFBT0EsRUFBS0UsY0FFakIsR0FDSHZFLE9BQU8rRCxpQkFBaUIsU0FBVTlCLEVBQVMsS0FDdkMsR0FBSUMsRUFDQUEsR0FBaUIsTUFFaEIsQ0FDRCxNQUFNMUQsRUFBT3dELEVBQWNaLGlDQUFpQ3BCLE9BQU9DLFNBQy9DLGlCQUFUekIsR0FBc0JTLE1BQU1ULEtBQ25Da0UsRUFBVW9CLFlBQVksYUFBYyxDQUFFdEYsU0FDdENnRSxFQUFNaEUsS0FBT0EsRUFDYjhELEVBQU9HLFNBQVNELE1BR3pCLE0sNkJDckpIcEcsT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBS3RELE1BQU1xRixFQUFnQixFQUFRLEdBd0I5QnhHLEVBQVE0RyxpQkF2QlIsTUFDSSwrQkFBK0I1RCxHQUMzQixNQUFNLFNBQUVrQixHQUFhc0MsRUFBYzNDLHlCQUF5QmIsR0FDNUQwRyxLQUFLQyxRQUFRekYsR0FBWUEsRUFBUzdCLFNBRXRDLFFBQVF1SCxHQUNKRixLQUFLRyxxQkFBcUJILEtBQUtJLFVBQy9CSixLQUFLSyxtQkFBbUJILEdBQ3hCRixLQUFLSSxTQUFXRixFQUVwQixxQkFBcUJ2SCxHQUNaQSxJQUdMQSxFQUFRMkgsVUFBWTNILEVBQVEySCxVQUFVQyxRQUFRLHdCQUF5QixLQUUzRSxtQkFBbUI1SCxHQUNWQSxJQUdMQSxFQUFRMkgsV0FBYSx3Qiw2QkN0QjdCcEosT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBU3REbkIsRUFBUXlILG1CQVJSLFNBQTRCeUMsR0FDSSxZQUF4QjVILFNBQVM2SCxZQUFvRCxrQkFBeEI3SCxTQUFTNkgsV0FDOUM3SCxTQUFTaUcsaUJBQWlCLG1CQUFvQjJCLEdBRzlDQSxNLDZCQ05SdEosT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBQ3RELE1BQU0yQixFQUFhLEVBQVEsR0FDM0I5QyxFQUFRbUgsc0JBQXlCTCxHQUN0QixJQUFJLE1BQ1AsWUFBWTRCLEVBQU1uRixHQUNkdUQsRUFBT3dCLFlBQVksQ0FDZkksT0FDQUQsT0FBUTNGLEVBQVdELGNBQWM0RixPQUNqQ2xGLFksaUJDYmhCLFlBVUEsSUFBSTZHLEVBQWtCLHNCQUdsQkMsRUFBTSxJQUdOQyxFQUFZLGtCQUdaQyxFQUFTLGFBR1RDLEVBQWEscUJBR2JDLEVBQWEsYUFHYkMsRUFBWSxjQUdaQyxFQUFlQyxTQUdmQyxFQUE4QixpQkFBVkMsR0FBc0JBLEdBQVVBLEVBQU9sSyxTQUFXQSxRQUFVa0ssRUFHaEZDLEVBQTBCLGlCQUFSQyxNQUFvQkEsTUFBUUEsS0FBS3BLLFNBQVdBLFFBQVVvSyxLQUd4RUMsRUFBT0osR0FBY0UsR0FBWUcsU0FBUyxjQUFUQSxHQVVqQ0MsRUFQY3ZLLE9BQU9rQixVQU9Rc0osU0FHN0JDLEVBQVlqSSxLQUFLRixJQUNqQm9JLEVBQVlsSSxLQUFLSCxJQWtCakJzSSxFQUFNLFdBQ1IsT0FBT04sRUFBS08sS0FBS0QsT0F5RG5CLFNBQVNFLEVBQVNDLEVBQU1DLEVBQU1DLEdBQzVCLElBQUlDLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQWlCLEVBQ2pCQyxHQUFVLEVBQ1ZDLEdBQVMsRUFDVEMsR0FBVyxFQUVmLEdBQW1CLG1CQUFSWixFQUNULE1BQU0sSUFBSWEsVUFBVW5DLEdBVXRCLFNBQVNvQyxFQUFXQyxHQUNsQixJQUFJQyxFQUFPYixFQUNQYyxFQUFVYixFQUtkLE9BSEFELEVBQVdDLE9BQVczSixFQUN0QmdLLEVBQWlCTSxFQUNqQlQsRUFBU04sRUFBS2tCLE1BQU1ELEVBQVNELEdBcUIvQixTQUFTRyxFQUFhSixHQUNwQixJQUFJSyxFQUFvQkwsRUFBT1AsRUFNL0IsWUFBeUIvSixJQUFqQitKLEdBQStCWSxHQUFxQm5CLEdBQ3pEbUIsRUFBb0IsR0FBT1QsR0FOSkksRUFBT04sR0FNOEJKLEVBR2pFLFNBQVNnQixJQUNQLElBQUlOLEVBQU9sQixJQUNYLEdBQUlzQixFQUFhSixHQUNmLE9BQU9PLEVBQWFQLEdBR3RCUixFQUFVdkUsV0FBV3FGLEVBekJ2QixTQUF1Qk4sR0FDckIsSUFFSVQsRUFBU0wsR0FGV2MsRUFBT1AsR0FJL0IsT0FBT0csRUFBU2YsRUFBVVUsRUFBUUQsR0FIUlUsRUFBT04sSUFHa0NILEVBb0JoQ2lCLENBQWNSLElBR25ELFNBQVNPLEVBQWFQLEdBS3BCLE9BSkFSLE9BQVU5SixFQUlObUssR0FBWVQsRUFDUFcsRUFBV0MsSUFFcEJaLEVBQVdDLE9BQVczSixFQUNmNkosR0FlVCxTQUFTa0IsSUFDUCxJQUFJVCxFQUFPbEIsSUFDUDRCLEVBQWFOLEVBQWFKLEdBTTlCLEdBSkFaLEVBQVd1QixVQUNYdEIsRUFBV3BDLEtBQ1h3QyxFQUFlTyxFQUVYVSxFQUFZLENBQ2QsUUFBZ0JoTCxJQUFaOEosRUFDRixPQXZFTixTQUFxQlEsR0FNbkIsT0FKQU4sRUFBaUJNLEVBRWpCUixFQUFVdkUsV0FBV3FGLEVBQWNwQixHQUU1QlMsRUFBVUksRUFBV0MsR0FBUVQsRUFpRXpCcUIsQ0FBWW5CLEdBRXJCLEdBQUlHLEVBR0YsT0FEQUosRUFBVXZFLFdBQVdxRixFQUFjcEIsR0FDNUJhLEVBQVdOLEdBTXRCLFlBSGdCL0osSUFBWjhKLElBQ0ZBLEVBQVV2RSxXQUFXcUYsRUFBY3BCLElBRTlCSyxFQUlULE9BeEdBTCxFQUFPMkIsRUFBUzNCLElBQVMsRUFDckI0QixFQUFTM0IsS0FDWFEsSUFBWVIsRUFBUVEsUUFFcEJMLEdBREFNLEVBQVMsWUFBYVQsR0FDSFAsRUFBVWlDLEVBQVMxQixFQUFRRyxVQUFZLEVBQUdKLEdBQVFJLEVBQ3JFTyxFQUFXLGFBQWNWLElBQVlBLEVBQVFVLFNBQVdBLEdBaUcxRFksRUFBVU0sT0FuQ1YsZ0JBQ2tCckwsSUFBWjhKLEdBQ0Z3QixhQUFheEIsR0FFZkUsRUFBaUIsRUFDakJOLEVBQVdLLEVBQWVKLEVBQVdHLE9BQVU5SixHQStCakQrSyxFQUFVUSxNQTVCVixXQUNFLFlBQW1CdkwsSUFBWjhKLEVBQXdCRCxFQUFTZ0IsRUFBYXpCLE1BNEJoRDJCLEVBMEZULFNBQVNLLEVBQVNwTSxHQUNoQixJQUFJdUgsU0FBY3ZILEVBQ2xCLFFBQVNBLElBQWtCLFVBQVJ1SCxHQUE0QixZQUFSQSxHQTRFekMsU0FBUzRFLEVBQVNuTSxHQUNoQixHQUFvQixpQkFBVEEsRUFDVCxPQUFPQSxFQUVULEdBaENGLFNBQWtCQSxHQUNoQixNQUF1QixpQkFBVEEsR0F0QmhCLFNBQXNCQSxHQUNwQixRQUFTQSxHQUF5QixpQkFBVEEsRUFzQnRCd00sQ0FBYXhNLElBQVVnSyxFQUFlOUssS0FBS2MsSUFBVW1KLEVBOEJwRHNELENBQVN6TSxHQUNYLE9BQU9rSixFQUVULEdBQUlrRCxFQUFTcE0sR0FBUSxDQUNuQixJQUFJME0sRUFBZ0MsbUJBQWpCMU0sRUFBTTJNLFFBQXdCM00sRUFBTTJNLFVBQVkzTSxFQUNuRUEsRUFBUW9NLEVBQVNNLEdBQVVBLEVBQVEsR0FBTUEsRUFFM0MsR0FBb0IsaUJBQVQxTSxFQUNULE9BQWlCLElBQVZBLEVBQWNBLEdBQVNBLEVBRWhDQSxFQUFRQSxFQUFNOEksUUFBUU0sRUFBUSxJQUM5QixJQUFJd0QsRUFBV3RELEVBQVdsQixLQUFLcEksR0FDL0IsT0FBUTRNLEdBQVlyRCxFQUFVbkIsS0FBS3BJLEdBQy9Cd0osRUFBYXhKLEVBQU02TSxNQUFNLEdBQUlELEVBQVcsRUFBSSxHQUMzQ3ZELEVBQVdqQixLQUFLcEksR0FBU2tKLEdBQU9sSixFQUd2Q2xCLEVBQU9ELFFBOUlQLFNBQWtCMEwsRUFBTUMsRUFBTUMsR0FDNUIsSUFBSVEsR0FBVSxFQUNWRSxHQUFXLEVBRWYsR0FBbUIsbUJBQVJaLEVBQ1QsTUFBTSxJQUFJYSxVQUFVbkMsR0FNdEIsT0FKSW1ELEVBQVMzQixLQUNYUSxFQUFVLFlBQWFSLElBQVlBLEVBQVFRLFFBQVVBLEVBQ3JERSxFQUFXLGFBQWNWLElBQVlBLEVBQVFVLFNBQVdBLEdBRW5EYixFQUFTQyxFQUFNQyxFQUFNLENBQzFCLFFBQVdTLEVBQ1gsUUFBV1QsRUFDWCxTQUFZVyxPLCtCQ3RUaEIsSUFBSTJCLEVBR0pBLEVBQUksV0FDSCxPQUFPdkUsS0FESixHQUlKLElBRUN1RSxFQUFJQSxHQUFLLElBQUkvQyxTQUFTLGNBQWIsR0FDUixNQUFPZ0QsR0FFYyxpQkFBWDFKLFNBQXFCeUosRUFBSXpKLFFBT3JDdkUsRUFBT0QsUUFBVWlPIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZ2V0dGVyIH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuIFx0XHR9XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBjcmVhdGUgYSBmYWtlIG5hbWVzcGFjZSBvYmplY3RcbiBcdC8vIG1vZGUgJiAxOiB2YWx1ZSBpcyBhIG1vZHVsZSBpZCwgcmVxdWlyZSBpdFxuIFx0Ly8gbW9kZSAmIDI6IG1lcmdlIGFsbCBwcm9wZXJ0aWVzIG9mIHZhbHVlIGludG8gdGhlIG5zXG4gXHQvLyBtb2RlICYgNDogcmV0dXJuIHZhbHVlIHdoZW4gYWxyZWFkeSBucyBvYmplY3RcbiBcdC8vIG1vZGUgJiA4fDE6IGJlaGF2ZSBsaWtlIHJlcXVpcmVcbiBcdF9fd2VicGFja19yZXF1aXJlX18udCA9IGZ1bmN0aW9uKHZhbHVlLCBtb2RlKSB7XG4gXHRcdGlmKG1vZGUgJiAxKSB2YWx1ZSA9IF9fd2VicGFja19yZXF1aXJlX18odmFsdWUpO1xuIFx0XHRpZihtb2RlICYgOCkgcmV0dXJuIHZhbHVlO1xuIFx0XHRpZigobW9kZSAmIDQpICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgJiYgdmFsdWUuX19lc01vZHVsZSkgcmV0dXJuIHZhbHVlO1xuIFx0XHR2YXIgbnMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIobnMpO1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0JywgeyBlbnVtZXJhYmxlOiB0cnVlLCB2YWx1ZTogdmFsdWUgfSk7XG4gXHRcdGlmKG1vZGUgJiAyICYmIHR5cGVvZiB2YWx1ZSAhPSAnc3RyaW5nJykgZm9yKHZhciBrZXkgaW4gdmFsdWUpIF9fd2VicGFja19yZXF1aXJlX18uZChucywga2V5LCBmdW5jdGlvbihrZXkpIHsgcmV0dXJuIHZhbHVlW2tleV07IH0uYmluZChudWxsLCBrZXkpKTtcbiBcdFx0cmV0dXJuIG5zO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IDIpO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmxldCBjYWNoZWRTZXR0aW5ncyA9IHVuZGVmaW5lZDtcbmZ1bmN0aW9uIGdldERhdGEoa2V5KSB7XG4gICAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZGF0YSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKGtleSk7XG4gICAgICAgIGlmIChkYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShkYXRhKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBsb2FkIGRhdGEgZm9yICR7a2V5fWApO1xufVxuZXhwb3J0cy5nZXREYXRhID0gZ2V0RGF0YTtcbmZ1bmN0aW9uIGdldFNldHRpbmdzKCkge1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIGNhY2hlZFNldHRpbmdzID0gZ2V0RGF0YSgnZGF0YS1zZXR0aW5ncycpO1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGxvYWQgc2V0dGluZ3MnKTtcbn1cbmV4cG9ydHMuZ2V0U2V0dGluZ3MgPSBnZXRTZXR0aW5ncztcbiIsIlwidXNlIHN0cmljdFwiO1xuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5mdW5jdGlvbiBjbGFtcChtaW4sIG1heCwgdmFsdWUpIHtcbiAgICByZXR1cm4gTWF0aC5taW4obWF4LCBNYXRoLm1heChtaW4sIHZhbHVlKSk7XG59XG5mdW5jdGlvbiBjbGFtcExpbmUobGluZSkge1xuICAgIHJldHVybiBjbGFtcCgwLCBzZXR0aW5nc18xLmdldFNldHRpbmdzKCkubGluZUNvdW50IC0gMSwgbGluZSk7XG59XG5jb25zdCBnZXRDb2RlTGluZUVsZW1lbnRzID0gKCgpID0+IHtcbiAgICBsZXQgZWxlbWVudHM7XG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgICAgaWYgKCFlbGVtZW50cykge1xuICAgICAgICAgICAgZWxlbWVudHMgPSBbeyBlbGVtZW50OiBkb2N1bWVudC5ib2R5LCBsaW5lOiAwIH1dO1xuICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ2NvZGUtbGluZScpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgbGluZSA9ICtlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS1saW5lJyk7XG4gICAgICAgICAgICAgICAgaWYgKGlzTmFOKGxpbmUpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC50YWdOYW1lID09PSAnQ09ERScgJiYgZWxlbWVudC5wYXJlbnRFbGVtZW50ICYmIGVsZW1lbnQucGFyZW50RWxlbWVudC50YWdOYW1lID09PSAnUFJFJykge1xuICAgICAgICAgICAgICAgICAgICAvLyBGZW5jaGVkIGNvZGUgYmxvY2tzIGFyZSBhIHNwZWNpYWwgY2FzZSBzaW5jZSB0aGUgYGNvZGUtbGluZWAgY2FuIG9ubHkgYmUgbWFya2VkIG9uXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSBgPGNvZGU+YCBlbGVtZW50IGFuZCBub3QgdGhlIHBhcmVudCBgPHByZT5gIGVsZW1lbnQuXG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzLnB1c2goeyBlbGVtZW50OiBlbGVtZW50LnBhcmVudEVsZW1lbnQsIGxpbmUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBlbGVtZW50cy5wdXNoKHsgZWxlbWVudDogZWxlbWVudCwgbGluZSB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVsZW1lbnRzO1xuICAgIH07XG59KSgpO1xuLyoqXG4gKiBGaW5kIHRoZSBodG1sIGVsZW1lbnRzIHRoYXQgbWFwIHRvIGEgc3BlY2lmaWMgdGFyZ2V0IGxpbmUgaW4gdGhlIGVkaXRvci5cbiAqXG4gKiBJZiBhbiBleGFjdCBtYXRjaCwgcmV0dXJucyBhIHNpbmdsZSBlbGVtZW50LiBJZiB0aGUgbGluZSBpcyBiZXR3ZWVuIGVsZW1lbnRzLFxuICogcmV0dXJucyB0aGUgZWxlbWVudCBwcmlvciB0byBhbmQgdGhlIGVsZW1lbnQgYWZ0ZXIgdGhlIGdpdmVuIGxpbmUuXG4gKi9cbmZ1bmN0aW9uIGdldEVsZW1lbnRzRm9yU291cmNlTGluZSh0YXJnZXRMaW5lKSB7XG4gICAgY29uc3QgbGluZU51bWJlciA9IE1hdGguZmxvb3IodGFyZ2V0TGluZSk7XG4gICAgY29uc3QgbGluZXMgPSBnZXRDb2RlTGluZUVsZW1lbnRzKCk7XG4gICAgbGV0IHByZXZpb3VzID0gbGluZXNbMF0gfHwgbnVsbDtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGxpbmVzKSB7XG4gICAgICAgIGlmIChlbnRyeS5saW5lID09PSBsaW5lTnVtYmVyKSB7XG4gICAgICAgICAgICByZXR1cm4geyBwcmV2aW91czogZW50cnksIG5leHQ6IHVuZGVmaW5lZCB9O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGVudHJ5LmxpbmUgPiBsaW5lTnVtYmVyKSB7XG4gICAgICAgICAgICByZXR1cm4geyBwcmV2aW91cywgbmV4dDogZW50cnkgfTtcbiAgICAgICAgfVxuICAgICAgICBwcmV2aW91cyA9IGVudHJ5O1xuICAgIH1cbiAgICByZXR1cm4geyBwcmV2aW91cyB9O1xufVxuZXhwb3J0cy5nZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUgPSBnZXRFbGVtZW50c0ZvclNvdXJjZUxpbmU7XG4vKipcbiAqIEZpbmQgdGhlIGh0bWwgZWxlbWVudHMgdGhhdCBhcmUgYXQgYSBzcGVjaWZpYyBwaXhlbCBvZmZzZXQgb24gdGhlIHBhZ2UuXG4gKi9cbmZ1bmN0aW9uIGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldChvZmZzZXQpIHtcbiAgICBjb25zdCBsaW5lcyA9IGdldENvZGVMaW5lRWxlbWVudHMoKTtcbiAgICBjb25zdCBwb3NpdGlvbiA9IG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZO1xuICAgIGxldCBsbyA9IC0xO1xuICAgIGxldCBoaSA9IGxpbmVzLmxlbmd0aCAtIDE7XG4gICAgd2hpbGUgKGxvICsgMSA8IGhpKSB7XG4gICAgICAgIGNvbnN0IG1pZCA9IE1hdGguZmxvb3IoKGxvICsgaGkpIC8gMik7XG4gICAgICAgIGNvbnN0IGJvdW5kcyA9IGxpbmVzW21pZF0uZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgaWYgKGJvdW5kcy50b3AgKyBib3VuZHMuaGVpZ2h0ID49IHBvc2l0aW9uKSB7XG4gICAgICAgICAgICBoaSA9IG1pZDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxvID0gbWlkO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGhpRWxlbWVudCA9IGxpbmVzW2hpXTtcbiAgICBjb25zdCBoaUJvdW5kcyA9IGhpRWxlbWVudC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGlmIChoaSA+PSAxICYmIGhpQm91bmRzLnRvcCA+IHBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGxvRWxlbWVudCA9IGxpbmVzW2xvXTtcbiAgICAgICAgcmV0dXJuIHsgcHJldmlvdXM6IGxvRWxlbWVudCwgbmV4dDogaGlFbGVtZW50IH07XG4gICAgfVxuICAgIGlmIChoaSA+IDEgJiYgaGkgPCBsaW5lcy5sZW5ndGggJiYgaGlCb3VuZHMudG9wICsgaGlCb3VuZHMuaGVpZ2h0ID4gcG9zaXRpb24pIHtcbiAgICAgICAgcmV0dXJuIHsgcHJldmlvdXM6IGhpRWxlbWVudCwgbmV4dDogbGluZXNbaGkgKyAxXSB9O1xuICAgIH1cbiAgICByZXR1cm4geyBwcmV2aW91czogaGlFbGVtZW50IH07XG59XG5leHBvcnRzLmdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldCA9IGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldDtcbi8qKlxuICogQXR0ZW1wdCB0byByZXZlYWwgdGhlIGVsZW1lbnQgZm9yIGEgc291cmNlIGxpbmUgaW4gdGhlIGVkaXRvci5cbiAqL1xuZnVuY3Rpb24gc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGxpbmUpIHtcbiAgICBpZiAoIXNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChsaW5lIDw9IDApIHtcbiAgICAgICAgd2luZG93LnNjcm9sbCh3aW5kb3cuc2Nyb2xsWCwgMCk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgeyBwcmV2aW91cywgbmV4dCB9ID0gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lKGxpbmUpO1xuICAgIGlmICghcHJldmlvdXMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgc2Nyb2xsVG8gPSAwO1xuICAgIGNvbnN0IHJlY3QgPSBwcmV2aW91cy5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGNvbnN0IHByZXZpb3VzVG9wID0gcmVjdC50b3A7XG4gICAgaWYgKG5leHQgJiYgbmV4dC5saW5lICE9PSBwcmV2aW91cy5saW5lKSB7XG4gICAgICAgIC8vIEJldHdlZW4gdHdvIGVsZW1lbnRzLiBHbyB0byBwZXJjZW50YWdlIG9mZnNldCBiZXR3ZWVuIHRoZW0uXG4gICAgICAgIGNvbnN0IGJldHdlZW5Qcm9ncmVzcyA9IChsaW5lIC0gcHJldmlvdXMubGluZSkgLyAobmV4dC5saW5lIC0gcHJldmlvdXMubGluZSk7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRPZmZzZXQgPSBuZXh0LmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wIC0gcHJldmlvdXNUb3A7XG4gICAgICAgIHNjcm9sbFRvID0gcHJldmlvdXNUb3AgKyBiZXR3ZWVuUHJvZ3Jlc3MgKiBlbGVtZW50T2Zmc2V0O1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgY29uc3QgcHJvZ3Jlc3NJbkVsZW1lbnQgPSBsaW5lIC0gTWF0aC5mbG9vcihsaW5lKTtcbiAgICAgICAgc2Nyb2xsVG8gPSBwcmV2aW91c1RvcCArIChyZWN0LmhlaWdodCAqIHByb2dyZXNzSW5FbGVtZW50KTtcbiAgICB9XG4gICAgd2luZG93LnNjcm9sbCh3aW5kb3cuc2Nyb2xsWCwgTWF0aC5tYXgoMSwgd2luZG93LnNjcm9sbFkgKyBzY3JvbGxUbykpO1xufVxuZXhwb3J0cy5zY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUgPSBzY3JvbGxUb1JldmVhbFNvdXJjZUxpbmU7XG5mdW5jdGlvbiBnZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldChvZmZzZXQpIHtcbiAgICBjb25zdCB7IHByZXZpb3VzLCBuZXh0IH0gPSBnZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQob2Zmc2V0KTtcbiAgICBpZiAocHJldmlvdXMpIHtcbiAgICAgICAgY29uc3QgcHJldmlvdXNCb3VuZHMgPSBwcmV2aW91cy5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCBvZmZzZXRGcm9tUHJldmlvdXMgPSAob2Zmc2V0IC0gd2luZG93LnNjcm9sbFkgLSBwcmV2aW91c0JvdW5kcy50b3ApO1xuICAgICAgICBpZiAobmV4dCkge1xuICAgICAgICAgICAgY29uc3QgcHJvZ3Jlc3NCZXR3ZWVuRWxlbWVudHMgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAobmV4dC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIHByZXZpb3VzQm91bmRzLnRvcCk7XG4gICAgICAgICAgICBjb25zdCBsaW5lID0gcHJldmlvdXMubGluZSArIHByb2dyZXNzQmV0d2VlbkVsZW1lbnRzICogKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuICAgICAgICAgICAgcmV0dXJuIGNsYW1wTGluZShsaW5lKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHByb2dyZXNzV2l0aGluRWxlbWVudCA9IG9mZnNldEZyb21QcmV2aW91cyAvIChwcmV2aW91c0JvdW5kcy5oZWlnaHQpO1xuICAgICAgICAgICAgY29uc3QgbGluZSA9IHByZXZpb3VzLmxpbmUgKyBwcm9ncmVzc1dpdGhpbkVsZW1lbnQ7XG4gICAgICAgICAgICByZXR1cm4gY2xhbXBMaW5lKGxpbmUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuZXhwb3J0cy5nZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCA9IGdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0O1xuLyoqXG4gKiBUcnkgdG8gZmluZCB0aGUgaHRtbCBlbGVtZW50IGJ5IHVzaW5nIGEgZnJhZ21lbnQgaWRcbiAqL1xuZnVuY3Rpb24gZ2V0TGluZUVsZW1lbnRGb3JGcmFnbWVudChmcmFnbWVudCkge1xuICAgIHJldHVybiBnZXRDb2RlTGluZUVsZW1lbnRzKCkuZmluZCgoZWxlbWVudCkgPT4ge1xuICAgICAgICByZXR1cm4gZWxlbWVudC5lbGVtZW50LmlkID09PSBmcmFnbWVudDtcbiAgICB9KTtcbn1cbmV4cG9ydHMuZ2V0TGluZUVsZW1lbnRGb3JGcmFnbWVudCA9IGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgYWN0aXZlTGluZU1hcmtlcl8xID0gcmVxdWlyZShcIi4vYWN0aXZlTGluZU1hcmtlclwiKTtcbmNvbnN0IGV2ZW50c18xID0gcmVxdWlyZShcIi4vZXZlbnRzXCIpO1xuY29uc3QgbWVzc2FnaW5nXzEgPSByZXF1aXJlKFwiLi9tZXNzYWdpbmdcIik7XG5jb25zdCBzY3JvbGxfc3luY18xID0gcmVxdWlyZShcIi4vc2Nyb2xsLXN5bmNcIik7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5jb25zdCB0aHJvdHRsZSA9IHJlcXVpcmUoXCJsb2Rhc2gudGhyb3R0bGVcIik7XG5sZXQgc2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuY29uc3QgbWFya2VyID0gbmV3IGFjdGl2ZUxpbmVNYXJrZXJfMS5BY3RpdmVMaW5lTWFya2VyKCk7XG5jb25zdCBzZXR0aW5ncyA9IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKTtcbmNvbnN0IHZzY29kZSA9IGFjcXVpcmVWc0NvZGVBcGkoKTtcbi8vIFNldCBWUyBDb2RlIHN0YXRlXG5sZXQgc3RhdGUgPSBzZXR0aW5nc18xLmdldERhdGEoJ2RhdGEtc3RhdGUnKTtcbnZzY29kZS5zZXRTdGF0ZShzdGF0ZSk7XG5jb25zdCBtZXNzYWdpbmcgPSBtZXNzYWdpbmdfMS5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUodnNjb2RlKTtcbndpbmRvdy5jc3BBbGVydGVyLnNldFBvc3RlcihtZXNzYWdpbmcpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3Iuc2V0UG9zdGVyKG1lc3NhZ2luZyk7XG53aW5kb3cub25sb2FkID0gKCkgPT4ge1xuICAgIHVwZGF0ZUltYWdlU2l6ZXMoKTtcbn07XG5ldmVudHNfMS5vbmNlRG9jdW1lbnRMb2FkZWQoKCkgPT4ge1xuICAgIGlmIChzZXR0aW5ncy5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIC8vIFRyeSB0byBzY3JvbGwgdG8gZnJhZ21lbnQgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBpZiAoc3RhdGUuZnJhZ21lbnQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gc2Nyb2xsX3N5bmNfMS5nZXRMaW5lRWxlbWVudEZvckZyYWdtZW50KHN0YXRlLmZyYWdtZW50KTtcbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGVsZW1lbnQubGluZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5pdGlhbExpbmUgPSArc2V0dGluZ3MubGluZTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGluaXRpYWxMaW5lKSkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGluaXRpYWxMaW5lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDApO1xuICAgIH1cbn0pO1xuY29uc3Qgb25VcGRhdGVWaWV3ID0gKCgpID0+IHtcbiAgICBjb25zdCBkb1Njcm9sbCA9IHRocm90dGxlKChsaW5lKSA9PiB7XG4gICAgICAgIHNjcm9sbERpc2FibGVkID0gdHJ1ZTtcbiAgICAgICAgc2Nyb2xsX3N5bmNfMS5zY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUobGluZSk7XG4gICAgfSwgNTApO1xuICAgIHJldHVybiAobGluZSwgc2V0dGluZ3MpID0+IHtcbiAgICAgICAgaWYgKCFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgc2V0dGluZ3MubGluZSA9IGxpbmU7XG4gICAgICAgICAgICBkb1Njcm9sbChsaW5lKTtcbiAgICAgICAgfVxuICAgIH07XG59KSgpO1xubGV0IHVwZGF0ZUltYWdlU2l6ZXMgPSB0aHJvdHRsZSgoKSA9PiB7XG4gICAgY29uc3QgaW1hZ2VJbmZvID0gW107XG4gICAgbGV0IGltYWdlcyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbWcnKTtcbiAgICBpZiAoaW1hZ2VzKSB7XG4gICAgICAgIGxldCBpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgaW1hZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBpbWcgPSBpbWFnZXNbaV07XG4gICAgICAgICAgICBpZiAoaW1nLmNsYXNzTGlzdC5jb250YWlucygnbG9hZGluZycpKSB7XG4gICAgICAgICAgICAgICAgaW1nLmNsYXNzTGlzdC5yZW1vdmUoJ2xvYWRpbmcnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGltYWdlSW5mby5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogaW1nLmlkLFxuICAgICAgICAgICAgICAgIGhlaWdodDogaW1nLmhlaWdodCxcbiAgICAgICAgICAgICAgICB3aWR0aDogaW1nLndpZHRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NhY2hlSW1hZ2VTaXplcycsIGltYWdlSW5mbyk7XG4gICAgfVxufSwgNTApO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgdXBkYXRlSW1hZ2VTaXplcygpO1xufSwgdHJ1ZSk7XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGV2ZW50ID0+IHtcbiAgICBpZiAoZXZlbnQuZGF0YS5zb3VyY2UgIT09IHNldHRpbmdzLnNvdXJjZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHN3aXRjaCAoZXZlbnQuZGF0YS50eXBlKSB7XG4gICAgICAgIGNhc2UgJ29uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbic6XG4gICAgICAgICAgICBtYXJrZXIub25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGV2ZW50LmRhdGEubGluZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndXBkYXRlVmlldyc6XG4gICAgICAgICAgICBvblVwZGF0ZVZpZXcoZXZlbnQuZGF0YS5saW5lLCBzZXR0aW5ncyk7XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG59LCBmYWxzZSk7XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIGV2ZW50ID0+IHtcbiAgICBpZiAoIXNldHRpbmdzLmRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIElnbm9yZSBjbGlja3Mgb24gbGlua3NcbiAgICBmb3IgKGxldCBub2RlID0gZXZlbnQudGFyZ2V0OyBub2RlOyBub2RlID0gbm9kZS5wYXJlbnROb2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgPT09ICdBJykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IG9mZnNldCA9IGV2ZW50LnBhZ2VZO1xuICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgbWVzc2FnaW5nLnBvc3RNZXNzYWdlKCdkaWRDbGljaycsIHsgbGluZTogTWF0aC5mbG9vcihsaW5lKSB9KTtcbiAgICB9XG59KTtcbmNvbnN0IHBhc3NUaHJvdWdoTGlua1NjaGVtZXMgPSBbJ2h0dHA6JywgJ2h0dHBzOicsICdtYWlsdG86JywgJ3ZzY29kZTonLCAndnNjb2RlLWluc2lkZXJzOiddO1xuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBldmVudCA9PiB7XG4gICAgaWYgKCFldmVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBub2RlID0gZXZlbnQudGFyZ2V0O1xuICAgIHdoaWxlIChub2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgJiYgbm9kZS50YWdOYW1lID09PSAnQScgJiYgbm9kZS5ocmVmKSB7XG4gICAgICAgICAgICBpZiAobm9kZS5nZXRBdHRyaWJ1dGUoJ2hyZWYnKS5zdGFydHNXaXRoKCcjJykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBQYXNzIHRocm91Z2gga25vd24gc2NoZW1lc1xuICAgICAgICAgICAgaWYgKHBhc3NUaHJvdWdoTGlua1NjaGVtZXMuc29tZShzY2hlbWUgPT4gbm9kZS5ocmVmLnN0YXJ0c1dpdGgoc2NoZW1lKSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBocmVmVGV4dCA9IG5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLWhyZWYnKSB8fCBub2RlLmdldEF0dHJpYnV0ZSgnaHJlZicpO1xuICAgICAgICAgICAgLy8gSWYgb3JpZ2luYWwgbGluayBkb2Vzbid0IGxvb2sgbGlrZSBhIHVybCwgZGVsZWdhdGUgYmFjayB0byBWUyBDb2RlIHRvIHJlc29sdmVcbiAgICAgICAgICAgIGlmICghL15bYS16XFwtXSs6L2kudGVzdChocmVmVGV4dCkpIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ29wZW5MaW5rJywgeyBocmVmOiBocmVmVGV4dCB9KTtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgIH1cbn0sIHRydWUpO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRocm90dGxlKCgpID0+IHtcbiAgICBpZiAoc2Nyb2xsRGlzYWJsZWQpIHtcbiAgICAgICAgc2Nyb2xsRGlzYWJsZWQgPSBmYWxzZTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KHdpbmRvdy5zY3JvbGxZKTtcbiAgICAgICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgICAgIG1lc3NhZ2luZy5wb3N0TWVzc2FnZSgncmV2ZWFsTGluZScsIHsgbGluZSB9KTtcbiAgICAgICAgICAgIHN0YXRlLmxpbmUgPSBsaW5lO1xuICAgICAgICAgICAgdnNjb2RlLnNldFN0YXRlKHN0YXRlKTtcbiAgICAgICAgfVxuICAgIH1cbn0sIDUwKSk7XG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuY29uc3Qgc2Nyb2xsX3N5bmNfMSA9IHJlcXVpcmUoXCIuL3Njcm9sbC1zeW5jXCIpO1xuY2xhc3MgQWN0aXZlTGluZU1hcmtlciB7XG4gICAgb25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGxpbmUpIHtcbiAgICAgICAgY29uc3QgeyBwcmV2aW91cyB9ID0gc2Nyb2xsX3N5bmNfMS5nZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUobGluZSk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZShwcmV2aW91cyAmJiBwcmV2aW91cy5lbGVtZW50KTtcbiAgICB9XG4gICAgX3VwZGF0ZShiZWZvcmUpIHtcbiAgICAgICAgdGhpcy5fdW5tYXJrQWN0aXZlRWxlbWVudCh0aGlzLl9jdXJyZW50KTtcbiAgICAgICAgdGhpcy5fbWFya0FjdGl2ZUVsZW1lbnQoYmVmb3JlKTtcbiAgICAgICAgdGhpcy5fY3VycmVudCA9IGJlZm9yZTtcbiAgICB9XG4gICAgX3VubWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSA9IGVsZW1lbnQuY2xhc3NOYW1lLnJlcGxhY2UoL1xcYmNvZGUtYWN0aXZlLWxpbmVcXGIvZywgJycpO1xuICAgIH1cbiAgICBfbWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSArPSAnIGNvZGUtYWN0aXZlLWxpbmUnO1xuICAgIH1cbn1cbmV4cG9ydHMuQWN0aXZlTGluZU1hcmtlciA9IEFjdGl2ZUxpbmVNYXJrZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gb25jZURvY3VtZW50TG9hZGVkKGYpIHtcbiAgICBpZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnIHx8IGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICd1bmluaXRpYWxpemVkJykge1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBmKCk7XG4gICAgfVxufVxuZXhwb3J0cy5vbmNlRG9jdW1lbnRMb2FkZWQgPSBvbmNlRG9jdW1lbnRMb2FkZWQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3Qgc2V0dGluZ3NfMSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzXCIpO1xuZXhwb3J0cy5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUgPSAodnNjb2RlKSA9PiB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyB7XG4gICAgICAgIHBvc3RNZXNzYWdlKHR5cGUsIGJvZHkpIHtcbiAgICAgICAgICAgIHZzY29kZS5wb3N0TWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgdHlwZSxcbiAgICAgICAgICAgICAgICBzb3VyY2U6IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5zb3VyY2UsXG4gICAgICAgICAgICAgICAgYm9keVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9O1xufTtcbiIsIi8qKlxuICogbG9kYXNoIChDdXN0b20gQnVpbGQpIDxodHRwczovL2xvZGFzaC5jb20vPlxuICogQnVpbGQ6IGBsb2Rhc2ggbW9kdWxhcml6ZSBleHBvcnRzPVwibnBtXCIgLW8gLi9gXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9ycyA8aHR0cHM6Ly9qcXVlcnkub3JnLz5cbiAqIFJlbGVhc2VkIHVuZGVyIE1JVCBsaWNlbnNlIDxodHRwczovL2xvZGFzaC5jb20vbGljZW5zZT5cbiAqIEJhc2VkIG9uIFVuZGVyc2NvcmUuanMgMS44LjMgPGh0dHA6Ly91bmRlcnNjb3JlanMub3JnL0xJQ0VOU0U+XG4gKiBDb3B5cmlnaHQgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbiAqL1xuXG4vKiogVXNlZCBhcyB0aGUgYFR5cGVFcnJvcmAgbWVzc2FnZSBmb3IgXCJGdW5jdGlvbnNcIiBtZXRob2RzLiAqL1xudmFyIEZVTkNfRVJST1JfVEVYVCA9ICdFeHBlY3RlZCBhIGZ1bmN0aW9uJztcblxuLyoqIFVzZWQgYXMgcmVmZXJlbmNlcyBmb3IgdmFyaW91cyBgTnVtYmVyYCBjb25zdGFudHMuICovXG52YXIgTkFOID0gMCAvIDA7XG5cbi8qKiBgT2JqZWN0I3RvU3RyaW5nYCByZXN1bHQgcmVmZXJlbmNlcy4gKi9cbnZhciBzeW1ib2xUYWcgPSAnW29iamVjdCBTeW1ib2xdJztcblxuLyoqIFVzZWQgdG8gbWF0Y2ggbGVhZGluZyBhbmQgdHJhaWxpbmcgd2hpdGVzcGFjZS4gKi9cbnZhciByZVRyaW0gPSAvXlxccyt8XFxzKyQvZztcblxuLyoqIFVzZWQgdG8gZGV0ZWN0IGJhZCBzaWduZWQgaGV4YWRlY2ltYWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmFkSGV4ID0gL15bLStdMHhbMC05YS1mXSskL2k7XG5cbi8qKiBVc2VkIHRvIGRldGVjdCBiaW5hcnkgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmluYXJ5ID0gL14wYlswMV0rJC9pO1xuXG4vKiogVXNlZCB0byBkZXRlY3Qgb2N0YWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzT2N0YWwgPSAvXjBvWzAtN10rJC9pO1xuXG4vKiogQnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMgd2l0aG91dCBhIGRlcGVuZGVuY3kgb24gYHJvb3RgLiAqL1xudmFyIGZyZWVQYXJzZUludCA9IHBhcnNlSW50O1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYGdsb2JhbGAgZnJvbSBOb2RlLmpzLiAqL1xudmFyIGZyZWVHbG9iYWwgPSB0eXBlb2YgZ2xvYmFsID09ICdvYmplY3QnICYmIGdsb2JhbCAmJiBnbG9iYWwuT2JqZWN0ID09PSBPYmplY3QgJiYgZ2xvYmFsO1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYHNlbGZgLiAqL1xudmFyIGZyZWVTZWxmID0gdHlwZW9mIHNlbGYgPT0gJ29iamVjdCcgJiYgc2VsZiAmJiBzZWxmLk9iamVjdCA9PT0gT2JqZWN0ICYmIHNlbGY7XG5cbi8qKiBVc2VkIGFzIGEgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb2JqZWN0LiAqL1xudmFyIHJvb3QgPSBmcmVlR2xvYmFsIHx8IGZyZWVTZWxmIHx8IEZ1bmN0aW9uKCdyZXR1cm4gdGhpcycpKCk7XG5cbi8qKiBVc2VkIGZvciBidWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcy4gKi9cbnZhciBvYmplY3RQcm90byA9IE9iamVjdC5wcm90b3R5cGU7XG5cbi8qKlxuICogVXNlZCB0byByZXNvbHZlIHRoZVxuICogW2B0b1N0cmluZ1RhZ2BdKGh0dHA6Ly9lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLW9iamVjdC5wcm90b3R5cGUudG9zdHJpbmcpXG4gKiBvZiB2YWx1ZXMuXG4gKi9cbnZhciBvYmplY3RUb1N0cmluZyA9IG9iamVjdFByb3RvLnRvU3RyaW5nO1xuXG4vKiBCdWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcyBmb3IgdGhvc2Ugd2l0aCB0aGUgc2FtZSBuYW1lIGFzIG90aGVyIGBsb2Rhc2hgIG1ldGhvZHMuICovXG52YXIgbmF0aXZlTWF4ID0gTWF0aC5tYXgsXG4gICAgbmF0aXZlTWluID0gTWF0aC5taW47XG5cbi8qKlxuICogR2V0cyB0aGUgdGltZXN0YW1wIG9mIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRoYXQgaGF2ZSBlbGFwc2VkIHNpbmNlXG4gKiB0aGUgVW5peCBlcG9jaCAoMSBKYW51YXJ5IDE5NzAgMDA6MDA6MDAgVVRDKS5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDIuNC4wXG4gKiBAY2F0ZWdvcnkgRGF0ZVxuICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgdGltZXN0YW1wLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmRlZmVyKGZ1bmN0aW9uKHN0YW1wKSB7XG4gKiAgIGNvbnNvbGUubG9nKF8ubm93KCkgLSBzdGFtcCk7XG4gKiB9LCBfLm5vdygpKTtcbiAqIC8vID0+IExvZ3MgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgaXQgdG9vayBmb3IgdGhlIGRlZmVycmVkIGludm9jYXRpb24uXG4gKi9cbnZhciBub3cgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHJvb3QuRGF0ZS5ub3coKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlYm91bmNlZCBmdW5jdGlvbiB0aGF0IGRlbGF5cyBpbnZva2luZyBgZnVuY2AgdW50aWwgYWZ0ZXIgYHdhaXRgXG4gKiBtaWxsaXNlY29uZHMgaGF2ZSBlbGFwc2VkIHNpbmNlIHRoZSBsYXN0IHRpbWUgdGhlIGRlYm91bmNlZCBmdW5jdGlvbiB3YXNcbiAqIGludm9rZWQuIFRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgIG1ldGhvZCB0byBjYW5jZWxcbiAqIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLlxuICogUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2Agc2hvdWxkIGJlIGludm9rZWQgb24gdGhlXG4gKiBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGAgdGltZW91dC4gVGhlIGBmdW5jYCBpcyBpbnZva2VkXG4gKiB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50XG4gKiBjYWxscyB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYFxuICogaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIGRlYm91bmNlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy5kZWJvdW5jZWAgYW5kIGBfLnRocm90dGxlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlYm91bmNlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIGRlbGF5LlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9ZmFsc2VdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgbGVhZGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLm1heFdhaXRdXG4gKiAgVGhlIG1heGltdW0gdGltZSBgZnVuY2AgaXMgYWxsb3dlZCB0byBiZSBkZWxheWVkIGJlZm9yZSBpdCdzIGludm9rZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGRlYm91bmNlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgY29zdGx5IGNhbGN1bGF0aW9ucyB3aGlsZSB0aGUgd2luZG93IHNpemUgaXMgaW4gZmx1eC5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdyZXNpemUnLCBfLmRlYm91bmNlKGNhbGN1bGF0ZUxheW91dCwgMTUwKSk7XG4gKlxuICogLy8gSW52b2tlIGBzZW5kTWFpbGAgd2hlbiBjbGlja2VkLCBkZWJvdW5jaW5nIHN1YnNlcXVlbnQgY2FsbHMuXG4gKiBqUXVlcnkoZWxlbWVudCkub24oJ2NsaWNrJywgXy5kZWJvdW5jZShzZW5kTWFpbCwgMzAwLCB7XG4gKiAgICdsZWFkaW5nJzogdHJ1ZSxcbiAqICAgJ3RyYWlsaW5nJzogZmFsc2VcbiAqIH0pKTtcbiAqXG4gKiAvLyBFbnN1cmUgYGJhdGNoTG9nYCBpcyBpbnZva2VkIG9uY2UgYWZ0ZXIgMSBzZWNvbmQgb2YgZGVib3VuY2VkIGNhbGxzLlxuICogdmFyIGRlYm91bmNlZCA9IF8uZGVib3VuY2UoYmF0Y2hMb2csIDI1MCwgeyAnbWF4V2FpdCc6IDEwMDAgfSk7XG4gKiB2YXIgc291cmNlID0gbmV3IEV2ZW50U291cmNlKCcvc3RyZWFtJyk7XG4gKiBqUXVlcnkoc291cmNlKS5vbignbWVzc2FnZScsIGRlYm91bmNlZCk7XG4gKlxuICogLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyBkZWJvdW5jZWQgaW52b2NhdGlvbi5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIGRlYm91bmNlZC5jYW5jZWwpO1xuICovXG5mdW5jdGlvbiBkZWJvdW5jZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIHZhciBsYXN0QXJncyxcbiAgICAgIGxhc3RUaGlzLFxuICAgICAgbWF4V2FpdCxcbiAgICAgIHJlc3VsdCxcbiAgICAgIHRpbWVySWQsXG4gICAgICBsYXN0Q2FsbFRpbWUsXG4gICAgICBsYXN0SW52b2tlVGltZSA9IDAsXG4gICAgICBsZWFkaW5nID0gZmFsc2UsXG4gICAgICBtYXhpbmcgPSBmYWxzZSxcbiAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoRlVOQ19FUlJPUl9URVhUKTtcbiAgfVxuICB3YWl0ID0gdG9OdW1iZXIod2FpdCkgfHwgMDtcbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICEhb3B0aW9ucy5sZWFkaW5nO1xuICAgIG1heGluZyA9ICdtYXhXYWl0JyBpbiBvcHRpb25zO1xuICAgIG1heFdhaXQgPSBtYXhpbmcgPyBuYXRpdmVNYXgodG9OdW1iZXIob3B0aW9ucy5tYXhXYWl0KSB8fCAwLCB3YWl0KSA6IG1heFdhaXQ7XG4gICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgfVxuXG4gIGZ1bmN0aW9uIGludm9rZUZ1bmModGltZSkge1xuICAgIHZhciBhcmdzID0gbGFzdEFyZ3MsXG4gICAgICAgIHRoaXNBcmcgPSBsYXN0VGhpcztcblxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkodGhpc0FyZywgYXJncyk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGxlYWRpbmdFZGdlKHRpbWUpIHtcbiAgICAvLyBSZXNldCBhbnkgYG1heFdhaXRgIHRpbWVyLlxuICAgIGxhc3RJbnZva2VUaW1lID0gdGltZTtcbiAgICAvLyBTdGFydCB0aGUgdGltZXIgZm9yIHRoZSB0cmFpbGluZyBlZGdlLlxuICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgLy8gSW52b2tlIHRoZSBsZWFkaW5nIGVkZ2UuXG4gICAgcmV0dXJuIGxlYWRpbmcgPyBpbnZva2VGdW5jKHRpbWUpIDogcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gcmVtYWluaW5nV2FpdCh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZSxcbiAgICAgICAgcmVzdWx0ID0gd2FpdCAtIHRpbWVTaW5jZUxhc3RDYWxsO1xuXG4gICAgcmV0dXJuIG1heGluZyA/IG5hdGl2ZU1pbihyZXN1bHQsIG1heFdhaXQgLSB0aW1lU2luY2VMYXN0SW52b2tlKSA6IHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNob3VsZEludm9rZSh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZTtcblxuICAgIC8vIEVpdGhlciB0aGlzIGlzIHRoZSBmaXJzdCBjYWxsLCBhY3Rpdml0eSBoYXMgc3RvcHBlZCBhbmQgd2UncmUgYXQgdGhlXG4gICAgLy8gdHJhaWxpbmcgZWRnZSwgdGhlIHN5c3RlbSB0aW1lIGhhcyBnb25lIGJhY2t3YXJkcyBhbmQgd2UncmUgdHJlYXRpbmdcbiAgICAvLyBpdCBhcyB0aGUgdHJhaWxpbmcgZWRnZSwgb3Igd2UndmUgaGl0IHRoZSBgbWF4V2FpdGAgbGltaXQuXG4gICAgcmV0dXJuIChsYXN0Q2FsbFRpbWUgPT09IHVuZGVmaW5lZCB8fCAodGltZVNpbmNlTGFzdENhbGwgPj0gd2FpdCkgfHxcbiAgICAgICh0aW1lU2luY2VMYXN0Q2FsbCA8IDApIHx8IChtYXhpbmcgJiYgdGltZVNpbmNlTGFzdEludm9rZSA+PSBtYXhXYWl0KSk7XG4gIH1cblxuICBmdW5jdGlvbiB0aW1lckV4cGlyZWQoKSB7XG4gICAgdmFyIHRpbWUgPSBub3coKTtcbiAgICBpZiAoc2hvdWxkSW52b2tlKHRpbWUpKSB7XG4gICAgICByZXR1cm4gdHJhaWxpbmdFZGdlKHRpbWUpO1xuICAgIH1cbiAgICAvLyBSZXN0YXJ0IHRoZSB0aW1lci5cbiAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHJlbWFpbmluZ1dhaXQodGltZSkpO1xuICB9XG5cbiAgZnVuY3Rpb24gdHJhaWxpbmdFZGdlKHRpbWUpIHtcbiAgICB0aW1lcklkID0gdW5kZWZpbmVkO1xuXG4gICAgLy8gT25seSBpbnZva2UgaWYgd2UgaGF2ZSBgbGFzdEFyZ3NgIHdoaWNoIG1lYW5zIGBmdW5jYCBoYXMgYmVlblxuICAgIC8vIGRlYm91bmNlZCBhdCBsZWFzdCBvbmNlLlxuICAgIGlmICh0cmFpbGluZyAmJiBsYXN0QXJncykge1xuICAgICAgcmV0dXJuIGludm9rZUZ1bmModGltZSk7XG4gICAgfVxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNhbmNlbCgpIHtcbiAgICBpZiAodGltZXJJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXJJZCk7XG4gICAgfVxuICAgIGxhc3RJbnZva2VUaW1lID0gMDtcbiAgICBsYXN0QXJncyA9IGxhc3RDYWxsVGltZSA9IGxhc3RUaGlzID0gdGltZXJJZCA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGZsdXNoKCkge1xuICAgIHJldHVybiB0aW1lcklkID09PSB1bmRlZmluZWQgPyByZXN1bHQgOiB0cmFpbGluZ0VkZ2Uobm93KCkpO1xuICB9XG5cbiAgZnVuY3Rpb24gZGVib3VuY2VkKCkge1xuICAgIHZhciB0aW1lID0gbm93KCksXG4gICAgICAgIGlzSW52b2tpbmcgPSBzaG91bGRJbnZva2UodGltZSk7XG5cbiAgICBsYXN0QXJncyA9IGFyZ3VtZW50cztcbiAgICBsYXN0VGhpcyA9IHRoaXM7XG4gICAgbGFzdENhbGxUaW1lID0gdGltZTtcblxuICAgIGlmIChpc0ludm9raW5nKSB7XG4gICAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBsZWFkaW5nRWRnZShsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgICAgaWYgKG1heGluZykge1xuICAgICAgICAvLyBIYW5kbGUgaW52b2NhdGlvbnMgaW4gYSB0aWdodCBsb29wLlxuICAgICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgICAgICByZXR1cm4gaW52b2tlRnVuYyhsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIGRlYm91bmNlZC5jYW5jZWwgPSBjYW5jZWw7XG4gIGRlYm91bmNlZC5mbHVzaCA9IGZsdXNoO1xuICByZXR1cm4gZGVib3VuY2VkO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSB0aHJvdHRsZWQgZnVuY3Rpb24gdGhhdCBvbmx5IGludm9rZXMgYGZ1bmNgIGF0IG1vc3Qgb25jZSBwZXJcbiAqIGV2ZXJ5IGB3YWl0YCBtaWxsaXNlY29uZHMuIFRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgXG4gKiBtZXRob2QgdG8gY2FuY2VsIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvXG4gKiBpbW1lZGlhdGVseSBpbnZva2UgdGhlbS4gUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2BcbiAqIHNob3VsZCBiZSBpbnZva2VkIG9uIHRoZSBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGBcbiAqIHRpbWVvdXQuIFRoZSBgZnVuY2AgaXMgaW52b2tlZCB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGVcbiAqIHRocm90dGxlZCBmdW5jdGlvbi4gU3Vic2VxdWVudCBjYWxscyB0byB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uIHJldHVybiB0aGVcbiAqIHJlc3VsdCBvZiB0aGUgbGFzdCBgZnVuY2AgaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIHRocm90dGxlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy50aHJvdHRsZWAgYW5kIGBfLmRlYm91bmNlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHRocm90dGxlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHRocm90dGxlIGludm9jYXRpb25zIHRvLlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHRocm90dGxlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgZXhjZXNzaXZlbHkgdXBkYXRpbmcgdGhlIHBvc2l0aW9uIHdoaWxlIHNjcm9sbGluZy5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdzY3JvbGwnLCBfLnRocm90dGxlKHVwZGF0ZVBvc2l0aW9uLCAxMDApKTtcbiAqXG4gKiAvLyBJbnZva2UgYHJlbmV3VG9rZW5gIHdoZW4gdGhlIGNsaWNrIGV2ZW50IGlzIGZpcmVkLCBidXQgbm90IG1vcmUgdGhhbiBvbmNlIGV2ZXJ5IDUgbWludXRlcy5cbiAqIHZhciB0aHJvdHRsZWQgPSBfLnRocm90dGxlKHJlbmV3VG9rZW4sIDMwMDAwMCwgeyAndHJhaWxpbmcnOiBmYWxzZSB9KTtcbiAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCB0aHJvdHRsZWQpO1xuICpcbiAqIC8vIENhbmNlbCB0aGUgdHJhaWxpbmcgdGhyb3R0bGVkIGludm9jYXRpb24uXG4gKiBqUXVlcnkod2luZG93KS5vbigncG9wc3RhdGUnLCB0aHJvdHRsZWQuY2FuY2VsKTtcbiAqL1xuZnVuY3Rpb24gdGhyb3R0bGUoZnVuYywgd2FpdCwgb3B0aW9ucykge1xuICB2YXIgbGVhZGluZyA9IHRydWUsXG4gICAgICB0cmFpbGluZyA9IHRydWU7XG5cbiAgaWYgKHR5cGVvZiBmdW5jICE9ICdmdW5jdGlvbicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEZVTkNfRVJST1JfVEVYVCk7XG4gIH1cbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICdsZWFkaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLmxlYWRpbmcgOiBsZWFkaW5nO1xuICAgIHRyYWlsaW5nID0gJ3RyYWlsaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLnRyYWlsaW5nIDogdHJhaWxpbmc7XG4gIH1cbiAgcmV0dXJuIGRlYm91bmNlKGZ1bmMsIHdhaXQsIHtcbiAgICAnbGVhZGluZyc6IGxlYWRpbmcsXG4gICAgJ21heFdhaXQnOiB3YWl0LFxuICAgICd0cmFpbGluZyc6IHRyYWlsaW5nXG4gIH0pO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIHRoZVxuICogW2xhbmd1YWdlIHR5cGVdKGh0dHA6Ly93d3cuZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi83LjAvI3NlYy1lY21hc2NyaXB0LWxhbmd1YWdlLXR5cGVzKVxuICogb2YgYE9iamVjdGAuIChlLmcuIGFycmF5cywgZnVuY3Rpb25zLCBvYmplY3RzLCByZWdleGVzLCBgbmV3IE51bWJlcigwKWAsIGFuZCBgbmV3IFN0cmluZygnJylgKVxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIGFuIG9iamVjdCwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0KHt9KTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0KFsxLCAyLCAzXSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdChfLm5vb3ApO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3QobnVsbCk7XG4gKiAvLyA9PiBmYWxzZVxuICovXG5mdW5jdGlvbiBpc09iamVjdCh2YWx1ZSkge1xuICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgcmV0dXJuICEhdmFsdWUgJiYgKHR5cGUgPT0gJ29iamVjdCcgfHwgdHlwZSA9PSAnZnVuY3Rpb24nKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZS4gQSB2YWx1ZSBpcyBvYmplY3QtbGlrZSBpZiBpdCdzIG5vdCBgbnVsbGBcbiAqIGFuZCBoYXMgYSBgdHlwZW9mYCByZXN1bHQgb2YgXCJvYmplY3RcIi5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZSwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZSh7fSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdExpa2UoWzEsIDIsIDNdKTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShfLm5vb3ApO1xuICogLy8gPT4gZmFsc2VcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShudWxsKTtcbiAqIC8vID0+IGZhbHNlXG4gKi9cbmZ1bmN0aW9uIGlzT2JqZWN0TGlrZSh2YWx1ZSkge1xuICByZXR1cm4gISF2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCc7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgY2xhc3NpZmllZCBhcyBhIGBTeW1ib2xgIHByaW1pdGl2ZSBvciBvYmplY3QuXG4gKlxuICogQHN0YXRpY1xuICogQG1lbWJlck9mIF9cbiAqIEBzaW5jZSA0LjAuMFxuICogQGNhdGVnb3J5IExhbmdcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYSBzeW1ib2wsIGVsc2UgYGZhbHNlYC5cbiAqIEBleGFtcGxlXG4gKlxuICogXy5pc1N5bWJvbChTeW1ib2wuaXRlcmF0b3IpO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNTeW1ib2woJ2FiYycpO1xuICogLy8gPT4gZmFsc2VcbiAqL1xuZnVuY3Rpb24gaXNTeW1ib2wodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PSAnc3ltYm9sJyB8fFxuICAgIChpc09iamVjdExpa2UodmFsdWUpICYmIG9iamVjdFRvU3RyaW5nLmNhbGwodmFsdWUpID09IHN5bWJvbFRhZyk7XG59XG5cbi8qKlxuICogQ29udmVydHMgYHZhbHVlYCB0byBhIG51bWJlci5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcHJvY2Vzcy5cbiAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIG51bWJlci5cbiAqIEBleGFtcGxlXG4gKlxuICogXy50b051bWJlcigzLjIpO1xuICogLy8gPT4gMy4yXG4gKlxuICogXy50b051bWJlcihOdW1iZXIuTUlOX1ZBTFVFKTtcbiAqIC8vID0+IDVlLTMyNFxuICpcbiAqIF8udG9OdW1iZXIoSW5maW5pdHkpO1xuICogLy8gPT4gSW5maW5pdHlcbiAqXG4gKiBfLnRvTnVtYmVyKCczLjInKTtcbiAqIC8vID0+IDMuMlxuICovXG5mdW5jdGlvbiB0b051bWJlcih2YWx1ZSkge1xuICBpZiAodHlwZW9mIHZhbHVlID09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG4gIGlmIChpc1N5bWJvbCh2YWx1ZSkpIHtcbiAgICByZXR1cm4gTkFOO1xuICB9XG4gIGlmIChpc09iamVjdCh2YWx1ZSkpIHtcbiAgICB2YXIgb3RoZXIgPSB0eXBlb2YgdmFsdWUudmFsdWVPZiA9PSAnZnVuY3Rpb24nID8gdmFsdWUudmFsdWVPZigpIDogdmFsdWU7XG4gICAgdmFsdWUgPSBpc09iamVjdChvdGhlcikgPyAob3RoZXIgKyAnJykgOiBvdGhlcjtcbiAgfVxuICBpZiAodHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHZhbHVlID09PSAwID8gdmFsdWUgOiArdmFsdWU7XG4gIH1cbiAgdmFsdWUgPSB2YWx1ZS5yZXBsYWNlKHJlVHJpbSwgJycpO1xuICB2YXIgaXNCaW5hcnkgPSByZUlzQmluYXJ5LnRlc3QodmFsdWUpO1xuICByZXR1cm4gKGlzQmluYXJ5IHx8IHJlSXNPY3RhbC50ZXN0KHZhbHVlKSlcbiAgICA/IGZyZWVQYXJzZUludCh2YWx1ZS5zbGljZSgyKSwgaXNCaW5hcnkgPyAyIDogOClcbiAgICA6IChyZUlzQmFkSGV4LnRlc3QodmFsdWUpID8gTkFOIDogK3ZhbHVlKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB0aHJvdHRsZTtcbiIsInZhciBnO1xuXG4vLyBUaGlzIHdvcmtzIGluIG5vbi1zdHJpY3QgbW9kZVxuZyA9IChmdW5jdGlvbigpIHtcblx0cmV0dXJuIHRoaXM7XG59KSgpO1xuXG50cnkge1xuXHQvLyBUaGlzIHdvcmtzIGlmIGV2YWwgaXMgYWxsb3dlZCAoc2VlIENTUClcblx0ZyA9IGcgfHwgbmV3IEZ1bmN0aW9uKFwicmV0dXJuIHRoaXNcIikoKTtcbn0gY2F0Y2ggKGUpIHtcblx0Ly8gVGhpcyB3b3JrcyBpZiB0aGUgd2luZG93IHJlZmVyZW5jZSBpcyBhdmFpbGFibGVcblx0aWYgKHR5cGVvZiB3aW5kb3cgPT09IFwib2JqZWN0XCIpIGcgPSB3aW5kb3c7XG59XG5cbi8vIGcgY2FuIHN0aWxsIGJlIHVuZGVmaW5lZCwgYnV0IG5vdGhpbmcgdG8gZG8gYWJvdXQgaXQuLi5cbi8vIFdlIHJldHVybiB1bmRlZmluZWQsIGluc3RlYWQgb2Ygbm90aGluZyBoZXJlLCBzbyBpdCdzXG4vLyBlYXNpZXIgdG8gaGFuZGxlIHRoaXMgY2FzZS4gaWYoIWdsb2JhbCkgeyAuLi59XG5cbm1vZHVsZS5leHBvcnRzID0gZztcbiJdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file diff --git a/extensions/markdown-language-features/media/markdown.css b/extensions/markdown-language-features/media/markdown.css index 48defb83345..5c06f2b082f 100644 --- a/extensions/markdown-language-features/media/markdown.css +++ b/extensions/markdown-language-features/media/markdown.css @@ -129,15 +129,6 @@ h1, h2, h3 { font-weight: normal; } -h1 code, -h2 code, -h3 code, -h4 code, -h5 code, -h6 code { - line-height: auto; -} - table { border-collapse: collapse; } diff --git a/extensions/markdown-language-features/media/pre.js b/extensions/markdown-language-features/media/pre.js index 5c9c7fb3b8b..bddc3b86ac5 100644 --- a/extensions/markdown-language-features/media/pre.js +++ b/extensions/markdown-language-features/media/pre.js @@ -1,280 +1,2 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = "./preview-src/pre.ts"); -/******/ }) -/************************************************************************/ -/******/ ({ - -/***/ "./preview-src/csp.ts": -/*!****************************!*\ - !*** ./preview-src/csp.ts ***! - \****************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 settings_1 = __webpack_require__(/*! ./settings */ "./preview-src/settings.ts"); -const strings_1 = __webpack_require__(/*! ./strings */ "./preview-src/strings.ts"); -/** - * Shows an alert when there is a content security policy violation. - */ -class CspAlerter { - constructor() { - this.didShow = false; - this.didHaveCspWarning = false; - document.addEventListener('securitypolicyviolation', () => { - this.onCspWarning(); - }); - window.addEventListener('message', (event) => { - if (event && event.data && event.data.name === 'vscode-did-block-svg') { - this.onCspWarning(); - } - }); - } - setPoster(poster) { - this.messaging = poster; - if (this.didHaveCspWarning) { - this.showCspWarning(); - } - } - onCspWarning() { - this.didHaveCspWarning = true; - this.showCspWarning(); - } - showCspWarning() { - const strings = strings_1.getStrings(); - const settings = settings_1.getSettings(); - if (this.didShow || settings.disableSecurityWarnings || !this.messaging) { - return; - } - this.didShow = true; - const notification = document.createElement('a'); - notification.innerText = strings.cspAlertMessageText; - notification.setAttribute('id', 'code-csp-warning'); - notification.setAttribute('title', strings.cspAlertMessageTitle); - notification.setAttribute('role', 'button'); - notification.setAttribute('aria-label', strings.cspAlertMessageLabel); - notification.onclick = () => { - this.messaging.postMessage('showPreviewSecuritySelector', { source: settings.source }); - }; - document.body.appendChild(notification); - } -} -exports.CspAlerter = CspAlerter; - - -/***/ }), - -/***/ "./preview-src/loading.ts": -/*!********************************!*\ - !*** ./preview-src/loading.ts ***! - \********************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -class StyleLoadingMonitor { - constructor() { - this.unloadedStyles = []; - this.finishedLoading = false; - const onStyleLoadError = (event) => { - const source = event.target.dataset.source; - this.unloadedStyles.push(source); - }; - window.addEventListener('DOMContentLoaded', () => { - for (const link of document.getElementsByClassName('code-user-style')) { - if (link.dataset.source) { - link.onerror = onStyleLoadError; - } - } - }); - window.addEventListener('load', () => { - if (!this.unloadedStyles.length) { - return; - } - this.finishedLoading = true; - if (this.poster) { - this.poster.postMessage('previewStyleLoadError', { unloadedStyles: this.unloadedStyles }); - } - }); - } - setPoster(poster) { - this.poster = poster; - if (this.finishedLoading) { - poster.postMessage('previewStyleLoadError', { unloadedStyles: this.unloadedStyles }); - } - } -} -exports.StyleLoadingMonitor = StyleLoadingMonitor; - - -/***/ }), - -/***/ "./preview-src/pre.ts": -/*!****************************!*\ - !*** ./preview-src/pre.ts ***! - \****************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 csp_1 = __webpack_require__(/*! ./csp */ "./preview-src/csp.ts"); -const loading_1 = __webpack_require__(/*! ./loading */ "./preview-src/loading.ts"); -window.cspAlerter = new csp_1.CspAlerter(); -window.styleLoadingMonitor = new loading_1.StyleLoadingMonitor(); - - -/***/ }), - -/***/ "./preview-src/settings.ts": -/*!*********************************!*\ - !*** ./preview-src/settings.ts ***! - \*********************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 }); -let cachedSettings = undefined; -function getData(key) { - const element = document.getElementById('vscode-markdown-preview-data'); - if (element) { - const data = element.getAttribute(key); - if (data) { - return JSON.parse(data); - } - } - throw new Error(`Could not load data for ${key}`); -} -exports.getData = getData; -function getSettings() { - if (cachedSettings) { - return cachedSettings; - } - cachedSettings = getData('data-settings'); - if (cachedSettings) { - return cachedSettings; - } - throw new Error('Could not load settings'); -} -exports.getSettings = getSettings; - - -/***/ }), - -/***/ "./preview-src/strings.ts": -/*!********************************!*\ - !*** ./preview-src/strings.ts ***! - \********************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -"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 }); -function getStrings() { - const store = document.getElementById('vscode-markdown-preview-data'); - if (store) { - const data = store.getAttribute('data-strings'); - if (data) { - return JSON.parse(data); - } - } - throw new Error('Could not load strings'); -} -exports.getStrings = getStrings; - - -/***/ }) - -/******/ }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvY3NwLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2xvYWRpbmcudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvcHJlLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3NldHRpbmdzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL3N0cmluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0EseURBQWlELGNBQWM7QUFDL0Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUNBQTJCLDBCQUEwQixFQUFFO0FBQ3ZELHlDQUFpQyxlQUFlO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhEQUFzRCwrREFBK0Q7O0FBRXJIO0FBQ0E7OztBQUdBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUNuRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QyxjQUFjO0FBQzVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1RUFBdUUsMEJBQTBCO0FBQ2pHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUNyREE7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtFQUFrRSxzQ0FBc0M7QUFDeEc7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5REFBeUQsc0NBQXNDO0FBQy9GO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7O0FDbENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0MsSUFBSTtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzVCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLGNBQWM7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJwcmUuanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHtcbiBcdFx0XHRcdGNvbmZpZ3VyYWJsZTogZmFsc2UsXG4gXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuIFx0XHRcdFx0Z2V0OiBnZXR0ZXJcbiBcdFx0XHR9KTtcbiBcdFx0fVxuIFx0fTtcblxuIFx0Ly8gZGVmaW5lIF9fZXNNb2R1bGUgb24gZXhwb3J0c1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5yID0gZnVuY3Rpb24oZXhwb3J0cykge1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9wcmV2aWV3LXNyYy9wcmUudHNcIik7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3Qgc2V0dGluZ3NfMSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzXCIpO1xuY29uc3Qgc3RyaW5nc18xID0gcmVxdWlyZShcIi4vc3RyaW5nc1wiKTtcbi8qKlxuICogU2hvd3MgYW4gYWxlcnQgd2hlbiB0aGVyZSBpcyBhIGNvbnRlbnQgc2VjdXJpdHkgcG9saWN5IHZpb2xhdGlvbi5cbiAqL1xuY2xhc3MgQ3NwQWxlcnRlciB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuZGlkU2hvdyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmRpZEhhdmVDc3BXYXJuaW5nID0gZmFsc2U7XG4gICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3NlY3VyaXR5cG9saWN5dmlvbGF0aW9uJywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5vbkNzcFdhcm5pbmcoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICBpZiAoZXZlbnQgJiYgZXZlbnQuZGF0YSAmJiBldmVudC5kYXRhLm5hbWUgPT09ICd2c2NvZGUtZGlkLWJsb2NrLXN2ZycpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm9uQ3NwV2FybmluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgc2V0UG9zdGVyKHBvc3Rlcikge1xuICAgICAgICB0aGlzLm1lc3NhZ2luZyA9IHBvc3RlcjtcbiAgICAgICAgaWYgKHRoaXMuZGlkSGF2ZUNzcFdhcm5pbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2hvd0NzcFdhcm5pbmcoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBvbkNzcFdhcm5pbmcoKSB7XG4gICAgICAgIHRoaXMuZGlkSGF2ZUNzcFdhcm5pbmcgPSB0cnVlO1xuICAgICAgICB0aGlzLnNob3dDc3BXYXJuaW5nKCk7XG4gICAgfVxuICAgIHNob3dDc3BXYXJuaW5nKCkge1xuICAgICAgICBjb25zdCBzdHJpbmdzID0gc3RyaW5nc18xLmdldFN0cmluZ3MoKTtcbiAgICAgICAgY29uc3Qgc2V0dGluZ3MgPSBzZXR0aW5nc18xLmdldFNldHRpbmdzKCk7XG4gICAgICAgIGlmICh0aGlzLmRpZFNob3cgfHwgc2V0dGluZ3MuZGlzYWJsZVNlY3VyaXR5V2FybmluZ3MgfHwgIXRoaXMubWVzc2FnaW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kaWRTaG93ID0gdHJ1ZTtcbiAgICAgICAgY29uc3Qgbm90aWZpY2F0aW9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuICAgICAgICBub3RpZmljYXRpb24uaW5uZXJUZXh0ID0gc3RyaW5ncy5jc3BBbGVydE1lc3NhZ2VUZXh0O1xuICAgICAgICBub3RpZmljYXRpb24uc2V0QXR0cmlidXRlKCdpZCcsICdjb2RlLWNzcC13YXJuaW5nJyk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3RpdGxlJywgc3RyaW5ncy5jc3BBbGVydE1lc3NhZ2VUaXRsZSk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnYnV0dG9uJyk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGFiZWwnLCBzdHJpbmdzLmNzcEFsZXJ0TWVzc2FnZUxhYmVsKTtcbiAgICAgICAgbm90aWZpY2F0aW9uLm9uY2xpY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2luZy5wb3N0TWVzc2FnZSgnc2hvd1ByZXZpZXdTZWN1cml0eVNlbGVjdG9yJywgeyBzb3VyY2U6IHNldHRpbmdzLnNvdXJjZSB9KTtcbiAgICAgICAgfTtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChub3RpZmljYXRpb24pO1xuICAgIH1cbn1cbmV4cG9ydHMuQ3NwQWxlcnRlciA9IENzcEFsZXJ0ZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmNsYXNzIFN0eWxlTG9hZGluZ01vbml0b3Ige1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnVubG9hZGVkU3R5bGVzID0gW107XG4gICAgICAgIHRoaXMuZmluaXNoZWRMb2FkaW5nID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IG9uU3R5bGVMb2FkRXJyb3IgPSAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHNvdXJjZSA9IGV2ZW50LnRhcmdldC5kYXRhc2V0LnNvdXJjZTtcbiAgICAgICAgICAgIHRoaXMudW5sb2FkZWRTdHlsZXMucHVzaChzb3VyY2UpO1xuICAgICAgICB9O1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsICgpID0+IHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgbGluayBvZiBkb2N1bWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCdjb2RlLXVzZXItc3R5bGUnKSkge1xuICAgICAgICAgICAgICAgIGlmIChsaW5rLmRhdGFzZXQuc291cmNlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxpbmsub25lcnJvciA9IG9uU3R5bGVMb2FkRXJyb3I7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMudW5sb2FkZWRTdHlsZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5maW5pc2hlZExvYWRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgaWYgKHRoaXMucG9zdGVyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wb3N0ZXIucG9zdE1lc3NhZ2UoJ3ByZXZpZXdTdHlsZUxvYWRFcnJvcicsIHsgdW5sb2FkZWRTdHlsZXM6IHRoaXMudW5sb2FkZWRTdHlsZXMgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBzZXRQb3N0ZXIocG9zdGVyKSB7XG4gICAgICAgIHRoaXMucG9zdGVyID0gcG9zdGVyO1xuICAgICAgICBpZiAodGhpcy5maW5pc2hlZExvYWRpbmcpIHtcbiAgICAgICAgICAgIHBvc3Rlci5wb3N0TWVzc2FnZSgncHJldmlld1N0eWxlTG9hZEVycm9yJywgeyB1bmxvYWRlZFN0eWxlczogdGhpcy51bmxvYWRlZFN0eWxlcyB9KTtcbiAgICAgICAgfVxuICAgIH1cbn1cbmV4cG9ydHMuU3R5bGVMb2FkaW5nTW9uaXRvciA9IFN0eWxlTG9hZGluZ01vbml0b3I7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgY3NwXzEgPSByZXF1aXJlKFwiLi9jc3BcIik7XG5jb25zdCBsb2FkaW5nXzEgPSByZXF1aXJlKFwiLi9sb2FkaW5nXCIpO1xud2luZG93LmNzcEFsZXJ0ZXIgPSBuZXcgY3NwXzEuQ3NwQWxlcnRlcigpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3IgPSBuZXcgbG9hZGluZ18xLlN0eWxlTG9hZGluZ01vbml0b3IoKTtcbiIsIlwidXNlIHN0cmljdFwiO1xuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5sZXQgY2FjaGVkU2V0dGluZ3MgPSB1bmRlZmluZWQ7XG5mdW5jdGlvbiBnZXREYXRhKGtleSkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndnNjb2RlLW1hcmtkb3duLXByZXZpZXctZGF0YScpO1xuICAgIGlmIChlbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBlbGVtZW50LmdldEF0dHJpYnV0ZShrZXkpO1xuICAgICAgICBpZiAoZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgbG9hZCBkYXRhIGZvciAke2tleX1gKTtcbn1cbmV4cG9ydHMuZ2V0RGF0YSA9IGdldERhdGE7XG5mdW5jdGlvbiBnZXRTZXR0aW5ncygpIHtcbiAgICBpZiAoY2FjaGVkU2V0dGluZ3MpIHtcbiAgICAgICAgcmV0dXJuIGNhY2hlZFNldHRpbmdzO1xuICAgIH1cbiAgICBjYWNoZWRTZXR0aW5ncyA9IGdldERhdGEoJ2RhdGEtc2V0dGluZ3MnKTtcbiAgICBpZiAoY2FjaGVkU2V0dGluZ3MpIHtcbiAgICAgICAgcmV0dXJuIGNhY2hlZFNldHRpbmdzO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBsb2FkIHNldHRpbmdzJyk7XG59XG5leHBvcnRzLmdldFNldHRpbmdzID0gZ2V0U2V0dGluZ3M7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gZ2V0U3RyaW5ncygpIHtcbiAgICBjb25zdCBzdG9yZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKHN0b3JlKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBzdG9yZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3RyaW5ncycpO1xuICAgICAgICBpZiAoZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzdHJpbmdzJyk7XG59XG5leHBvcnRzLmdldFN0cmluZ3MgPSBnZXRTdHJpbmdzO1xuIl0sInNvdXJjZVJvb3QiOiIifQ== \ No newline at end of file +!function(e){var t={};function n(s){if(t[s])return t[s].exports;var o=t[s]={i:s,l:!1,exports:{}};return e[s].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,s){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(n.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(s,o,function(t){return e[t]}.bind(null,o));return s},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=8)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});let s=void 0;function o(e){const t=document.getElementById("vscode-markdown-preview-data");if(t){const n=t.getAttribute(e);if(n)return JSON.parse(n)}throw new Error(`Could not load data for ${e}`)}t.getData=o,t.getSettings=function(){if(s)return s;if(s=o("data-settings"))return s;throw new Error("Could not load settings")}},,,,,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const s=n(9),o=n(11);window.cspAlerter=new s.CspAlerter,window.styleLoadingMonitor=new o.StyleLoadingMonitor},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const s=n(0),o=n(10);t.CspAlerter=class{constructor(){this.didShow=!1,this.didHaveCspWarning=!1,document.addEventListener("securitypolicyviolation",()=>{this.onCspWarning()}),window.addEventListener("message",e=>{e&&e.data&&"vscode-did-block-svg"===e.data.name&&this.onCspWarning()})}setPoster(e){this.messaging=e,this.didHaveCspWarning&&this.showCspWarning()}onCspWarning(){this.didHaveCspWarning=!0,this.showCspWarning()}showCspWarning(){const e=o.getStrings(),t=s.getSettings();if(this.didShow||t.disableSecurityWarnings||!this.messaging)return;this.didShow=!0;const n=document.createElement("a");n.innerText=e.cspAlertMessageText,n.setAttribute("id","code-csp-warning"),n.setAttribute("title",e.cspAlertMessageTitle),n.setAttribute("role","button"),n.setAttribute("aria-label",e.cspAlertMessageLabel),n.onclick=()=>{this.messaging.postMessage("showPreviewSecuritySelector",{source:t.source})},document.body.appendChild(n)}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getStrings=function(){const e=document.getElementById("vscode-markdown-preview-data");if(e){const t=e.getAttribute("data-strings");if(t)return JSON.parse(t)}throw new Error("Could not load strings")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});t.StyleLoadingMonitor=class{constructor(){this.unloadedStyles=[],this.finishedLoading=!1;const e=e=>{const t=e.target.dataset.source;this.unloadedStyles.push(t)};window.addEventListener("DOMContentLoaded",()=>{for(const t of document.getElementsByClassName("code-user-style"))t.dataset.source&&(t.onerror=e)}),window.addEventListener("load",()=>{this.unloadedStyles.length&&(this.finishedLoading=!0,this.poster&&this.poster.postMessage("previewStyleLoadError",{unloadedStyles:this.unloadedStyles}))})}setPoster(e){this.poster=e,this.finishedLoading&&e.postMessage("previewStyleLoadError",{unloadedStyles:this.unloadedStyles})}}}]); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvc2V0dGluZ3MudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvcHJlLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2NzcC50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9zdHJpbmdzLnRzIiwid2VicGFjazovLy8uL3ByZXZpZXctc3JjL2xvYWRpbmcudHMiXSwibmFtZXMiOlsiaW5zdGFsbGVkTW9kdWxlcyIsIl9fd2VicGFja19yZXF1aXJlX18iLCJtb2R1bGVJZCIsImV4cG9ydHMiLCJtb2R1bGUiLCJpIiwibCIsIm1vZHVsZXMiLCJjYWxsIiwibSIsImMiLCJkIiwibmFtZSIsImdldHRlciIsIm8iLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImVudW1lcmFibGUiLCJnZXQiLCJyIiwiU3ltYm9sIiwidG9TdHJpbmdUYWciLCJ2YWx1ZSIsInQiLCJtb2RlIiwiX19lc01vZHVsZSIsIm5zIiwiY3JlYXRlIiwia2V5IiwiYmluZCIsIm4iLCJvYmplY3QiLCJwcm9wZXJ0eSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwicCIsInMiLCJjYWNoZWRTZXR0aW5ncyIsInVuZGVmaW5lZCIsImdldERhdGEiLCJlbGVtZW50IiwiZG9jdW1lbnQiLCJnZXRFbGVtZW50QnlJZCIsImRhdGEiLCJnZXRBdHRyaWJ1dGUiLCJKU09OIiwicGFyc2UiLCJFcnJvciIsImdldFNldHRpbmdzIiwiY3NwXzEiLCJsb2FkaW5nXzEiLCJ3aW5kb3ciLCJjc3BBbGVydGVyIiwiQ3NwQWxlcnRlciIsInN0eWxlTG9hZGluZ01vbml0b3IiLCJTdHlsZUxvYWRpbmdNb25pdG9yIiwic2V0dGluZ3NfMSIsInN0cmluZ3NfMSIsInRoaXMiLCJkaWRTaG93IiwiZGlkSGF2ZUNzcFdhcm5pbmciLCJhZGRFdmVudExpc3RlbmVyIiwib25Dc3BXYXJuaW5nIiwiZXZlbnQiLCJwb3N0ZXIiLCJtZXNzYWdpbmciLCJzaG93Q3NwV2FybmluZyIsInN0cmluZ3MiLCJnZXRTdHJpbmdzIiwic2V0dGluZ3MiLCJkaXNhYmxlU2VjdXJpdHlXYXJuaW5ncyIsIm5vdGlmaWNhdGlvbiIsImNyZWF0ZUVsZW1lbnQiLCJpbm5lclRleHQiLCJjc3BBbGVydE1lc3NhZ2VUZXh0Iiwic2V0QXR0cmlidXRlIiwiY3NwQWxlcnRNZXNzYWdlVGl0bGUiLCJjc3BBbGVydE1lc3NhZ2VMYWJlbCIsIm9uY2xpY2siLCJwb3N0TWVzc2FnZSIsInNvdXJjZSIsImJvZHkiLCJhcHBlbmRDaGlsZCIsInN0b3JlIiwidW5sb2FkZWRTdHlsZXMiLCJmaW5pc2hlZExvYWRpbmciLCJvblN0eWxlTG9hZEVycm9yIiwidGFyZ2V0IiwiZGF0YXNldCIsInB1c2giLCJsaW5rIiwiZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSIsIm9uZXJyb3IiLCJsZW5ndGgiXSwibWFwcGluZ3MiOiJhQUNFLElBQUlBLEVBQW1CLEdBR3ZCLFNBQVNDLEVBQW9CQyxHQUc1QixHQUFHRixFQUFpQkUsR0FDbkIsT0FBT0YsRUFBaUJFLEdBQVVDLFFBR25DLElBQUlDLEVBQVNKLEVBQWlCRSxHQUFZLENBQ3pDRyxFQUFHSCxFQUNISSxHQUFHLEVBQ0hILFFBQVMsSUFVVixPQU5BSSxFQUFRTCxHQUFVTSxLQUFLSixFQUFPRCxRQUFTQyxFQUFRQSxFQUFPRCxRQUFTRixHQUcvREcsRUFBT0UsR0FBSSxFQUdKRixFQUFPRCxRQUtmRixFQUFvQlEsRUFBSUYsRUFHeEJOLEVBQW9CUyxFQUFJVixFQUd4QkMsRUFBb0JVLEVBQUksU0FBU1IsRUFBU1MsRUFBTUMsR0FDM0NaLEVBQW9CYSxFQUFFWCxFQUFTUyxJQUNsQ0csT0FBT0MsZUFBZWIsRUFBU1MsRUFBTSxDQUFFSyxZQUFZLEVBQU1DLElBQUtMLEtBS2hFWixFQUFvQmtCLEVBQUksU0FBU2hCLEdBQ1gsb0JBQVhpQixRQUEwQkEsT0FBT0MsYUFDMUNOLE9BQU9DLGVBQWViLEVBQVNpQixPQUFPQyxZQUFhLENBQUVDLE1BQU8sV0FFN0RQLE9BQU9DLGVBQWViLEVBQVMsYUFBYyxDQUFFbUIsT0FBTyxLQVF2RHJCLEVBQW9Cc0IsRUFBSSxTQUFTRCxFQUFPRSxHQUV2QyxHQURVLEVBQVBBLElBQVVGLEVBQVFyQixFQUFvQnFCLElBQy9CLEVBQVBFLEVBQVUsT0FBT0YsRUFDcEIsR0FBVyxFQUFQRSxHQUE4QixpQkFBVkYsR0FBc0JBLEdBQVNBLEVBQU1HLFdBQVksT0FBT0gsRUFDaEYsSUFBSUksRUFBS1gsT0FBT1ksT0FBTyxNQUd2QixHQUZBMUIsRUFBb0JrQixFQUFFTyxHQUN0QlgsT0FBT0MsZUFBZVUsRUFBSSxVQUFXLENBQUVULFlBQVksRUFBTUssTUFBT0EsSUFDdEQsRUFBUEUsR0FBNEIsaUJBQVRGLEVBQW1CLElBQUksSUFBSU0sS0FBT04sRUFBT3JCLEVBQW9CVSxFQUFFZSxFQUFJRSxFQUFLLFNBQVNBLEdBQU8sT0FBT04sRUFBTU0sSUFBUUMsS0FBSyxLQUFNRCxJQUM5SSxPQUFPRixHQUlSekIsRUFBb0I2QixFQUFJLFNBQVMxQixHQUNoQyxJQUFJUyxFQUFTVCxHQUFVQSxFQUFPcUIsV0FDN0IsV0FBd0IsT0FBT3JCLEVBQWdCLFNBQy9DLFdBQThCLE9BQU9BLEdBRXRDLE9BREFILEVBQW9CVSxFQUFFRSxFQUFRLElBQUtBLEdBQzVCQSxHQUlSWixFQUFvQmEsRUFBSSxTQUFTaUIsRUFBUUMsR0FBWSxPQUFPakIsT0FBT2tCLFVBQVVDLGVBQWUxQixLQUFLdUIsRUFBUUMsSUFHekcvQixFQUFvQmtDLEVBQUksR0FJakJsQyxFQUFvQkEsRUFBb0JtQyxFQUFJLEcsK0JDN0VyRHJCLE9BQU9DLGVBQWViLEVBQVMsYUFBYyxDQUFFbUIsT0FBTyxJQUN0RCxJQUFJZSxPQUFpQkMsRUFDckIsU0FBU0MsRUFBUVgsR0FDYixNQUFNWSxFQUFVQyxTQUFTQyxlQUFlLGdDQUN4QyxHQUFJRixFQUFTLENBQ1QsTUFBTUcsRUFBT0gsRUFBUUksYUFBYWhCLEdBQ2xDLEdBQUllLEVBQ0EsT0FBT0UsS0FBS0MsTUFBTUgsR0FHMUIsTUFBTSxJQUFJSSxNQUFNLDJCQUEyQm5CLEtBRS9DekIsRUFBUW9DLFFBQVVBLEVBV2xCcEMsRUFBUTZDLFlBVlIsV0FDSSxHQUFJWCxFQUNBLE9BQU9BLEVBR1gsR0FEQUEsRUFBaUJFLEVBQVEsaUJBRXJCLE9BQU9GLEVBRVgsTUFBTSxJQUFJVSxNQUFNLDZCLG9DQ3JCcEJoQyxPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sSUFDdEQsTUFBTTJCLEVBQVEsRUFBUSxHQUNoQkMsRUFBWSxFQUFRLElBQzFCQyxPQUFPQyxXQUFhLElBQUlILEVBQU1JLFdBQzlCRixPQUFPRyxvQkFBc0IsSUFBSUosRUFBVUsscUIsNkJDSjNDeEMsT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBQ3RELE1BQU1rQyxFQUFhLEVBQVEsR0FDckJDLEVBQVksRUFBUSxJQThDMUJ0RCxFQUFRa0QsV0ExQ1IsTUFDSSxjQUNJSyxLQUFLQyxTQUFVLEVBQ2ZELEtBQUtFLG1CQUFvQixFQUN6Qm5CLFNBQVNvQixpQkFBaUIsMEJBQTJCLEtBQ2pESCxLQUFLSSxpQkFFVFgsT0FBT1UsaUJBQWlCLFVBQVlFLElBQzVCQSxHQUFTQSxFQUFNcEIsTUFBNEIseUJBQXBCb0IsRUFBTXBCLEtBQUsvQixNQUNsQzhDLEtBQUtJLGlCQUlqQixVQUFVRSxHQUNOTixLQUFLTyxVQUFZRCxFQUNiTixLQUFLRSxtQkFDTEYsS0FBS1EsaUJBR2IsZUFDSVIsS0FBS0UsbUJBQW9CLEVBQ3pCRixLQUFLUSxpQkFFVCxpQkFDSSxNQUFNQyxFQUFVVixFQUFVVyxhQUNwQkMsRUFBV2IsRUFBV1IsY0FDNUIsR0FBSVUsS0FBS0MsU0FBV1UsRUFBU0MsMEJBQTRCWixLQUFLTyxVQUMxRCxPQUVKUCxLQUFLQyxTQUFVLEVBQ2YsTUFBTVksRUFBZTlCLFNBQVMrQixjQUFjLEtBQzVDRCxFQUFhRSxVQUFZTixFQUFRTyxvQkFDakNILEVBQWFJLGFBQWEsS0FBTSxvQkFDaENKLEVBQWFJLGFBQWEsUUFBU1IsRUFBUVMsc0JBQzNDTCxFQUFhSSxhQUFhLE9BQVEsVUFDbENKLEVBQWFJLGFBQWEsYUFBY1IsRUFBUVUsc0JBQ2hETixFQUFhTyxRQUFVLEtBQ25CcEIsS0FBS08sVUFBVWMsWUFBWSw4QkFBK0IsQ0FBRUMsT0FBUVgsRUFBU1csVUFFakZ2QyxTQUFTd0MsS0FBS0MsWUFBWVgsTSw2QkM3Q2xDeEQsT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBV3REbkIsRUFBUWlFLFdBVlIsV0FDSSxNQUFNZSxFQUFRMUMsU0FBU0MsZUFBZSxnQ0FDdEMsR0FBSXlDLEVBQU8sQ0FDUCxNQUFNeEMsRUFBT3dDLEVBQU12QyxhQUFhLGdCQUNoQyxHQUFJRCxFQUNBLE9BQU9FLEtBQUtDLE1BQU1ILEdBRzFCLE1BQU0sSUFBSUksTUFBTSw0Qiw2QkNicEJoQyxPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sSUFpQ3REbkIsRUFBUW9ELG9CQWhDUixNQUNJLGNBQ0lHLEtBQUswQixlQUFpQixHQUN0QjFCLEtBQUsyQixpQkFBa0IsRUFDdkIsTUFBTUMsRUFBb0J2QixJQUN0QixNQUFNaUIsRUFBU2pCLEVBQU13QixPQUFPQyxRQUFRUixPQUNwQ3RCLEtBQUswQixlQUFlSyxLQUFLVCxJQUU3QjdCLE9BQU9VLGlCQUFpQixtQkFBb0IsS0FDeEMsSUFBSyxNQUFNNkIsS0FBUWpELFNBQVNrRCx1QkFBdUIsbUJBQzNDRCxFQUFLRixRQUFRUixTQUNiVSxFQUFLRSxRQUFVTixLQUkzQm5DLE9BQU9VLGlCQUFpQixPQUFRLEtBQ3ZCSCxLQUFLMEIsZUFBZVMsU0FHekJuQyxLQUFLMkIsaUJBQWtCLEVBQ25CM0IsS0FBS00sUUFDTE4sS0FBS00sT0FBT2UsWUFBWSx3QkFBeUIsQ0FBRUssZUFBZ0IxQixLQUFLMEIsb0JBSXBGLFVBQVVwQixHQUNOTixLQUFLTSxPQUFTQSxFQUNWTixLQUFLMkIsaUJBQ0xyQixFQUFPZSxZQUFZLHdCQUF5QixDQUFFSyxlQUFnQjFCLEtBQUswQiIsImZpbGUiOiJwcmUuanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBnZXR0ZXIgfSk7XG4gXHRcdH1cbiBcdH07XG5cbiBcdC8vIGRlZmluZSBfX2VzTW9kdWxlIG9uIGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uciA9IGZ1bmN0aW9uKGV4cG9ydHMpIHtcbiBcdFx0aWYodHlwZW9mIFN5bWJvbCAhPT0gJ3VuZGVmaW5lZCcgJiYgU3ltYm9sLnRvU3RyaW5nVGFnKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFN5bWJvbC50b1N0cmluZ1RhZywgeyB2YWx1ZTogJ01vZHVsZScgfSk7XG4gXHRcdH1cbiBcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcbiBcdH07XG5cbiBcdC8vIGNyZWF0ZSBhIGZha2UgbmFtZXNwYWNlIG9iamVjdFxuIFx0Ly8gbW9kZSAmIDE6IHZhbHVlIGlzIGEgbW9kdWxlIGlkLCByZXF1aXJlIGl0XG4gXHQvLyBtb2RlICYgMjogbWVyZ2UgYWxsIHByb3BlcnRpZXMgb2YgdmFsdWUgaW50byB0aGUgbnNcbiBcdC8vIG1vZGUgJiA0OiByZXR1cm4gdmFsdWUgd2hlbiBhbHJlYWR5IG5zIG9iamVjdFxuIFx0Ly8gbW9kZSAmIDh8MTogYmVoYXZlIGxpa2UgcmVxdWlyZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy50ID0gZnVuY3Rpb24odmFsdWUsIG1vZGUpIHtcbiBcdFx0aWYobW9kZSAmIDEpIHZhbHVlID0gX193ZWJwYWNrX3JlcXVpcmVfXyh2YWx1ZSk7XG4gXHRcdGlmKG1vZGUgJiA4KSByZXR1cm4gdmFsdWU7XG4gXHRcdGlmKChtb2RlICYgNCkgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJiB2YWx1ZS5fX2VzTW9kdWxlKSByZXR1cm4gdmFsdWU7XG4gXHRcdHZhciBucyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18ucihucyk7XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShucywgJ2RlZmF1bHQnLCB7IGVudW1lcmFibGU6IHRydWUsIHZhbHVlOiB2YWx1ZSB9KTtcbiBcdFx0aWYobW9kZSAmIDIgJiYgdHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSBmb3IodmFyIGtleSBpbiB2YWx1ZSkgX193ZWJwYWNrX3JlcXVpcmVfXy5kKG5zLCBrZXksIGZ1bmN0aW9uKGtleSkgeyByZXR1cm4gdmFsdWVba2V5XTsgfS5iaW5kKG51bGwsIGtleSkpO1xuIFx0XHRyZXR1cm4gbnM7XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gOCk7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xubGV0IGNhY2hlZFNldHRpbmdzID0gdW5kZWZpbmVkO1xuZnVuY3Rpb24gZ2V0RGF0YShrZXkpIHtcbiAgICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ZzY29kZS1tYXJrZG93bi1wcmV2aWV3LWRhdGEnKTtcbiAgICBpZiAoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBkYXRhID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoa2V5KTtcbiAgICAgICAgaWYgKGRhdGEpIHtcbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGRhdGEpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGxvYWQgZGF0YSBmb3IgJHtrZXl9YCk7XG59XG5leHBvcnRzLmdldERhdGEgPSBnZXREYXRhO1xuZnVuY3Rpb24gZ2V0U2V0dGluZ3MoKSB7XG4gICAgaWYgKGNhY2hlZFNldHRpbmdzKSB7XG4gICAgICAgIHJldHVybiBjYWNoZWRTZXR0aW5ncztcbiAgICB9XG4gICAgY2FjaGVkU2V0dGluZ3MgPSBnZXREYXRhKCdkYXRhLXNldHRpbmdzJyk7XG4gICAgaWYgKGNhY2hlZFNldHRpbmdzKSB7XG4gICAgICAgIHJldHVybiBjYWNoZWRTZXR0aW5ncztcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzZXR0aW5ncycpO1xufVxuZXhwb3J0cy5nZXRTZXR0aW5ncyA9IGdldFNldHRpbmdzO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmNvbnN0IGNzcF8xID0gcmVxdWlyZShcIi4vY3NwXCIpO1xuY29uc3QgbG9hZGluZ18xID0gcmVxdWlyZShcIi4vbG9hZGluZ1wiKTtcbndpbmRvdy5jc3BBbGVydGVyID0gbmV3IGNzcF8xLkNzcEFsZXJ0ZXIoKTtcbndpbmRvdy5zdHlsZUxvYWRpbmdNb25pdG9yID0gbmV3IGxvYWRpbmdfMS5TdHlsZUxvYWRpbmdNb25pdG9yKCk7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3Qgc2V0dGluZ3NfMSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzXCIpO1xuY29uc3Qgc3RyaW5nc18xID0gcmVxdWlyZShcIi4vc3RyaW5nc1wiKTtcbi8qKlxuICogU2hvd3MgYW4gYWxlcnQgd2hlbiB0aGVyZSBpcyBhIGNvbnRlbnQgc2VjdXJpdHkgcG9saWN5IHZpb2xhdGlvbi5cbiAqL1xuY2xhc3MgQ3NwQWxlcnRlciB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuZGlkU2hvdyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmRpZEhhdmVDc3BXYXJuaW5nID0gZmFsc2U7XG4gICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3NlY3VyaXR5cG9saWN5dmlvbGF0aW9uJywgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5vbkNzcFdhcm5pbmcoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICBpZiAoZXZlbnQgJiYgZXZlbnQuZGF0YSAmJiBldmVudC5kYXRhLm5hbWUgPT09ICd2c2NvZGUtZGlkLWJsb2NrLXN2ZycpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm9uQ3NwV2FybmluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgc2V0UG9zdGVyKHBvc3Rlcikge1xuICAgICAgICB0aGlzLm1lc3NhZ2luZyA9IHBvc3RlcjtcbiAgICAgICAgaWYgKHRoaXMuZGlkSGF2ZUNzcFdhcm5pbmcpIHtcbiAgICAgICAgICAgIHRoaXMuc2hvd0NzcFdhcm5pbmcoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBvbkNzcFdhcm5pbmcoKSB7XG4gICAgICAgIHRoaXMuZGlkSGF2ZUNzcFdhcm5pbmcgPSB0cnVlO1xuICAgICAgICB0aGlzLnNob3dDc3BXYXJuaW5nKCk7XG4gICAgfVxuICAgIHNob3dDc3BXYXJuaW5nKCkge1xuICAgICAgICBjb25zdCBzdHJpbmdzID0gc3RyaW5nc18xLmdldFN0cmluZ3MoKTtcbiAgICAgICAgY29uc3Qgc2V0dGluZ3MgPSBzZXR0aW5nc18xLmdldFNldHRpbmdzKCk7XG4gICAgICAgIGlmICh0aGlzLmRpZFNob3cgfHwgc2V0dGluZ3MuZGlzYWJsZVNlY3VyaXR5V2FybmluZ3MgfHwgIXRoaXMubWVzc2FnaW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kaWRTaG93ID0gdHJ1ZTtcbiAgICAgICAgY29uc3Qgbm90aWZpY2F0aW9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuICAgICAgICBub3RpZmljYXRpb24uaW5uZXJUZXh0ID0gc3RyaW5ncy5jc3BBbGVydE1lc3NhZ2VUZXh0O1xuICAgICAgICBub3RpZmljYXRpb24uc2V0QXR0cmlidXRlKCdpZCcsICdjb2RlLWNzcC13YXJuaW5nJyk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3RpdGxlJywgc3RyaW5ncy5jc3BBbGVydE1lc3NhZ2VUaXRsZSk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnYnV0dG9uJyk7XG4gICAgICAgIG5vdGlmaWNhdGlvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGFiZWwnLCBzdHJpbmdzLmNzcEFsZXJ0TWVzc2FnZUxhYmVsKTtcbiAgICAgICAgbm90aWZpY2F0aW9uLm9uY2xpY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2luZy5wb3N0TWVzc2FnZSgnc2hvd1ByZXZpZXdTZWN1cml0eVNlbGVjdG9yJywgeyBzb3VyY2U6IHNldHRpbmdzLnNvdXJjZSB9KTtcbiAgICAgICAgfTtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChub3RpZmljYXRpb24pO1xuICAgIH1cbn1cbmV4cG9ydHMuQ3NwQWxlcnRlciA9IENzcEFsZXJ0ZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gZ2V0U3RyaW5ncygpIHtcbiAgICBjb25zdCBzdG9yZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKHN0b3JlKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBzdG9yZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3RyaW5ncycpO1xuICAgICAgICBpZiAoZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzdHJpbmdzJyk7XG59XG5leHBvcnRzLmdldFN0cmluZ3MgPSBnZXRTdHJpbmdzO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5jbGFzcyBTdHlsZUxvYWRpbmdNb25pdG9yIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy51bmxvYWRlZFN0eWxlcyA9IFtdO1xuICAgICAgICB0aGlzLmZpbmlzaGVkTG9hZGluZyA9IGZhbHNlO1xuICAgICAgICBjb25zdCBvblN0eWxlTG9hZEVycm9yID0gKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBzb3VyY2UgPSBldmVudC50YXJnZXQuZGF0YXNldC5zb3VyY2U7XG4gICAgICAgICAgICB0aGlzLnVubG9hZGVkU3R5bGVzLnB1c2goc291cmNlKTtcbiAgICAgICAgfTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCAoKSA9PiB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGxpbmsgb2YgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgnY29kZS11c2VyLXN0eWxlJykpIHtcbiAgICAgICAgICAgICAgICBpZiAobGluay5kYXRhc2V0LnNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICBsaW5rLm9uZXJyb3IgPSBvblN0eWxlTG9hZEVycm9yO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnVubG9hZGVkU3R5bGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZmluaXNoZWRMb2FkaW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIGlmICh0aGlzLnBvc3Rlcikge1xuICAgICAgICAgICAgICAgIHRoaXMucG9zdGVyLnBvc3RNZXNzYWdlKCdwcmV2aWV3U3R5bGVMb2FkRXJyb3InLCB7IHVubG9hZGVkU3R5bGVzOiB0aGlzLnVubG9hZGVkU3R5bGVzIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgc2V0UG9zdGVyKHBvc3Rlcikge1xuICAgICAgICB0aGlzLnBvc3RlciA9IHBvc3RlcjtcbiAgICAgICAgaWYgKHRoaXMuZmluaXNoZWRMb2FkaW5nKSB7XG4gICAgICAgICAgICBwb3N0ZXIucG9zdE1lc3NhZ2UoJ3ByZXZpZXdTdHlsZUxvYWRFcnJvcicsIHsgdW5sb2FkZWRTdHlsZXM6IHRoaXMudW5sb2FkZWRTdHlsZXMgfSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5leHBvcnRzLlN0eWxlTG9hZGluZ01vbml0b3IgPSBTdHlsZUxvYWRpbmdNb25pdG9yO1xuIl0sInNvdXJjZVJvb3QiOiIifQ== \ No newline at end of file diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 4cd76c86007..341e509d921 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -314,11 +314,11 @@ "watch": "npm run build-preview && gulp watch-extension:markdown-language-features", "vscode:prepublish": "npm run build-ext && npm run build-preview", "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:markdown-language-features ./tsconfig.json", - "build-preview": "webpack --mode development" + "build-preview": "webpack --mode production" }, "dependencies": { - "highlight.js": "9.15.8", - "markdown-it": "^9.1.0", + "highlight.js": "9.15.10", + "markdown-it": "^10.0.0", "markdown-it-front-matter": "^0.1.2", "vscode-extension-telemetry": "0.1.1", "vscode-nls": "^4.0.0" @@ -327,14 +327,14 @@ "@types/highlight.js": "9.12.3", "@types/lodash.throttle": "^4.1.3", "@types/markdown-it": "0.0.2", - "@types/node": "^10.14.8", + "@types/node": "^12.11.7", "lodash.throttle": "^4.1.1", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", - "ts-loader": "^4.0.1", - "typescript": "^3.3.1", + "ts-loader": "^6.2.1", + "typescript": "^3.6.4", "vscode": "^1.1.10", - "webpack": "^4.1.0", - "webpack-cli": "^2.0.10" + "webpack": "^4.41.2", + "webpack-cli": "^3.3.0" } } diff --git a/extensions/markdown-language-features/preview-src/index.ts b/extensions/markdown-language-features/preview-src/index.ts index b12614fe9ec..311c40b62d6 100644 --- a/extensions/markdown-language-features/preview-src/index.ts +++ b/extensions/markdown-language-features/preview-src/index.ts @@ -19,7 +19,7 @@ const settings = getSettings(); const vscode = acquireVsCodeApi(); // Set VS Code state -let state = getData<{ line: number, fragment: string }>('data-state'); +let state = getData<{ line: number; fragment: string; }>('data-state'); vscode.setState(state); const messaging = createPosterForVsCode(vscode); @@ -67,7 +67,7 @@ const onUpdateView = (() => { })(); let updateImageSizes = throttle(() => { - const imageInfo: { id: string, height: number, width: number }[] = []; + const imageInfo: { id: string, height: number, width: number; }[] = []; let images = document.getElementsByTagName('img'); if (images) { let i; @@ -129,6 +129,8 @@ document.addEventListener('dblclick', event => { } }); +const passThroughLinkSchemes = ['http:', 'https:', 'mailto:', 'vscode:', 'vscode-insiders:']; + document.addEventListener('click', event => { if (!event) { return; @@ -138,36 +140,40 @@ document.addEventListener('click', event => { while (node) { if (node.tagName && node.tagName === 'A' && node.href) { if (node.getAttribute('href').startsWith('#')) { - break; + return; } - if (node.href.startsWith('file://') || node.href.startsWith('vscode-resource:') || node.href.startsWith(settings.webviewResourceRoot)) { - const [path, fragment] = node.href.replace(/^(file:\/\/|vscode-resource:)/i, '').replace(new RegExp(`^${escapeRegExp(settings.webviewResourceRoot)}`)).split('#'); - messaging.postMessage('clickLink', { path, fragment }); + + // Pass through known schemes + if (passThroughLinkSchemes.some(scheme => node.href.startsWith(scheme))) { + return; + } + + const hrefText = node.getAttribute('data-href') || node.getAttribute('href'); + + // If original link doesn't look like a url, delegate back to VS Code to resolve + if (!/^[a-z\-]+:/i.test(hrefText)) { + messaging.postMessage('openLink', { href: hrefText }); event.preventDefault(); event.stopPropagation(); - break; + return; } - break; + + return; } node = node.parentNode; } }, true); -if (settings.scrollEditorWithPreview) { - window.addEventListener('scroll', throttle(() => { - if (scrollDisabled) { - scrollDisabled = false; - } else { - const line = getEditorLineNumberForPageOffset(window.scrollY); - if (typeof line === 'number' && !isNaN(line)) { - messaging.postMessage('revealLine', { line }); - state.line = line; - vscode.setState(state); - } +window.addEventListener('scroll', throttle(() => { + if (scrollDisabled) { + scrollDisabled = false; + } else { + const line = getEditorLineNumberForPageOffset(window.scrollY); + if (typeof line === 'number' && !isNaN(line)) { + messaging.postMessage('revealLine', { line }); + state.line = line; + vscode.setState(state); } - }, 50)); -} + } +}, 50)); -function escapeRegExp(text: string) { - return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); -} diff --git a/extensions/markdown-language-features/preview-src/scroll-sync.ts b/extensions/markdown-language-features/preview-src/scroll-sync.ts index eee320ac8e7..2d12fd2731a 100644 --- a/extensions/markdown-language-features/preview-src/scroll-sync.ts +++ b/extensions/markdown-language-features/preview-src/scroll-sync.ts @@ -27,7 +27,15 @@ const getCodeLineElements = (() => { elements = [{ element: document.body, line: 0 }]; for (const element of document.getElementsByClassName('code-line')) { const line = +element.getAttribute('data-line')!; - if (!isNaN(line)) { + if (isNaN(line)) { + continue; + } + + if (element.tagName === 'CODE' && element.parentElement && element.parentElement.tagName === 'PRE') { + // Fenched code blocks are a special case since the `code-line` can only be marked on + // the `` element and not the parent `
` element.
+					elements.push({ element: element.parentElement as HTMLElement, line });
+				} else {
 					elements.push({ element: element as HTMLElement, line });
 				}
 			}
@@ -81,6 +89,9 @@ export function getLineElementsAtPageOffset(offset: number): { previous: CodeLin
 		const loElement = lines[lo];
 		return { previous: loElement, next: hiElement };
 	}
+	if (hi > 1 && hi < lines.length && hiBounds.top + hiBounds.height > position) {
+		return { previous: hiElement, next: lines[hi + 1] };
+	}
 	return { previous: hiElement };
 }
 
@@ -125,8 +136,7 @@ export function getEditorLineNumberForPageOffset(offset: number) {
 			const progressBetweenElements = offsetFromPrevious / (next.element.getBoundingClientRect().top - previousBounds.top);
 			const line = previous.line + progressBetweenElements * (next.line - previous.line);
 			return clampLine(line);
-		}
-		else {
+		} else {
 			const progressWithinElement = offsetFromPrevious / (previousBounds.height);
 			const line = previous.line + progressWithinElement;
 			return clampLine(line);
diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts
index 44e8873b16d..7180f0a69c8 100644
--- a/extensions/markdown-language-features/src/extension.ts
+++ b/extensions/markdown-language-features/src/extension.ts
@@ -56,7 +56,7 @@ function registerMarkdownLanguageFeatures(
 
 	return vscode.Disposable.from(
 		vscode.languages.setLanguageConfiguration('markdown', {
-			wordPattern: new RegExp('(\\p{Alphabetic}|\\p{Number})+', 'ug'),
+			wordPattern: new RegExp('(\\p{Alphabetic}|\\p{Number}|\\p{Nonspacing_Mark})+', 'ug'),
 		}),
 		vscode.languages.registerDocumentSymbolProvider(selector, symbolProvider),
 		vscode.languages.registerDocumentLinkProvider(selector, new LinkProvider()),
diff --git a/extensions/markdown-language-features/src/features/documentLinkProvider.ts b/extensions/markdown-language-features/src/features/documentLinkProvider.ts
index 23364c4d69b..441055e5e71 100644
--- a/extensions/markdown-language-features/src/features/documentLinkProvider.ts
+++ b/extensions/markdown-language-features/src/features/documentLinkProvider.ts
@@ -7,7 +7,7 @@ import * as path from 'path';
 import * as vscode from 'vscode';
 import * as nls from 'vscode-nls';
 import { OpenDocumentLinkCommand } from '../commands/openDocumentLink';
-import { getUriForLinkWithKnownExternalScheme } from '../util/links';
+import { getUriForLinkWithKnownExternalScheme, isOfScheme, Schemes } from '../util/links';
 
 const localize = nls.loadMessageBundle();
 
@@ -18,6 +18,10 @@ function parseLink(
 ): { uri: vscode.Uri, tooltip?: string } {
 	const externalSchemeUri = getUriForLinkWithKnownExternalScheme(link);
 	if (externalSchemeUri) {
+		// Normalize VS Code links to target currently running version
+		if (isOfScheme(Schemes.vscode, link) || isOfScheme(Schemes['vscode-insiders'], link)) {
+			return { uri: vscode.Uri.parse(link).with({ scheme: vscode.env.uriScheme }) };
+		}
 		return { uri: externalSchemeUri };
 	}
 
diff --git a/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts
index 00224e1364d..16636dd1585 100644
--- a/extensions/markdown-language-features/src/features/preview.ts
+++ b/extensions/markdown-language-features/src/features/preview.ts
@@ -25,7 +25,7 @@ interface WebviewMessage {
 
 interface CacheImageSizesMessage extends WebviewMessage {
 	readonly type: 'cacheImageSizes';
-	readonly body: { id: string, width: number, height: number }[];
+	readonly body: { id: string, width: number, height: number; }[];
 }
 
 interface RevealLineMessage extends WebviewMessage {
@@ -43,10 +43,9 @@ interface DidClickMessage extends WebviewMessage {
 }
 
 interface ClickLinkMessage extends WebviewMessage {
-	readonly type: 'clickLink';
+	readonly type: 'openLink';
 	readonly body: {
-		readonly path: string;
-		readonly fragment?: string;
+		readonly href: string;
 	};
 }
 
@@ -88,7 +87,7 @@ export class MarkdownPreview extends Disposable {
 	private forceUpdate = false;
 	private isScrolling = false;
 	private _disposed: boolean = false;
-	private imageInfo: { id: string, width: number, height: number }[] = [];
+	private imageInfo: { id: string, width: number, height: number; }[] = [];
 	private scrollToFragment: string | undefined;
 
 	public static async revive(
@@ -202,8 +201,8 @@ export class MarkdownPreview extends Disposable {
 					this.onDidClickPreview(e.body.line);
 					break;
 
-				case 'clickLink':
-					this.onDidClickPreviewLink(e.body.path, e.body.fragment);
+				case 'openLink':
+					this.onDidClickPreviewLink(e.body.href);
 					break;
 
 				case 'showPreviewSecuritySelector':
@@ -284,15 +283,17 @@ export class MarkdownPreview extends Disposable {
 		super.dispose();
 	}
 
-	public update(resource: vscode.Uri) {
-		const editor = vscode.window.activeTextEditor;
+	public update(resource: vscode.Uri, isRefresh = true) {
 		// Reposition scroll preview, position scroll to the top if active text editor
 		// doesn't corresponds with preview
+		const editor = vscode.window.activeTextEditor;
 		if (editor) {
-			if (editor.document.uri.fsPath === resource.fsPath) {
-				this.line = getVisibleLine(editor);
-			} else {
-				this.line = 0;
+			if (!isRefresh || this._previewConfigurations.loadAndCacheConfiguration(this._resource).scrollEditorWithPreview) {
+				if (editor.document.uri.fsPath === resource.fsPath) {
+					this.line = getVisibleLine(editor);
+				} else {
+					this.line = 0;
+				}
 			}
 		}
 
@@ -320,7 +321,7 @@ export class MarkdownPreview extends Disposable {
 
 	public refresh() {
 		this.forceUpdate = true;
-		this.update(this._resource);
+		this.update(this._resource, true);
 	}
 
 	public updateConfiguration() {
@@ -484,6 +485,12 @@ export class MarkdownPreview extends Disposable {
 
 	private onDidScrollPreview(line: number) {
 		this.line = line;
+
+		const config = this._previewConfigurations.loadAndCacheConfiguration(this._resource);
+		if (!config.scrollEditorWithPreview) {
+			return;
+		}
+
 		for (const editor of vscode.window.visibleTextEditors) {
 			if (!this.isPreviewOf(editor.document.uri)) {
 				continue;
@@ -528,12 +535,19 @@ export class MarkdownPreview extends Disposable {
 		this.editor.webview.html = html;
 	}
 
-	private async onDidClickPreviewLink(path: string, fragment: string | undefined) {
-		this.scrollToFragment = undefined;
+	private async onDidClickPreviewLink(href: string) {
+		let [hrefPath, fragment] = decodeURIComponent(href).split('#');
+
+		// We perviously already resolve absolute paths.
+		// Now make sure we handle relative file paths
+		if (hrefPath[0] !== '/') {
+			hrefPath = path.join(path.dirname(this.resource.path), hrefPath);
+		}
+
 		const config = vscode.workspace.getConfiguration('markdown', this.resource);
 		const openLinks = config.get('preview.openMarkdownLinks', 'inPreview');
 		if (openLinks === 'inPreview') {
-			const markdownLink = await resolveLinkToMarkdownFile(path);
+			const markdownLink = await resolveLinkToMarkdownFile(hrefPath);
 			if (markdownLink) {
 				if (fragment) {
 					this.scrollToFragment = fragment;
@@ -543,10 +557,10 @@ export class MarkdownPreview extends Disposable {
 			}
 		}
 
-		vscode.commands.executeCommand('_markdown.openDocumentLink', { path, fragment, fromResource: this.resource });
+		vscode.commands.executeCommand('_markdown.openDocumentLink', { path: hrefPath, fragment, fromResource: this.resource });
 	}
 
-	private async onCacheImageSizes(imageInfo: { id: string, width: number, height: number }[]) {
+	private async onCacheImageSizes(imageInfo: { id: string, width: number, height: number; }[]) {
 		this.imageInfo = imageInfo;
 	}
 }
diff --git a/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts
index bcd7dc43ff4..d3b88f06c42 100644
--- a/extensions/markdown-language-features/src/markdownEngine.ts
+++ b/extensions/markdown-language-features/src/markdownEngine.ts
@@ -4,13 +4,13 @@
  *--------------------------------------------------------------------------------------------*/
 
 import * as crypto from 'crypto';
-import { MarkdownIt, Token } from 'markdown-it';
 import * as path from 'path';
+import { MarkdownIt, Token } from 'markdown-it';
 import * as vscode from 'vscode';
 import { MarkdownContributionProvider as MarkdownContributionProvider } from './markdownExtensions';
 import { Slugifier } from './slugify';
 import { SkinnyTextDocument } from './tableOfContentsProvider';
-import { getUriForLinkWithKnownExternalScheme } from './util/links';
+import { Schemes, isOfScheme } from './util/links';
 
 const UNICODE_NEWLINE_REGEX = /\u2028|\u2029/g;
 
@@ -105,10 +105,10 @@ export class MarkdownEngine {
 
 				this.addImageStabilizer(md);
 				this.addFencedRenderer(md);
-
 				this.addLinkNormalizer(md);
 				this.addLinkValidator(md);
 				this.addNamedHeaders(md);
+				this.addLinkRenderer(md);
 				return md;
 			});
 		}
@@ -143,6 +143,7 @@ export class MarkdownEngine {
 	public async render(input: SkinnyTextDocument | string): Promise {
 		const config = this.getConfig(typeof input === 'string' ? undefined : input.uri);
 		const engine = await this.getEngine(config);
+
 		const tokens = typeof input === 'string'
 			? this.tokenizeString(input, engine)
 			: this.tokenizeDocument(input, config, engine);
@@ -226,36 +227,33 @@ export class MarkdownEngine {
 		const normalizeLink = md.normalizeLink;
 		md.normalizeLink = (link: string) => {
 			try {
-				const externalSchemeUri = getUriForLinkWithKnownExternalScheme(link);
-				if (externalSchemeUri) {
-					// set true to skip encoding
-					return normalizeLink(externalSchemeUri.toString(true));
+				// Normalize VS Code schemes to target the current version
+				if (isOfScheme(Schemes.vscode, link) || isOfScheme(Schemes['vscode-insiders'], link)) {
+					return normalizeLink(vscode.Uri.parse(link).with({ scheme: vscode.env.uriScheme }).toString());
 				}
 
-				// 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}`);
+				// If original link doesn't look like a url with a scheme, assume it must be a link to a file in workspace
+				if (!/^[a-z\-]+:/i.test(link)) {
+					// Use a fake scheme for parsing
+					let uri = vscode.Uri.parse('markdown-link:' + link);
 
-				if (uri.path) {
-					// Assume it must be a file
-					const fragment = uri.fragment;
+					// Relative paths should be resolved correctly inside the preview but we need to
+					// handle absolute paths specially (for images) to resolve them relative to the workspace root
 					if (uri.path[0] === '/') {
 						const root = vscode.workspace.getWorkspaceFolder(this.currentDocument!);
 						if (root) {
-							uri = vscode.Uri.file(path.join(root.uri.fsPath, uri.path));
+							uri = uri.with({
+								path: path.join(root.uri.fsPath, uri.path),
+							});
 						}
-					} else {
-						uri = vscode.Uri.file(path.join(path.dirname(this.currentDocument!.path), uri.path));
 					}
 
-					if (fragment) {
+					if (uri.fragment) {
 						uri = uri.with({
-							fragment: this.slugifier.fromHeading(fragment).value
+							fragment: this.slugifier.fromHeading(uri.fragment).value
 						});
 					}
-					return normalizeLink(uri.with({ scheme: 'vscode-resource' }).toString(true));
-				} else if (!uri.path && uri.fragment) {
-					return `#${this.slugifier.fromHeading(uri.fragment).value}`;
+					return normalizeLink(uri.toString(true).replace(/^markdown-link:/, ''));
 				}
 			} catch (e) {
 				// noop
@@ -268,7 +266,11 @@ export class MarkdownEngine {
 		const validateLink = md.validateLink;
 		md.validateLink = (link: string) => {
 			// support file:// links
-			return validateLink(link) || link.startsWith('file:') || /^data:image\/.*?;/.test(link);
+			return validateLink(link)
+				|| isOfScheme(Schemes.file, link)
+				|| isOfScheme(Schemes.vscode, link)
+				|| isOfScheme(Schemes['vscode-insiders'], link)
+				|| /^data:image\/.*?;/.test(link);
 		};
 	}
 
@@ -296,6 +298,22 @@ export class MarkdownEngine {
 			}
 		};
 	}
+
+	private addLinkRenderer(md: any): void {
+		const old_render = md.renderer.rules.link_open || ((tokens: any, idx: number, options: any, _env: any, self: any) => {
+			return self.renderToken(tokens, idx, options);
+		});
+
+		md.renderer.rules.link_open = (tokens: any, idx: number, options: any, env: any, self: any) => {
+			const token = tokens[idx];
+			const hrefIndex = token.attrIndex('href');
+			if (hrefIndex >= 0) {
+				const href = token.attrs[hrefIndex][1];
+				token.attrPush(['data-href', href]);
+			}
+			return old_render(tokens, idx, options, env, self);
+		};
+	}
 }
 
 async function getMarkdownOptions(md: () => MarkdownIt) {
@@ -303,16 +321,7 @@ async function getMarkdownOptions(md: () => MarkdownIt) {
 	return {
 		html: true,
 		highlight: (str: string, lang?: string) => {
-			// Workaround for highlight not supporting tsx: https://github.com/isagalaev/highlight.js/issues/1155
-			if (lang && ['tsx', 'typescriptreact'].includes(lang.toLocaleLowerCase())) {
-				lang = 'jsx';
-			}
-			if (lang && lang.toLocaleLowerCase() === 'json5') {
-				lang = 'json';
-			}
-			if (lang && ['c#', 'csharp'].includes(lang.toLocaleLowerCase())) {
-				lang = 'cs';
-			}
+			lang = normalizeHighlightLang(lang);
 			if (lang && hljs.getLanguage(lang)) {
 				try {
 					return `
${hljs.highlight(lang, str, true).value}
`; @@ -323,3 +332,24 @@ async function getMarkdownOptions(md: () => MarkdownIt) { } }; } + +function normalizeHighlightLang(lang: string | undefined) { + switch (lang && lang.toLowerCase()) { + case 'tsx': + case 'typescriptreact': + // Workaround for highlight not supporting tsx: https://github.com/isagalaev/highlight.js/issues/1155 + return 'jsx'; + + case 'json5': + case 'jsonc': + return 'json'; + + case 'c#': + case 'csharp': + return 'cs'; + + default: + return lang; + } +} + diff --git a/extensions/markdown-language-features/src/util/links.ts b/extensions/markdown-language-features/src/util/links.ts index c1c2b1bdfb7..74383466f72 100644 --- a/extensions/markdown-language-features/src/util/links.ts +++ b/extensions/markdown-language-features/src/util/links.ts @@ -5,14 +5,30 @@ import * as vscode from 'vscode'; -const knownSchemes = ['http:', 'https:', 'file:', 'mailto:', 'data:', `${vscode.env.uriScheme}:`, 'vscode:', 'vscode-insiders:', 'vscode-resource:']; +export const Schemes = { + http: 'http:', + https: 'https:', + file: 'file:', + mailto: 'mailto:', + data: 'data:', + vscode: 'vscode:', + 'vscode-insiders': 'vscode-insiders:', + 'vscode-resource': 'vscode-resource:', +}; -export function getUriForLinkWithKnownExternalScheme( - link: string, -): vscode.Uri | undefined { - if (knownSchemes.some(knownScheme => link.toLowerCase().startsWith(knownScheme))) { +const knownSchemes = [ + ...Object.values(Schemes), + `${vscode.env.uriScheme}:` +]; + +export function getUriForLinkWithKnownExternalScheme(link: string): vscode.Uri | undefined { + if (knownSchemes.some(knownScheme => isOfScheme(knownScheme, link))) { return vscode.Uri.parse(link); } return undefined; } + +export function isOfScheme(scheme: string, link: string): boolean { + return link.toLowerCase().startsWith(scheme); +} diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index a45f00885e8..cf99e4dacff 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@sindresorhus/is@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" - integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== - "@types/highlight.js@9.12.3": version "9.12.3" resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.3.tgz#b672cfaac25cbbc634a0fd92c515f66faa18dbca" @@ -29,33 +24,192 @@ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.2.tgz#5d9ad19e6e6508cdd2f2596df86fd0aade598660" integrity sha1-XZrRnm5lCM3S8llt+G/Qqt5ZhmA= -"@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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== + +"@webassemblyjs/ast@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" + integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== + dependencies: + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + +"@webassemblyjs/floating-point-hex-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" + integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== + +"@webassemblyjs/helper-api-error@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" + integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== + +"@webassemblyjs/helper-buffer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" + integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== + +"@webassemblyjs/helper-code-frame@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" + integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== + dependencies: + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/helper-fsm@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" + integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== + +"@webassemblyjs/helper-module-context@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" + integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== + dependencies: + "@webassemblyjs/ast" "1.8.5" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" + integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== + +"@webassemblyjs/helper-wasm-section@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" + integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + +"@webassemblyjs/ieee754@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" + integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" + integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" + integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== + +"@webassemblyjs/wasm-edit@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" + integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/helper-wasm-section" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-opt" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/wasm-gen@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" + integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wasm-opt@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" + integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + +"@webassemblyjs/wasm-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" + integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wast-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" + integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/floating-point-hex-parser" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-code-frame" "1.8.5" + "@webassemblyjs/helper-fsm" "1.8.5" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" + integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -acorn-dynamic-import@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" - integrity sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg== - dependencies: - acorn "^5.0.0" +acorn@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" + integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== -acorn@^5.0.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.0.tgz#1abb587fbf051f94e3de20e6b26ef910b1828298" - integrity sha512-arn53F07VXmls4o4pUhSzBa4fvaagPRe7AVZ8l7NHxFWUie2DsuFSBMMNAkgzRlOhEhzAnxeKyaWVzOH4xqp/g== +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== ajv-keywords@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" integrity sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74= +ajv-keywords@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" + integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== + ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -83,6 +237,16 @@ ajv@^6.1.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" +ajv@^6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + 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" @@ -90,16 +254,6 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-escapes@^1.0.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.0.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" - integrity sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ== - ansi-gray@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" @@ -124,33 +278,28 @@ ansi-regex@^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@^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-styles@^3.2.1: +ansi-styles@^3.2.0, 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" -ansi-styles@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" - integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg= - 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= -any-observable@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242" - integrity sha1-xnhwBYADV5AJCD9UrAq6+1wz0kI= - anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -188,11 +337,6 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -argv@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" - integrity sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas= - arr-diff@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" @@ -301,33 +445,11 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -ast-types@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" - integrity sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ== - -ast-types@0.11.2: - version "0.11.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.2.tgz#cc4e1d15a36b39979a1986fe1e91321cbfae7783" - integrity sha512-aL+pcOQ+6dpWd0xrUe+Obo2CgdkFvsntkXEmzZKqEN4cR0PStF+1MBuc4V+YZsv4Q36luvyjG7F4lc+wH2bmag== - 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= -async@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - -async@^2.0.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" - integrity sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw== - dependencies: - lodash "^4.14.0" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -353,663 +475,6 @@ aws4@^1.2.1, aws4@^1.6.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" integrity sha1-g+9cqGCysy5KDe7e6MdxudtXRx4= -babel-code-frame@^6.26.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= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" - integrity sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g= - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.0" - debug "^2.6.8" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.7" - slash "^1.0.0" - source-map "^0.5.6" - -babel-generator@^6.26.0: - version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-helper-bindify-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" - integrity sha1-FMGeXxQte0fxmlJDHlKxzLxAozA= - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-explode-class@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - integrity sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes= - dependencies: - babel-helper-bindify-decorators "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs= - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - integrity sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU= - -babel-plugin-syntax-async-generators@^6.5.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" - integrity sha1-a8lj67FuzLrmuStZbrfzXDQqi5o= - -babel-plugin-syntax-class-constructor-call@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" - integrity sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY= - -babel-plugin-syntax-class-properties@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - integrity sha1-1+sjt5oxf4VDlixQW4J8fWysJ94= - -babel-plugin-syntax-decorators@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - integrity sha1-MSVjtNvePMgGzuPkFszurd0RrAs= - -babel-plugin-syntax-dynamic-import@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - integrity sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo= - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= - -babel-plugin-syntax-export-extensions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" - integrity sha1-cKFITw+QiaToStRLrDU8lbmxJyE= - -babel-plugin-syntax-flow@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" - integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0= - -babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM= - -babel-plugin-transform-async-generator-functions@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" - integrity sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds= - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E= - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-class-constructor-call@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" - integrity sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk= - dependencies: - babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-class-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - integrity sha1-anl2PqYdM9NvN7YRqp3vgagbRqw= - dependencies: - babel-helper-function-name "^6.24.1" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" - integrity sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0= - dependencies: - babel-helper-explode-class "^6.24.1" - babel-plugin-syntax-decorators "^6.13.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - integrity sha1-u8UbSflk1wy42OC5ToICRs46YUE= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8= - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - integrity sha1-WkxYpQyclGHlZLSyo7+ryXolhNs= - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - integrity sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM= - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - integrity sha1-mXux8auWf2gtKwh2/jWNYOdlxW0= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - integrity sha1-c+s9MQypaePvnskcU3QabxV2Qj4= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - integrity sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - integrity sha1-g0yJhTvDaxrw86TF26qU/Y6sqos= - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - integrity sha1-T1SgLWzWbPkVKAAZox0xklN3yi4= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - integrity sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ= - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" - integrity sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo= - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - integrity sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM= - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - integrity sha1-rJl+YoXNGO1hdq22B9YCNErThGg= - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - integrity sha1-JM72muIcuDp/hgPa0CH1cusnj40= - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - integrity sha1-V6w1GrScrxSpfNE7CfZv3wpiXys= - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - integrity sha1-JPh11nIch2YbvZmkYi5R8U3jiqA= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - integrity sha1-1taKmfia7cRTbIGlQujdnxdG+NE= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - integrity sha1-AMHNsaynERLN8M9hJsLta0V8zbw= - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - integrity sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - integrity sha1-04sS9C6nMj9yk4fxinxa4frrNek= - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - integrity sha1-KrDJx/MJj6SJB3cruBP+QejeOg4= - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-export-extensions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" - integrity sha1-U3OLR+deghhYnuqUbLvTkQm75lM= - dependencies: - babel-plugin-syntax-export-extensions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-flow-strip-types@^6.8.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" - integrity sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988= - dependencies: - babel-plugin-syntax-flow "^6.18.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" - integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY= - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.26.0" - -babel-plugin-transform-regenerator@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - integrity sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8= - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-preset-es2015@^6.9.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" - integrity sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk= - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.24.1" - babel-plugin-transform-es2015-classes "^6.24.1" - babel-plugin-transform-es2015-computed-properties "^6.24.1" - babel-plugin-transform-es2015-destructuring "^6.22.0" - babel-plugin-transform-es2015-duplicate-keys "^6.24.1" - babel-plugin-transform-es2015-for-of "^6.22.0" - babel-plugin-transform-es2015-function-name "^6.24.1" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-plugin-transform-es2015-modules-systemjs "^6.24.1" - babel-plugin-transform-es2015-modules-umd "^6.24.1" - babel-plugin-transform-es2015-object-super "^6.24.1" - babel-plugin-transform-es2015-parameters "^6.24.1" - babel-plugin-transform-es2015-shorthand-properties "^6.24.1" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.24.1" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.22.0" - babel-plugin-transform-es2015-unicode-regex "^6.24.1" - babel-plugin-transform-regenerator "^6.24.1" - -babel-preset-stage-1@^6.5.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" - integrity sha1-dpLNfc1oSZB+auSgqFWJz7niv7A= - dependencies: - babel-plugin-transform-class-constructor-call "^6.24.1" - babel-plugin-transform-export-extensions "^6.22.0" - babel-preset-stage-2 "^6.24.1" - -babel-preset-stage-2@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" - integrity sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE= - dependencies: - babel-plugin-syntax-dynamic-import "^6.18.0" - babel-plugin-transform-class-properties "^6.24.1" - babel-plugin-transform-decorators "^6.24.1" - babel-preset-stage-3 "^6.24.1" - -babel-preset-stage-3@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" - integrity sha1-g2raCp56f6N8sTj7kyb4eTSkg5U= - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-generator-functions "^6.24.1" - babel-plugin-transform-async-to-generator "^6.24.1" - babel-plugin-transform-exponentiation-operator "^6.24.1" - babel-plugin-transform-object-rest-spread "^6.22.0" - -babel-register@^6.26.0, babel-register@^6.9.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-template@^6.24.1, babel-template@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babylon@^6.17.3, babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -1050,16 +515,16 @@ big.js@^3.1.3: resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + 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= -binaryextensions@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" - integrity sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA== - block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -1067,10 +532,10 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== +bluebird@^3.5.5: + version "3.7.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" + integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" @@ -1133,6 +598,13 @@ braces@^2.3.0, braces@^2.3.1: split-string "^3.0.2" to-regex "^3.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" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -1206,6 +678,11 @@ buffer-crc32@~0.2.3: resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -1220,33 +697,30 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= -cacache@^10.0.1: - version "10.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" - integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== +cacache@^12.0.2: + version "12.0.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" + integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== dependencies: - bluebird "^3.5.1" - chownr "^1.0.1" - glob "^7.1.2" - graceful-fs "^4.1.11" - lru-cache "^4.1.1" - mississippi "^2.0.0" + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" mkdirp "^0.5.1" move-concurrently "^1.0.1" promise-inflight "^1.0.1" - rimraf "^2.6.2" - ssri "^5.2.4" - unique-filename "^1.1.0" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" y18n "^4.0.0" cache-base@^1.0.1: @@ -1264,23 +738,10 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -cacheable-request@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" - integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= - dependencies: - clone-response "1.0.2" - get-stream "3.0.0" - http-cache-semantics "3.8.1" - keyv "3.0.0" - lowercase-keys "1.0.0" - normalize-url "2.0.1" - responselike "1.0.2" - -camelcase@^4.1.0: - version "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== caseless@~0.11.0: version "0.11.0" @@ -1292,7 +753,16 @@ caseless@~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, chalk@^1.1.3: +chalk@2.4.2: + 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" + +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= @@ -1303,7 +773,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1: +chalk@^2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" integrity sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ== @@ -1312,20 +782,6 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" - integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8= - dependencies: - ansi-styles "~1.0.0" - has-color "~0.1.0" - strip-ansi "~0.1.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= - charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -1350,15 +806,17 @@ chokidar@^2.0.2: optionalDependencies: fsevents "^1.0.0" -chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= +chownr@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" + integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== -chrome-trace-event@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-0.1.2.tgz#90f36885d5345a50621332f0717b595883d5d982" - integrity sha1-kPNohdU0WlBiEzLwcXtZWIPV2YI= +chrome-trace-event@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" + integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== + dependencies: + tslib "^1.9.0" cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -1378,66 +836,20 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -cli-cursor@^1.0.1, cli-cursor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc= +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: - 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" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-spinners@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" - integrity sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw= - -cli-table@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" - integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= - dependencies: - colors "1.0.3" - -cli-truncate@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" - integrity sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ= - dependencies: - slice-ansi "0.0.4" - string-width "^1.0.1" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" + 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" integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= -clone-response@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - clone-stats@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" @@ -1482,15 +894,6 @@ 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= -codecov@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.0.0.tgz#c273b8c4f12945723e8dc9d25803d89343e5f28e" - integrity sha1-wnO4xPEpRXI+jcnSWAPYk0Pl8o4= - dependencies: - argv "0.0.2" - request "2.81.0" - urlgrey "0.4.4" - collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -1516,16 +919,6 @@ color-support@^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== -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.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= - 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" @@ -1538,7 +931,12 @@ commander@2.11.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== -commander@^2.9.0, commander@~2.14.1: +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^2.9.0: version "2.14.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" integrity sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw== @@ -1558,7 +956,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.4.7, concat-stream@^1.5.0: +concat-stream@^1.5.0: version "1.6.1" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.1.tgz#261b8f518301f1d834e36342b9fea095d2620a26" integrity sha512-gslSSJx03QKa59cIKqeJO9HQ/WZMotvYJCuaUULrLpjj8oG40kV2Z+gz82pVxlTkOADi4PJxQPPfhl1ELYrrXw== @@ -1584,7 +982,7 @@ constants-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -convert-source-map@^1.1.1, convert-source-map@^1.5.0: +convert-source-map@^1.1.1: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= @@ -1606,11 +1004,6 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" - integrity sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4= - 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" @@ -1646,16 +1039,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: - 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= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^6.0.4: +cross-spawn@6.0.5, 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== @@ -1707,11 +1091,6 @@ cyclist@~0.2.2: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= -dargs@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-5.1.0.tgz#ec7ea50c78564cd36c9d5ec18f66329fade27829" - integrity sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk= - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -1719,11 +1098,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -date-fns@^1.27.2: - version "1.29.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" - integrity sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw== - date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" @@ -1741,14 +1115,14 @@ debug@3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debug@^2.0.0, debug@^2.1.0, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: +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" -decamelize@^1.1.1: +decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -1758,13 +1132,6 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= -decompress-response@^3.2.0, decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - deep-assign@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-1.0.0.tgz#b092743be8427dc621ea0067cdec7e70dd19f37b" @@ -1772,7 +1139,7 @@ deep-assign@^1.0.0: dependencies: is-obj "^1.0.0" -deep-extend@^0.4.0, deep-extend@~0.4.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= @@ -1817,17 +1184,10 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -detect-conflict@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/detect-conflict/-/detect-conflict-1.0.1.tgz#088657a66a961c05019db7c4230883b1c6b4176e" - integrity sha1-CIZXpmqWHAUBnbfEIwiDsca0F24= - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= - dependencies: - repeating "^2.0.0" +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= detect-libc@^1.0.2: version "1.0.3" @@ -1851,16 +1211,6 @@ diff@3.3.1: resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" integrity sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww== -diff@^2.1.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99" - integrity sha1-YOr9DSjukG5Oj/ClLBIpUhAzv5k= - -diff@^3.3.0, diff@^3.3.1: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - diffie-hellman@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" @@ -1870,11 +1220,6 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" -dom-walk@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= - domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" @@ -1887,11 +1232,6 @@ duplexer2@0.0.2: dependencies: readable-stream "~1.1.9" -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" @@ -1924,21 +1264,6 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" -editions@^1.3.3: - version "1.3.4" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" - integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== - -ejs@^2.3.1: - version "2.5.7" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.7.tgz#cc872c168880ae3c7189762fd5ffc00896c9518a" - integrity sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo= - -elegant-spinner@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" - integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= - elliptic@^6.0.0: version "6.4.0" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" @@ -1952,6 +1277,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" @@ -1964,6 +1294,15 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" +enhanced-resolve@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + enhanced-resolve@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a" @@ -1973,10 +1312,19 @@ enhanced-resolve@^4.0.0: memory-fs "^0.4.0" tapable "^1.0.0" -entities@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= +enhanced-resolve@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" + integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +entities@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" + integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== errno@^0.1.3, errno@~0.1.7: version "0.1.7" @@ -1985,39 +1333,19 @@ errno@^0.1.3, errno@~0.1.7: dependencies: prr "~1.0.1" -error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" - integrity sha1-+FWobOYa3E6GIcPNoh56dhLDqNw= - dependencies: - is-arrayish "^0.2.1" - -error@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" - integrity sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI= - dependencies: - string-template "~0.2.1" - xtend "~4.0.0" - escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, 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= -eslint-scope@^3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" - integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" -esprima@~4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" - integrity sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw== - esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" @@ -2030,11 +1358,6 @@ estraverse@^4.1.0, estraverse@^4.1.1: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - event-stream@^3.3.1, event-stream@~3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -2048,10 +1371,10 @@ event-stream@^3.3.1, event-stream@~3.3.4: stream-combiner "~0.0.4" through "~2.3.1" -events@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= +events@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" + integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" @@ -2061,24 +1384,19 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= +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 "^5.0.1" - get-stream "^3.0.0" + 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" -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= - expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" @@ -2140,24 +1458,6 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ= -external-editor@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" - integrity sha1-Etew24UPf/fnCBuvQAVwAGDEYAs= - dependencies: - extend "^3.0.0" - spawn-sync "^1.0.15" - tmp "^0.0.29" - -external-editor@^2.0.4, external-editor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" - integrity sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -2203,6 +1503,11 @@ fast-deep-equal@^1.0.0: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" integrity sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8= +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" @@ -2215,20 +1520,10 @@ fd-slicer@~1.0.1: dependencies: pend "~1.2.0" -figures@^1.3.5, figures@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" +figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== filename-regex@^2.0.0: version "2.0.1" @@ -2256,39 +1551,44 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" - integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= +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-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== dependencies: commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" + make-dir "^2.0.0" + pkg-dir "^3.0.0" -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= +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 "^2.0.0" + locate-path "^3.0.0" + +findup-sync@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" 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= -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" - integrity sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA= - dependencies: - readable-stream "^2.0.2" - -flow-parser@^0.*: - version "0.66.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.66.0.tgz#be583fefb01192aa5164415d31a6241b35718983" - integrity sha1-vlg/77ARkqpRZEFdMaYkGzVxiYM= - flush-write-stream@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.2.tgz#c81b90d8746766f1a609a46809946c45dd8ae417" @@ -2339,7 +1639,7 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -from2@^2.1.0, from2@^2.1.1: +from2@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= @@ -2420,15 +1720,17 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" -get-caller-file@^1.0.1: - version "1.0.2" - 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-stream@3.0.0, get-stream@^3.0.0: - version "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" @@ -2442,29 +1744,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -gh-got@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0" - integrity sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw== - dependencies: - got "^7.0.0" - is-plain-obj "^1.1.0" - -github-username@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417" - integrity sha1-y+KABBiDIG2kISrp5LXxacML9Bc= - dependencies: - gh-got "^6.0.0" - -glob-all@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.1.0.tgz#8913ddfb5ee1ac7812656241b03d5217c64b02ab" - integrity sha1-iRPd+17hrHgSZWJBsD1SF8ZLAqs= - dependencies: - glob "^7.0.5" - yargs "~1.2.6" - glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -2502,7 +1781,7 @@ glob-stream@^5.3.2: to-absolute-glob "^0.1.1" unique-stream "^2.0.2" -glob@7.1.2, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: +glob@7.1.2, glob@^7.0.5, 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== @@ -2525,17 +1804,25 @@ glob@^5.0.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^6.0.1: - version "6.0.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" - integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= +glob@^7.1.3, glob@^7.1.4: + version "7.1.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" + integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== dependencies: + fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "2 || 3" + minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + global-modules@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" @@ -2556,41 +1843,14 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -global@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" - integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8= +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== dependencies: - min-document "^2.19.0" - process "~0.5.1" - -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - -globby@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-4.1.0.tgz#080f54549ec1b82a6c60e631fc82e1211dbe95f8" - integrity sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg= - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^6.0.1" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" glogg@^1.0.0: version "1.0.1" @@ -2599,60 +1859,15 @@ glogg@^1.0.0: dependencies: sparkles "^1.0.0" -got@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -got@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/got/-/got-8.2.0.tgz#0d11a071d05046348a2f5c0a5fa047fb687fdfc6" - integrity sha512-giadqJpXIwjY+ZsuWys8p2yjZGhOHiU4hiJHjS/oeCxw1u8vANQz3zPlrxW2Zw/siCXsSMI3hvzWGcnFyujyAg== - dependencies: - "@sindresorhus/is" "^0.7.0" - cacheable-request "^2.1.1" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - into-stream "^3.1.0" - is-retry-allowed "^1.1.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - mimic-response "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^2.0.1" - pify "^3.0.0" - safe-buffer "^5.1.1" - timed-out "^4.0.1" - url-parse-lax "^3.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2: +graceful-fs@^4.0.0, 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= -grouped-queue@^0.3.0, grouped-queue@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c" - integrity sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw= - dependencies: - lodash "^4.17.2" +graceful-fs@^4.1.15: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== growl@1.10.3: version "1.10.3" @@ -2815,11 +2030,6 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-color@~0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" - integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8= - has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" @@ -2837,18 +2047,6 @@ has-gulplog@^0.1.0: dependencies: sparkles "^1.0.0" -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== - -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== - dependencies: - has-symbol-support-x "^1.4.1" - has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -2933,10 +2131,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.15.8: - version "9.15.8" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.8.tgz#f344fda123f36f1a65490e932cf90569e4999971" - integrity sha512-RrapkKQWwE+wKdF73VsOa2RQdIoO3mxwJ4P8mhbI6KYJUraUHRKM5w5zQQKXNk0xNL4UVRdulV9SBJcmzJNzVA== +highlight.js@9.15.10: + version "9.15.10" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2" + integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw== hmac-drbg@^1.0.0: version "1.0.1" @@ -2957,14 +2155,6 @@ hoek@4.x.x: resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" integrity sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ== -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" @@ -2972,16 +2162,6 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" - integrity sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg== - -http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - http-signature@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" @@ -3005,11 +2185,6 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@^0.4.17: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== - ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" @@ -3020,27 +2195,23 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= +import-local@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= - -indexof@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= +infer-owner@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== inflight@^1.0.4: version "1.0.6" @@ -3050,7 +2221,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.3, inherits@^2.0.1, inherits@^2.0.3, 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= @@ -3060,94 +2231,20 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= -ini@^1.3.4, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== -inquirer@^1.0.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" - integrity sha1-TexvMvN+97sLLtPx0aXD9UUHSRg= - dependencies: - ansi-escapes "^1.1.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - external-editor "^1.1.0" - figures "^1.3.5" - lodash "^4.3.0" - mute-stream "0.0.6" - pinkie-promise "^2.0.0" - run-async "^2.2.0" - rx "^4.1.0" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" +interpret@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== -inquirer@^3.3.0: - 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 "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.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@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.1.0.tgz#19da508931892328abbbdd4c477f1efc65abfd67" - integrity sha512-kn7N70US1MSZHZHSGJLiZ7iCwwncc7b0gc68YtlX29OjI3Mp0tSVV+snVXpZ1G+ONS3Ac9zd1m6hve2ibLDYfA== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.1.0" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^5.5.2" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -interpret@^1.0.0, interpret@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= - -into-stream@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" - integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= - dependencies: - from2 "^2.1.1" - p-is-promise "^1.1.0" - -invariant@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688" - integrity sha512-7Z5PPegwDTyjbaeCnV0efcyS6vdKAU51kpEmS7QFib3P4822l8ICYyMn7qvJnc+WzLoDsuI9gPMKbJ8pCu8XtA== - dependencies: - loose-envify "^1.0.0" - -invert-kv@^1.0.0: - version "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== is-accessor-descriptor@^0.1.6: version "0.1.6" @@ -3163,11 +2260,6 @@ is-accessor-descriptor@^1.0.0: 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" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - 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" @@ -3180,13 +2272,6 @@ is-buffer@^1.1.5, is-buffer@~1.1.1: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= - 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" @@ -3253,13 +2338,6 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" - 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" @@ -3322,23 +2400,16 @@ is-number@^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-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-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-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= - -is-observable@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-0.2.0.tgz#b361311d83c6e5d726cabf5e250b0237106f5ae2" - integrity sha1-s2ExHYPG5dcmyr9eJQsCNxBvWuI= - dependencies: - symbol-observable "^0.2.2" - is-odd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" @@ -3346,11 +2417,6 @@ is-odd@^2.0.0: dependencies: is-number "^4.0.0" -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - is-plain-object@^2.0.1, 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" @@ -3368,29 +2434,12 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= -is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= - -is-scoped@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-1.0.0.tgz#449ca98299e713038256289ecb2b540dc437cb30" - integrity sha1-RJypgpnnEwOCViieyytUDcQ3yzA= - dependencies: - scoped-regex "^1.0.0" - -is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: +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= @@ -3415,6 +2464,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: version "3.2.1" resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" @@ -3452,74 +2506,26 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istextorbinary@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.2.1.tgz#a5231a08ef6dd22b268d0895084cf8d58b5bec53" - integrity sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw== - dependencies: - binaryextensions "2" - editions "^1.3.3" - textextensions "2" - -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - -js-tokens@^3.0.0, js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jscodeshift@^0.4.0, jscodeshift@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.4.1.tgz#da91a1c2eccfa03a3387a21d39948e251ced444a" - integrity sha512-iOX6If+hsw0q99V3n31t4f5VlD1TQZddH08xbT65ZqA7T4Vkx68emrDZMUOLVvCEAJ6NpAk7DECe3fjC/t52AQ== - dependencies: - async "^1.5.0" - babel-plugin-transform-flow-strip-types "^6.8.0" - babel-preset-es2015 "^6.9.0" - babel-preset-stage-1 "^6.5.0" - babel-register "^6.9.0" - babylon "^6.17.3" - colors "^1.1.2" - flow-parser "^0.*" - lodash "^4.13.1" - micromatch "^2.3.7" - node-dir "0.1.8" - nomnom "^1.8.1" - recast "^0.12.5" - temp "^0.8.1" - write-file-atomic "^1.2.0" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= +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" @@ -3537,11 +2543,18 @@ 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= -json5@^0.5.0, json5@^0.5.1: +json5@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -3562,13 +2575,6 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -keyv@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" - integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== - dependencies: - json-buffer "3.0.0" - kind-of@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" @@ -3612,12 +2618,12 @@ lazystream@^1.0.0: dependencies: readable-stream "^2.0.5" -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= +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 "^1.0.0" + invert-kv "^2.0.0" linkify-it@^2.0.0: version "2.0.3" @@ -3626,74 +2632,21 @@ linkify-it@^2.0.0: dependencies: uc.micro "^1.0.1" -listr-silent-renderer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" - integrity sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4= +loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== -listr-update-renderer@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7" - integrity sha1-NE2YDaLKLosUW6MFkI8yrj9MyKc= +loader-utils@1.2.3, loader-utils@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - elegant-spinner "^1.0.1" - figures "^1.7.0" - indent-string "^3.0.0" - log-symbols "^1.0.2" - log-update "^1.0.2" - strip-ansi "^3.0.1" + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" -listr-verbose-renderer@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35" - integrity sha1-ggb0z21S3cWCfl/RSYng6WWTOjU= - dependencies: - chalk "^1.1.3" - cli-cursor "^1.0.2" - date-fns "^1.27.2" - figures "^1.7.0" - -listr@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/listr/-/listr-0.13.0.tgz#20bb0ba30bae660ee84cc0503df4be3d5623887d" - integrity sha1-ILsLowuuZg7oTMBQPfS+PVYjiH0= - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - figures "^1.7.0" - indent-string "^2.1.0" - is-observable "^0.2.0" - is-promise "^2.1.0" - is-stream "^1.1.0" - listr-silent-renderer "^1.1.1" - listr-update-renderer "^0.4.0" - listr-verbose-renderer "^0.4.0" - log-symbols "^1.0.2" - log-update "^1.0.2" - ora "^0.2.3" - p-map "^1.1.1" - rxjs "^5.4.2" - stream-to-observable "^0.2.0" - strip-ansi "^3.0.1" - -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - -loader-runner@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" - integrity sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI= - -loader-utils@^1.0.2, loader-utils@^1.1.0: +loader-utils@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= @@ -3702,12 +2655,12 @@ loader-utils@^1.0.2, loader-utils@^1.1.0: emojis-list "^2.0.0" json5 "^0.5.0" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= +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 "^2.0.0" + p-locate "^3.0.0" path-exists "^3.0.0" lodash._basecopy@^3.0.0: @@ -3819,64 +2772,37 @@ lodash.throttle@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= -lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" - integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw== - 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== -log-symbols@2.2.0, log-symbols@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: - chalk "^2.0.1" + yallist "^3.0.2" -log-symbols@^1.0.1, log-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" - integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg= +make-dir@^2.0.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: - chalk "^1.0.0" + pify "^4.0.1" + semver "^5.6.0" -log-update@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1" - integrity sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE= +mamacro@^0.0.3: + version "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: - ansi-escapes "^1.0.0" - cli-cursor "^1.0.2" - -loose-envify@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" - integrity sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg= - dependencies: - js-tokens "^3.0.0" - -lowercase-keys@1.0.0, lowercase-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= - -lru-cache@^4.0.1, lru-cache@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" - integrity sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -make-dir@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" - integrity sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw== - dependencies: - pify "^3.0.0" + p-defer "^1.0.0" map-cache@^0.2.2: version "0.2.2" @@ -3900,13 +2826,13 @@ markdown-it-front-matter@^0.1.2: resolved "https://registry.yarnpkg.com/markdown-it-front-matter/-/markdown-it-front-matter-0.1.2.tgz#e50bf56e77e6a4f5ac4ffa894d4d45ccd9896b20" integrity sha1-5Qv1bnfmpPWsT/qJTU1FzNmJayA= -markdown-it@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-9.1.0.tgz#df9601c168568704d554b1fff9af0c5b561168d9" - integrity sha512-xHKG4C8iPriyfu/jc2hsCC045fKrMQ0VexX2F1FGYiRxDxqMB2aAhF8WauJ3fltn2kb90moGBkiiEdooGIg55w== +markdown-it@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc" + integrity sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg== dependencies: argparse "^1.0.7" - entities "~1.1.1" + entities "~2.0.0" linkify-it "^2.0.0" mdurl "^1.0.1" uc.micro "^1.0.5" @@ -3933,39 +2859,16 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= -mem-fs-editor@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz#dd0a6eaf2bb8a6b37740067aa549eb530105af9f" - integrity sha1-3Qpuryu4prN3QAZ6pUnrUwEFr58= +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: - commondir "^1.0.1" - deep-extend "^0.4.0" - ejs "^2.3.1" - glob "^7.0.3" - globby "^6.1.0" - mkdirp "^0.5.0" - multimatch "^2.0.0" - rimraf "^2.2.8" - through2 "^2.0.0" - vinyl "^2.0.1" + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" -mem-fs@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc" - integrity sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw= - dependencies: - through2 "^2.0.0" - vinyl "^1.1.0" - vinyl-file "^2.0.0" - -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - -memory-fs@^0.4.0, memory-fs@~0.4.1: +memory-fs@^0.4.0, memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= @@ -3973,6 +2876,14 @@ memory-fs@^0.4.0, memory-fs@~0.4.1: errno "^0.1.3" readable-stream "^2.0.1" +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + merge-stream@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" @@ -3999,7 +2910,26 @@ micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.1.4, micromatch@^3.1.8: +micromatch@^3.0.4, 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" + +micromatch@^3.1.4: version "3.1.9" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89" integrity sha512-SlIz6sv5UPaAVVFRKodKjCg48EbNoIhgetzfK/Cy0v5U52Z6zB136M8tp0UC9jM53LYbmIRihJszvvqpKkfm9g== @@ -4018,6 +2948,14 @@ micromatch@^3.1.4, micromatch@^3.1.8: snapdragon "^0.8.1" to-regex "^3.0.1" +micromatch@^4.0.0: + 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" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -4038,22 +2976,10 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: dependencies: mime-db "~1.30.0" -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-response@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" - integrity sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4= - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= - dependencies: - dom-walk "^0.1.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== minimalistic-assert@^1.0.0: version "1.0.0" @@ -4077,20 +3003,15 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" - integrity sha1-md9lelJXTCHJBXSX33QnkLK0wN4= - minimist@^1.1.0, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -mississippi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" - integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== dependencies: concat-stream "^1.5.0" duplexify "^3.4.2" @@ -4098,7 +3019,7 @@ mississippi@^2.0.0: flush-write-stream "^1.0.0" from2 "^2.1.0" parallel-transform "^1.1.0" - pump "^2.0.1" + pump "^3.0.0" pumpify "^1.3.3" stream-each "^1.1.0" through2 "^2.0.0" @@ -4111,7 +3032,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1, "mkdirp@>=0.5 0", 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= @@ -4187,16 +3108,6 @@ multipipe@^0.1.2: dependencies: duplexer2 "0.0.2" -mute-stream@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" - integrity sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s= - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - nan@^2.3.0: version "2.9.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866" @@ -4225,20 +3136,20 @@ neo-async@^2.5.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f" integrity sha512-nJmSswG4As/MkRq7QZFuH/sf/yuv8ODdMZrY4Bedjp77a5MK4A6s7YbBB64c9u79EBUOfXUXBvArmvzTD0X+6g== +neo-async@^2.6.1: + 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-dir@0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" - integrity sha1-VfuN62mQcHB/tn+RpGDwRIKUx30= - -node-libs-browser@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" - integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg== +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== dependencies: assert "^1.1.1" browserify-zlib "^0.2.0" @@ -4247,10 +3158,10 @@ node-libs-browser@^2.0.0: constants-browserify "^1.0.0" crypto-browserify "^3.11.0" domain-browser "^1.1.1" - events "^1.0.0" + events "^3.0.0" https-browserify "^1.0.0" os-browserify "^0.3.0" - path-browserify "0.0.0" + path-browserify "0.0.1" process "^0.11.10" punycode "^1.2.4" querystring-es3 "^0.2.0" @@ -4261,8 +3172,8 @@ node-libs-browser@^2.0.0: timers-browserify "^2.0.4" tty-browserify "0.0.0" url "^0.11.0" - util "^0.10.3" - vm-browserify "0.0.4" + util "^0.11.0" + vm-browserify "^1.0.1" node-pre-gyp@^0.6.39: version "0.6.39" @@ -4288,14 +3199,6 @@ node.extend@~1.1.2: dependencies: is "^3.1.0" -nomnom@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" - integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc= - dependencies: - chalk "~0.4.0" - underscore "~1.6.0" - nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -4304,16 +3207,6 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.3.2: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - 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" @@ -4321,15 +3214,6 @@ normalize-path@^2.0.1, normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" -normalize-url@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.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" @@ -4362,7 +3246,7 @@ object-assign@^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, object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.0, 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= @@ -4405,28 +3289,6 @@ once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: 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" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -ora@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" - integrity sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q= - dependencies: - chalk "^1.1.1" - cli-cursor "^1.0.2" - cli-spinners "^0.1.2" - object-assign "^4.0.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" @@ -4445,21 +3307,16 @@ os-homedir@^1.0.0: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== +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 "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" -os-shim@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" - integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc= - -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= @@ -4472,75 +3329,39 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== - -p-each-series@^1.0.0: +p-defer@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" - integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= - dependencies: - p-reduce "^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@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= +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-lazy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-lazy/-/p-lazy-1.0.0.tgz#ec53c802f2ee3ac28f166cc82d0b2b02de27a835" - integrity sha1-7FPIAvLuOsKPFmzILQsrAt4nqDU= - -p-limit@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" - integrity sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng== +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== dependencies: - p-try "^1.0.0" + p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= +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 "^1.1.0" + p-limit "^2.0.0" -p-map@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" - integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== - -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= - -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= - dependencies: - p-finally "^1.0.0" - -p-timeout@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" - integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= +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== pako@~1.0.5: version "1.0.6" @@ -4577,13 +3398,6 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -4594,10 +3408,10 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -path-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" - integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== path-dirname@^1.0.0: version "1.0.2" @@ -4609,7 +3423,7 @@ path-exists@^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, path-is-absolute@^1.0.1: +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= @@ -4619,18 +3433,6 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -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-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - pause-stream@0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" @@ -4664,15 +3466,15 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= +picomatch@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.1.0.tgz#0fd042f568d08b1ad9ff2d3ec0f0bfb3cb80e177" + integrity sha512-uhnEDzAbrcJ8R3g2fANnSuXZMBtkpSjxTTgn2LeSiQlfmq72enQJWdQllXW24MBLYnA1SBD2vfvx2o0Zw3Ielw== -pify@^3.0.0: - version "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" @@ -4686,12 +3488,12 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== dependencies: - find-up "^2.1.0" + find-up "^3.0.0" plugin-error@^0.1.2: version "0.1.2" @@ -4709,36 +3511,11 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= -prettier@^1.5.3: - version "1.11.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" - integrity sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw== - -pretty-bytes@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9" - integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk= - -private@^0.1.6, private@^0.1.7, private@~0.1.5: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - process-nextick-args@^1.0.6, 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" @@ -4754,11 +3531,6 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -process@~0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8= - promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -4769,11 +3541,6 @@ prr@~1.0.1: resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - public-encrypt@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" @@ -4785,7 +3552,7 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" -pump@^2.0.0, pump@^2.0.1: +pump@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== @@ -4793,6 +3560,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: version "1.4.0" resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.4.0.tgz#80b7c5df7e24153d03f0e7ac8a05a5d068bd07fb" @@ -4812,6 +3587,11 @@ punycode@^1.2.4, punycode@^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.3.0: version "6.3.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" @@ -4827,15 +3607,6 @@ qs@~6.5.1: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== -query-string@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.0.tgz#9583b15fd1307f899e973ed418886426a9976469" - integrity sha512-F3DkxxlY0AqD/rwe4YAwjRE2HjOkKW7TxsuteyrS/Jbwrxw887PqYBL4sWUJ9D/V1hmFns0SCD6FDyvlwo9RCQ== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -4898,31 +3669,6 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -read-chunk@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655" - integrity sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU= - dependencies: - pify "^3.0.0" - safe-buffer "^5.1.1" - -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - "readable-stream@1 || 2", readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.3.3: version "2.3.5" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" @@ -4979,53 +3725,6 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" -recast@^0.12.5: - version "0.12.9" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1" - integrity sha512-y7ANxCWmMW8xLOaiopiRDlyjQ9ajKRENBH+2wjntIbk3A6ZR1+BLQttkmSHMY7Arl+AAZFwJ10grg2T6f1WI8A== - dependencies: - ast-types "0.10.1" - core-js "^2.4.1" - esprima "~4.0.0" - private "~0.1.5" - source-map "~0.6.1" - -recast@^0.14.4: - version "0.14.4" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.14.4.tgz#383dd606eac924c1157b0293b53191c34bd3c641" - integrity sha512-b6fRXujYf8mTIyljymL3rglje1LfuGKdD44CuKs6o1B18MmZ+mEEpD5gsaxGVABZHyPvYwPLcyBTA/SvxtiyFg== - dependencies: - ast-types "0.11.2" - esprima "~4.0.0" - private "~0.1.5" - source-map "~0.6.1" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= - dependencies: - resolve "^1.1.6" - -regenerate@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" - integrity sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg== - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" @@ -5041,27 +3740,6 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - integrity sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA= - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= - dependencies: - jsesc "~0.5.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" @@ -5077,13 +3755,6 @@ repeat-string@^1.5.2, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - replace-ext@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" @@ -5181,10 +3852,10 @@ require-directory@^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== requires-port@~1.0.0: version "1.0.0" @@ -5198,7 +3869,7 @@ resolve-cwd@^2.0.0: dependencies: resolve-from "^3.0.0" -resolve-dir@^1.0.0: +resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= @@ -5216,52 +3887,24 @@ 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.6: - version "1.5.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" - integrity sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw== - dependencies: - path-parse "^1.0.5" - -responselike@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -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" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - 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, rimraf@^2.2.0, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@^2.5.1, rimraf@^2.5.4, 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" -rimraf@~2.2.6: - version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.1" @@ -5271,13 +3914,6 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" -run-async@^2.0.0, run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" - run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" @@ -5285,30 +3921,6 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -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= - -rx@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" - integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= - -rxjs@^5.4.2, rxjs@^5.5.2: - version "5.5.6" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.6.tgz#e31fb96d6fd2ff1fd84bcea8ae9c02d007179c02" - integrity sha512-v4Q5HDC0FHAQ7zcBX7T2IL6O5ltl1a2GX4ENjPXg6SjDY69Cmx9v4113C99a4wGF16ClPv5Z8mghuYorVkg/kg== - dependencies: - symbol-observable "1.0.1" - safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -5321,28 +3933,34 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -schema-utils@^0.4.2: - version "0.4.5" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" - integrity sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA== +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== dependencies: ajv "^6.1.0" + ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -scoped-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8" - integrity sha1-o0a7Gs1CB65wvXwMfKnlZra63bg= - -"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: +semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== -serialize-javascript@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" - integrity sha1-fJWFFNtqwkQ6irwGLcn3iGp/YAU= +semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +serialize-javascript@^1.7.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" + integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" @@ -5406,35 +4024,11 @@ 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.0: - 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" - -signal-exit@^3.0.0, signal-exit@^3.0.2: +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= -slash@^1.0.0: - version "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= - -slide@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -5479,13 +4073,6 @@ sntp@2.x.x: dependencies: hoek "4.x.x" -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" @@ -5502,13 +4089,6 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.4.15: - 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-support@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.3.tgz#2b3d5fff298cfa4d1afd7d4352d569e9a0158e76" @@ -5516,12 +4096,20 @@ source-map-support@^0.5.0: dependencies: source-map "^0.6.0" +source-map-support@~0.5.12: + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.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, source-map@^0.5.7: +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= @@ -5536,40 +4124,6 @@ sparkles@^1.0.0: resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" integrity sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM= -spawn-sync@^1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" - integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY= - dependencies: - concat-stream "^1.4.7" - os-shim "^0.1.2" - -spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" - integrity sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" - integrity sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg== - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" - integrity sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA== - 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" @@ -5604,12 +4158,12 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -ssri@^5.2.4: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.2.4.tgz#9985e14041e65fc397af96542be35724ac11da52" - integrity sha512-UnEAgMZa15973iH7cUi0AHjJn1ACDIkaMyZILoqwN6yzt+4P81I8tBc5Hl+qwi5auMplZtPQsHrPBR5vJLcQtQ== +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== dependencies: - safe-buffer "^5.1.1" + figgy-pudding "^3.5.1" stat-mode@^0.2.0: version "0.2.2" @@ -5663,13 +4217,6 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= -stream-to-observable@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.2.0.tgz#59d6ea393d87c2c0ddac10aa0d561bc6ba6f0e10" - integrity sha1-WdbqOT2HwsDdrBCqDVYbxrpvDhA= - dependencies: - any-observable "^0.2.0" - streamfilter@^1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/streamfilter/-/streamfilter-1.0.7.tgz#ae3e64522aa5a35c061fd17f67620c7653c643c9" @@ -5682,16 +4229,6 @@ streamifier@~0.1.1: resolved "https://registry.yarnpkg.com/streamifier/-/streamifier-0.1.1.tgz#97e98d8fa4d105d62a2691d1dc07e820db8dfc4f" integrity sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8= -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - -string-template@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" - integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= - string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -5701,13 +4238,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@^2.0.0, string-width@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== +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 "^4.0.0" + strip-ansi "^5.1.0" string_decoder@^1.0.0, string_decoder@~1.0.3: version "1.0.3" @@ -5740,10 +4278,12 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" - integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE= +strip-ansi@^5.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" @@ -5753,14 +4293,6 @@ strip-bom-stream@^1.0.0: first-chunk-stream "^1.0.0" strip-bom "^2.0.0" -strip-bom-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca" - integrity sha1-+H217yYT9paKpUWr/h7HKLaoKco= - dependencies: - first-chunk-stream "^2.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" @@ -5768,11 +4300,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" @@ -5790,33 +4317,35 @@ supports-color@4.4.0: dependencies: has-flag "^2.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" + 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= -supports-color@^5.2.0, supports-color@^5.3.0: +supports-color@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" integrity sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg== dependencies: has-flag "^3.0.0" -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= - -symbol-observable@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-0.2.4.tgz#95a83db26186d6af7e7a18dbd9760a2f86d08f40" - integrity sha1-lag9smGG1q9+ehjb2XYKL4bQj0A= - tapable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" integrity sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg== +tapable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + tar-pack@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" @@ -5840,23 +4369,29 @@ tar@^2.2.1: fstream "^1.0.2" inherits "2" -temp@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" - integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k= +terser-webpack-plugin@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4" + integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg== dependencies: - os-tmpdir "^1.0.0" - rimraf "~2.2.6" + cacache "^12.0.2" + find-cache-dir "^2.1.0" + is-wsl "^1.1.0" + schema-utils "^1.0.0" + serialize-javascript "^1.7.0" + source-map "^0.6.1" + terser "^4.1.2" + webpack-sources "^1.4.0" + worker-farm "^1.7.0" -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -textextensions@2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" - integrity sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA== +terser@^4.1.2: + version "4.3.9" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.9.tgz#e4be37f80553d02645668727777687dad26bbca8" + integrity sha512-NFGMpHjlzmyOtPL+fDw3G7+6Ueh/sz4mkaUYa4lJCxOPTNzd0Uj0aZJOmsDYoSQyfuVoWDMSWTPU3huyOm2zdA== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" through2-filter@^2.0.0: version "2.0.0" @@ -5882,7 +4417,7 @@ through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0, through2@~2. readable-stream "^2.1.5" xtend "~4.0.1" -through@2, through@^2.3.6, through@~2.3, through@~2.3.1: +through@2, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -5892,11 +4427,6 @@ time-stamp@^1.0.0: resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= -timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - timers-browserify@^2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae" @@ -5904,20 +4434,6 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -tmp@^0.0.29: - version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" - integrity sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA= - dependencies: - os-tmpdir "~1.0.1" - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - 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" @@ -5930,11 +4446,6 @@ to-arraybuffer@^1.0.0: resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= - 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" @@ -5950,7 +4461,14 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" -to-regex@^3.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" + +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== @@ -5967,21 +4485,21 @@ tough-cookie@~2.3.0, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" -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= - -ts-loader@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-4.0.1.tgz#3d920b059966efec9637133ab0ca9b04d625d59a" - integrity sha512-dzgQnkAGY4sLqVw6t4LJH8FGR8j0zsPmC1Ff2ChzKhYO+hgWJkSEyrHTlSSZqn5oWr0Po7q/IRoeq8O4SNKQ9A== +ts-loader@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.1.tgz#67939d5772e8a8c6bdaf6277ca023a4812da02ef" + integrity sha512-Dd9FekWuABGgjE1g0TlQJ+4dFUfYGbYcs52/HQObE0ZmUNjQlmLAS7xXsSzy23AMaMwipsx5sNHvoEpT2CZq1g== dependencies: chalk "^2.3.0" enhanced-resolve "^4.0.0" loader-utils "^1.0.2" - micromatch "^3.1.4" - semver "^5.0.1" + micromatch "^4.0.0" + semver "^6.0.0" + +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== tty-browserify@0.0.0: version "0.0.0" @@ -6010,10 +4528,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.1.tgz#6de14e1db4b8a006ac535e482c8ba018c55f750b" - integrity sha512-cTmIDFW7O0IHbn1DPYjkiebHxwtCMU+eTy30ZtJNBPF9j2O1ITu5XH2YnBeVRKWHqF+3JQwWJv0Q0aUgX8W7IA== +typescript@^3.6.4: + version "3.6.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" + integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== uc.micro@^1.0.1: version "1.0.3" @@ -6025,38 +4543,11 @@ uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" integrity sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg== -uglify-es@^3.3.4: - version "3.3.10" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.10.tgz#8b0b7992cebe20edc26de1bf325cef797b8f3fa5" - integrity sha512-rPzPisCzW68Okj1zNrfa2dR9uEm43SevDmpR6FChoZABFk9dANGnzzBMgHYUXI3609//63fnVkyQ1SQmAMyjww== - dependencies: - commander "~2.14.1" - source-map "~0.6.1" - -uglifyjs-webpack-plugin@^1.1.1, uglifyjs-webpack-plugin@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.2.tgz#e7516d4367afdb715c3847841eb46f94c45ca2b9" - integrity sha512-CG/NvzXfemUAm5Y4Guh5eEaJYHtkG7kKNpXEJHp9QpxsFVB5/qKvYWoMaq4sa99ccZ0hM3MK8vQV9XPZB4357A== - dependencies: - cacache "^10.0.1" - find-cache-dir "^1.0.0" - schema-utils "^0.4.2" - serialize-javascript "^1.4.0" - source-map "^0.6.1" - uglify-es "^3.3.4" - webpack-sources "^1.1.0" - worker-farm "^1.5.2" - 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= -underscore@~1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" - integrity sha1-izixDKze9jM3uLJOT/htRa6lKag= - union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -6067,10 +4558,10 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" -unique-filename@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" - integrity sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM= +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== dependencies: unique-slug "^2.0.0" @@ -6097,42 +4588,23 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -untildify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" - integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA= - dependencies: - os-homedir "^1.0.0" - -untildify@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" - integrity sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E= - upath@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== +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" + 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= -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - url-parse@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" @@ -6141,11 +4613,6 @@ url-parse@^1.1.9: querystringify "~1.0.0" requires-port "~1.0.0" -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= - url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -6154,11 +4621,6 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" -urlgrey@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f" - integrity sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8= - use@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8" @@ -6173,36 +4635,35 @@ util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util@0.10.3, util@^0.10.3: +util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= dependencies: inherits "2.0.1" +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + uuid@^3.0.0, uuid@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" integrity sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA== -v8-compile-cache@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" - integrity sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA== +v8-compile-cache@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" + integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== 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= -validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" - integrity sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -6212,18 +4673,6 @@ verror@1.10.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" - integrity sha1-p+v1/779obfRjRQPyweyI++2dRo= - dependencies: - graceful-fs "^4.1.2" - pify "^2.3.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - strip-bom-stream "^2.0.0" - vinyl "^1.1.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" @@ -6272,7 +4721,7 @@ vinyl@^0.5.0: clone-stats "^0.0.1" replace-ext "0.0.1" -vinyl@^1.0.0, vinyl@^1.1.0: +vinyl@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ= @@ -6281,7 +4730,7 @@ vinyl@^1.0.0, vinyl@^1.1.0: clone-stats "^0.0.1" replace-ext "0.0.1" -vinyl@^2.0.1, vinyl@^2.0.2: +vinyl@^2.0.2: version "2.1.0" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" integrity sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw= @@ -6306,12 +4755,10 @@ vinyl@~2.0.1: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" -vm-browserify@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" - integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= - dependencies: - indexof "0.0.1" +vm-browserify@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" + integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== vscode-extension-telemetry@0.1.1: version "0.1.1" @@ -6345,89 +4792,68 @@ vscode@^1.1.10: url-parse "^1.1.9" vinyl-source-stream "^1.1.0" -watchpack@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.5.0.tgz#231e783af830a22f8966f65c4c4bacc814072eed" - integrity sha512-RSlipNQB1u48cq0wH/BNfCu1tD/cJ8ydFIkNYhp9o+3d+8unClkIovpW5qpFPgmL9OE48wfAnlZydXByWP82AA== +watchpack@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== dependencies: chokidar "^2.0.2" graceful-fs "^4.1.2" neo-async "^2.5.0" -webpack-addons@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/webpack-addons/-/webpack-addons-1.1.5.tgz#2b178dfe873fb6e75e40a819fa5c26e4a9bc837a" - integrity sha512-MGO0nVniCLFAQz1qv22zM02QPjcpAoJdy7ED0i3Zy7SY1IecgXCm460ib7H/Wq7e9oL5VL6S2BxaObxwIcag0g== +webpack-cli@^3.3.0: + version "3.3.10" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13" + integrity sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg== dependencies: - jscodeshift "^0.4.0" + chalk "2.4.2" + cross-spawn "6.0.5" + enhanced-resolve "4.1.0" + findup-sync "3.0.0" + global-modules "2.0.0" + import-local "2.0.0" + interpret "1.2.0" + loader-utils "1.2.3" + supports-color "6.1.0" + v8-compile-cache "2.0.3" + yargs "13.2.4" -webpack-cli@^2.0.10: - version "2.0.10" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-2.0.10.tgz#09b888fbaa0b4288ba4b94c4462b6f559dfcf51e" - integrity sha512-PQWEOoXkhjBV4svPuESghZRc80VvDoSSRPaLiInWifDlRJgoPWpiLCFXyMLQTTaug7ApLrSEW7BcuwwY6DEv5w== - dependencies: - chalk "^2.3.1" - codecov "^3.0.0" - cross-spawn "^6.0.4" - diff "^3.3.0" - enhanced-resolve "^4.0.0" - glob-all "^3.1.0" - global "^4.3.2" - global-modules "^1.0.0" - got "^8.2.0" - inquirer "^5.1.0" - interpret "^1.0.4" - jscodeshift "^0.4.1" - listr "^0.13.0" - loader-utils "^1.1.0" - lodash "^4.17.5" - log-symbols "2.2.0" - mkdirp "^0.5.1" - p-each-series "^1.0.0" - p-lazy "^1.0.0" - prettier "^1.5.3" - recast "^0.14.4" - resolve-cwd "^2.0.0" - supports-color "^5.2.0" - uglifyjs-webpack-plugin "^1.2.2" - v8-compile-cache "^1.1.2" - webpack-addons "^1.1.5" - yargs "9.0.1" - yeoman-environment "^2.0.0" - yeoman-generator "github:ev1stensberg/generator#Feature-getArgument" - -webpack-sources@^1.0.1, webpack-sources@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" - integrity sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw== +webpack-sources@^1.4.0, webpack-sources@^1.4.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== dependencies: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.1.0.tgz#91b6862e56eb3b18b79bb10b51866987ff10d2d6" - integrity sha512-ZFYcAZ44kOT+xsS5MS2H1fQr0PJkwQdYem/d17wacDkkupzsAkBJ3hDShWHdPVvWluFs6pfhHWw/dVso1m0rsA== +webpack@^4.41.2: + version "4.41.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.2.tgz#c34ec76daa3a8468c9b61a50336d8e3303dce74e" + integrity sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A== dependencies: - acorn "^5.0.0" - acorn-dynamic-import "^3.0.0" - ajv "^6.1.0" - ajv-keywords "^3.1.0" - chrome-trace-event "^0.1.1" - enhanced-resolve "^4.0.0" - eslint-scope "^3.7.1" - loader-runner "^2.3.0" - loader-utils "^1.1.0" - memory-fs "~0.4.1" - micromatch "^3.1.8" - mkdirp "~0.5.0" - neo-async "^2.5.0" - node-libs-browser "^2.0.0" - schema-utils "^0.4.2" - tapable "^1.0.0" - uglifyjs-webpack-plugin "^1.1.1" - watchpack "^1.5.0" - webpack-sources "^1.0.1" + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.2.1" + ajv "^6.10.2" + ajv-keywords "^3.4.1" + chrome-trace-event "^1.0.2" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.3" + json-parse-better-errors "^1.0.2" + loader-runner "^2.4.0" + loader-utils "^1.2.3" + memory-fs "^0.4.1" + micromatch "^3.1.10" + mkdirp "^0.5.1" + neo-async "^2.6.1" + node-libs-browser "^2.2.1" + schema-utils "^1.0.0" + tapable "^1.1.3" + terser-webpack-plugin "^1.4.1" + watchpack "^1.6.0" + webpack-sources "^1.4.1" which-module@^2.0.0: version "2.0.0" @@ -6441,6 +4867,13 @@ which@^1.2.14, which@^1.2.9: dependencies: isexe "^2.0.0" +which@^1.3.1: + 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.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" @@ -6448,36 +4881,27 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2" -worker-farm@^1.5.2: - version "1.5.4" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.4.tgz#4debbe46b40edefcc717ebde74a90b1ae1e909a1" - integrity sha512-ITyClEvcfv0ozqJl1vmWFWhvI+OIrkbInYqkEPE50wFPXj8J9Gd3FYf8+CkZJXJJsQBYe+2DvmoK9Zhx5w8W+w== +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== dependencies: errno "~0.1.7" - xtend "~4.0.1" -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= +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: - string-width "^1.0.1" - strip-ansi "^3.0.1" + 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" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^1.2.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8= - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - xml@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" @@ -6488,53 +4912,40 @@ xml@^1.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= - 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== -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= +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 "^4.1.0" + camelcase "^5.0.0" + decamelize "^1.2.0" -yargs@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" - integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= +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: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" + 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 "^1.0.1" + require-main-filename "^2.0.0" set-blocking "^2.0.0" - string-width "^2.0.0" + string-width "^3.0.0" which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - -yargs@~1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b" - integrity sha1-nHtKgv1dWVsr8Xq23MQxNUMv40s= - dependencies: - minimist "^0.1.0" + y18n "^4.0.0" + yargs-parser "^13.1.0" yauzl@^2.2.1: version "2.9.1" @@ -6551,73 +4962,6 @@ yazl@^2.2.1: dependencies: buffer-crc32 "~0.2.3" -yeoman-environment@^1.1.0: - version "1.6.6" - resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-1.6.6.tgz#cd85fa67d156060e440d7807d7ef7cf0d2d1d671" - integrity sha1-zYX6Z9FWBg5EDXgH1+988NLR1nE= - dependencies: - chalk "^1.0.0" - debug "^2.0.0" - diff "^2.1.2" - escape-string-regexp "^1.0.2" - globby "^4.0.0" - grouped-queue "^0.3.0" - inquirer "^1.0.2" - lodash "^4.11.1" - log-symbols "^1.0.1" - mem-fs "^1.1.0" - text-table "^0.2.0" - untildify "^2.0.0" - -yeoman-environment@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.5.tgz#84f22bafa84088971fe99ea85f654a3a3dd2b693" - integrity sha512-6/W7/B54OPHJXob0n0+pmkwFsirC8cokuQkPSmT/D0lCcSxkKtg/BA6ZnjUBIwjuGqmw3DTrT4en++htaUju5g== - dependencies: - chalk "^2.1.0" - debug "^3.1.0" - diff "^3.3.1" - escape-string-regexp "^1.0.2" - globby "^6.1.0" - grouped-queue "^0.3.3" - inquirer "^3.3.0" - is-scoped "^1.0.0" - lodash "^4.17.4" - log-symbols "^2.1.0" - mem-fs "^1.1.0" - text-table "^0.2.0" - untildify "^3.0.2" - -"yeoman-generator@github:ev1stensberg/generator#Feature-getArgument": - version "1.1.1" - resolved "https://codeload.github.com/ev1stensberg/generator/tar.gz/9e24fa31c85302ca1145ae34fc68b4f133251ca0" - dependencies: - async "^2.0.0" - chalk "^1.0.0" - cli-table "^0.3.1" - cross-spawn "^5.0.1" - dargs "^5.1.0" - dateformat "^2.0.0" - debug "^2.1.0" - detect-conflict "^1.0.0" - error "^7.0.2" - find-up "^2.1.0" - github-username "^4.0.0" - istextorbinary "^2.1.0" - lodash "^4.11.1" - mem-fs-editor "^3.0.0" - minimist "^1.2.0" - mkdirp "^0.5.0" - pretty-bytes "^4.0.2" - read-chunk "^2.0.0" - read-pkg-up "^2.0.0" - rimraf "^2.2.0" - run-async "^2.0.0" - shelljs "^0.7.0" - text-table "^0.2.0" - through2 "^2.0.0" - yeoman-environment "^1.1.0" - zone.js@0.7.6: version "0.7.6" resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009" diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index 2828669b04d..815a412492a 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -138,6 +138,6 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" } } diff --git a/extensions/merge-conflict/yarn.lock b/extensions/merge-conflict/yarn.lock index e6247e29255..7af62a72ce7 100644 --- a/extensions/merge-conflict/yarn.lock +++ b/extensions/merge-conflict/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/npm/README.md b/extensions/npm/README.md index a24a7d69d6e..f3707f85d32 100644 --- a/extensions/npm/README.md +++ b/extensions/npm/README.md @@ -22,9 +22,13 @@ The Npm Script Explorer shows the npm scripts found in your workspace. The explo The extension supports to run the selected script as a task when editing the `package.json`file. You can either run a script from the hover shown on a script or using the command `Run Selected Npm Script`. +### Run Scripts from a Folder in the Explorer + +The extension supports running a script as a task from a folder in the Explorer. The command `Run NPM Script in Folder...` shown in the Explorer context menu finds all scripts in `package.json` files that are contained in this folder. You can then select the script to be executed as a task from the resulting list. You enable this support with the `npm.runScriptFromFolder` which is `false` by default. + ### Others -The extension fetches data from https://registry.npmjs/org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies. +The extension fetches data from https://registry.npmjs.org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies. ## Settings @@ -34,5 +38,7 @@ The extension fetches data from https://registry.npmjs/org and https://registry. - `npm.exclude` - Glob patterns for folders that should be excluded from automatic script detection. The pattern is matched against the **absolute path** of the package.json. For example, to exclude all test folders use '**/test/**'. - `npm.enableScriptExplorer` - Enable an explorer view for npm scripts. - `npm.scriptExplorerAction` - The default click action: `open` or `run`, the default is `open`. +- `npm.enableRunFromFolder` - Enable running npm scripts from the context menu of folders in Explorer, the default is `false`. - `npm.scriptCodeLens.enable` - Enable/disable the code lenses to run a script, the default is `false`. + diff --git a/extensions/npm/package.json b/extensions/npm/package.json index a987d6082b4..cbd9645341a 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -20,16 +20,17 @@ "dependencies": { "jsonc-parser": "^2.1.1", "minimatch": "^3.0.4", - "request-light": "^0.2.4", + "request-light": "^0.2.5", "vscode-nls": "^4.0.0" }, "devDependencies": { "@types/minimatch": "^3.0.3", - "@types/node": "^10.14.8" + "@types/node": "^12.11.7" }, "main": "./out/main", "activationEvents": [ "onCommand:workbench.action.tasks.runTask", + "onCommand:npm.runScriptFromFolder", "onLanguage:json", "workspaceContains:package.json", "onView:npm" @@ -88,6 +89,10 @@ { "command": "npm.runSelectedScript", "title": "%command.runSelectedScript%" + }, + { + "command": "npm.runScriptFromFolder", + "title": "%command.runScriptFromFolder%" } ], "menus": { @@ -115,6 +120,10 @@ { "command": "npm.runSelectedScript", "when": "false" + }, + { + "command": "npm.runScriptFromFolder", + "when": "false" } ], "editor/context": [ @@ -172,7 +181,14 @@ "when": "view == npm && viewItem == script", "group": "navigation@3" } - ] + ], + "explorer/context": [ + { + "when": "config.npm.enableRunFromFolder && explorerViewletVisible && explorerResourceIsFolder", + "command": "npm.runScriptFromFolder", + "group": "2_workspace" + } + ] }, "configuration": { "id": "npm", @@ -222,6 +238,12 @@ "scope": "resource", "description": "%config.npm.enableScriptExplorer%" }, + "npm.enableRunFromFolder": { + "type": "boolean", + "default": false, + "scope": "resource", + "description": "%config.npm.enableRunFromFolder%" + }, "npm.scriptExplorerAction": { "type": "string", "enum": [ diff --git a/extensions/npm/package.nls.json b/extensions/npm/package.nls.json index 40121b8fa8d..014010a8425 100644 --- a/extensions/npm/package.nls.json +++ b/extensions/npm/package.nls.json @@ -1,21 +1,23 @@ { "description": "Extension to add task support for npm scripts.", - "displayName": "Npm support for VS Code", + "displayName": "NPM support for VS Code", "config.npm.autoDetect": "Controls whether npm scripts should be automatically detected.", "config.npm.runSilent": "Run npm commands with the `--silent` option.", "config.npm.packageManager": "The package manager used to run scripts.", "config.npm.exclude": "Configure glob patterns for folders that should be excluded from automatic script detection.", "config.npm.enableScriptExplorer": "Enable an explorer view for npm scripts when there is no top-level 'package.json' file.", - "config.npm.scriptExplorerAction": "The default click action used in the scripts explorer: `open` or `run`, the default is `open`.", - "config.npm.fetchOnlinePackageInfo": "Fetch data from https://registry.npmjs/org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies.", + "config.npm.scriptExplorerAction": "The default click action used in the npm scripts explorer: `open` or `run`, the default is `open`.", + "config.npm.enableRunFromFolder": "Enable running NPM scripts contained in a folder from the Explorer context menu.", + "config.npm.fetchOnlinePackageInfo": "Fetch data from https://registry.npmjs.org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies.", "npm.parseError": "Npm task detection: failed to parse the file {0}", "taskdef.script": "The npm script to customize.", "taskdef.path": "The path to the folder of the package.json file that provides the script. Can be omitted.", - "view.name": "Npm Scripts", + "view.name": "NPM Scripts", "command.refresh": "Refresh", "command.run": "Run", "command.debug": "Debug", "command.openScript": "Open", "command.runInstall": "Run Install", - "command.runSelectedScript": "Run Script" + "command.runSelectedScript": "Run Script", + "command.runScriptFromFolder": "Run NPM Script in Folder..." } diff --git a/extensions/npm/src/commands.ts b/extensions/npm/src/commands.ts index 08384681708..7ca92879f9b 100644 --- a/extensions/npm/src/commands.ts +++ b/extensions/npm/src/commands.ts @@ -3,11 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import { - runScript, findScriptAtPosition -} from './tasks'; import * as nls from 'vscode-nls'; +import * as vscode from 'vscode'; + +import { + detectNpmScriptsForFolder, + findScriptAtPosition, + runScript, + FolderTaskItem +} from './tasks'; const localize = nls.loadMessageBundle(); @@ -28,4 +32,37 @@ export function runSelectedScript() { let message = localize('noScriptFound', 'Could not find a valid npm script at the selection.'); vscode.window.showErrorMessage(message); } -} \ No newline at end of file +} + +export async function selectAndRunScriptFromFolder(selectedFolder: vscode.Uri) { + let taskList: FolderTaskItem[] = await detectNpmScriptsForFolder(selectedFolder); + + if (taskList && taskList.length > 0) { + const quickPick = vscode.window.createQuickPick(); + quickPick.title = 'Run NPM script in Folder'; + quickPick.placeholder = 'Select an npm script'; + quickPick.items = taskList; + + const toDispose: vscode.Disposable[] = []; + + let pickPromise = new Promise((c) => { + toDispose.push(quickPick.onDidAccept(() => { + toDispose.forEach(d => d.dispose()); + c(quickPick.selectedItems[0]); + })); + toDispose.push(quickPick.onDidHide(() => { + toDispose.forEach(d => d.dispose()); + c(undefined); + })); + }); + quickPick.show(); + let result = await pickPromise; + quickPick.dispose(); + if (result) { + vscode.tasks.executeTask(result.task); + } + } + else { + vscode.window.showInformationMessage(`No npm scripts found in ${selectedFolder.fsPath}`, { modal: true }); + } +} diff --git a/extensions/npm/src/features/jsonContributions.ts b/extensions/npm/src/features/jsonContributions.ts index b9ecfd57cee..e59b7866ec3 100644 --- a/extensions/npm/src/features/jsonContributions.ts +++ b/extensions/npm/src/features/jsonContributions.ts @@ -25,7 +25,7 @@ export interface IJSONContribution { getDocumentSelector(): DocumentSelector; getInfoContribution(fileName: string, location: Location): Thenable | null; collectPropertySuggestions(fileName: string, location: Location, currentWord: string, addValue: boolean, isLast: boolean, result: ISuggestionsCollector): Thenable | null; - collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable | null; + collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable; collectDefaultSuggestions(fileName: string, result: ISuggestionsCollector): Thenable; resolveSuggestion?(item: CompletionItem): Thenable | null; } @@ -164,4 +164,4 @@ export class JSONCompletionItemProvider implements CompletionItemProvider { } } -export const xhrDisabled = () => Promise.reject({ responseText: 'Use of online resources is disabled.' }); \ No newline at end of file +export const xhrDisabled = () => Promise.reject({ responseText: 'Use of online resources is disabled.' }); diff --git a/extensions/npm/src/features/packageJSONContribution.ts b/extensions/npm/src/features/packageJSONContribution.ts index 17e194cad32..4789886891c 100644 --- a/extensions/npm/src/features/packageJSONContribution.ts +++ b/extensions/npm/src/features/packageJSONContribution.ts @@ -182,11 +182,7 @@ export class PackageJSONContribution implements IJSONContribution { return Promise.resolve(null); } - public collectValueSuggestions( - _fileName: string, - location: Location, - result: ISuggestionsCollector - ): Thenable | null { + public async collectValueSuggestions(_fileName: string, location: Location, result: ISuggestionsCollector): Promise { if (!this.onlineEnabled()) { return null; } @@ -194,34 +190,30 @@ 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') { - 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); + const info = await this.fetchPackageInfo(currentKey); + if (info && info.distTagsLatest) { - 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); + let name = JSON.stringify(info.distTagsLatest); + 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.minorversion', 'Matches the most recent minor version (1.2.x)'); - result.add(proposal); - } - return 0; - }, () => { - return 0; - }); + name = JSON.stringify('^' + info.distTagsLatest); + 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('~' + info.distTagsLatest); + 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 null; @@ -243,37 +235,73 @@ export class PackageJSONContribution implements IJSONContribution { return null; } - private getInfo(pack: string): Thenable { - return this.npmView(pack).then(info => { + private async getInfo(pack: string): Promise { + let info = await this.fetchPackageInfo(pack); + if (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 []; + } + + return []; + } + + private async fetchPackageInfo(pack: string): Promise { + let info = await this.npmView(pack); + if (!info) { + info = await this.npmjsView(pack); + } + return info; + } + + + 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) { + try { + const content = JSON.parse(stdout); + resolve({ + description: content['description'], + distTagsLatest: content['dist-tags.latest'], + homepage: content['homepage'] + }); + return; + } catch (e) { + // ignore + } + } + resolve(undefined); + }); }); } - 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(); - } + private async npmjsView(pack: string): Promise { + const queryUrl = 'https://registry.npmjs.org/' + encodeURIComponent(pack).replace(/%40/g, '@'); + try { + const success = await this.xhr({ + url: queryUrl, + agent: USER_AGENT }); - }); + const obj = JSON.parse(success.responseText); + if (obj) { + const latest = obj && obj['dist-tags'] && obj['dist-tags']['latest']; + if (latest) { + return { + description: obj.description || '', + distTagsLatest: latest, + homepage: obj.homepage || '' + }; + } + } + } + catch (e) { + //ignore + } + return undefined; } public getInfoContribution(_fileName: string, location: Location): Thenable | null { @@ -327,4 +355,4 @@ 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 d32d245b0ed..3777f393757 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -6,10 +6,10 @@ import * as httpRequest from 'request-light'; import * as vscode from 'vscode'; import { addJSONProviders } from './features/jsonContributions'; +import { runSelectedScript, selectAndRunScriptFromFolder } from './commands'; import { NpmScriptsTreeDataProvider } from './npmView'; import { invalidateTasksCache, NpmTaskProvider, hasPackageJson } from './tasks'; import { invalidateHoverScriptsCache, NpmScriptHoverProvider } from './scriptHover'; -import { runSelectedScript } from './commands'; let treeDataProvider: NpmScriptsTreeDataProvider | undefined; @@ -45,6 +45,8 @@ export async function activate(context: vscode.ExtensionContext): Promise if (await hasPackageJson()) { vscode.commands.executeCommand('setContext', 'npm:showScriptExplorer', true); } + + context.subscriptions.push(vscode.commands.registerCommand('npm.runScriptFromFolder', selectAndRunScriptFromFolder)); } function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposable | undefined { diff --git a/extensions/npm/src/npmView.ts b/extensions/npm/src/npmView.ts index f01e8121719..b5234c5fc1b 100644 --- a/extensions/npm/src/npmView.ts +++ b/extensions/npm/src/npmView.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import { - Event, EventEmitter, ExtensionContext, Task, + Event, EventEmitter, ExtensionContext, Task2 as Task, TextDocument, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder, commands, window, workspace, tasks, Selection, TaskGroup } from 'vscode'; @@ -108,13 +108,9 @@ class NpmScript extends TreeItem { dark: context.asAbsolutePath(path.join('resources', 'dark', 'script.svg')) }; } - - let uri = getPackageJsonUriFromTask(task); - getScripts(uri!).then(scripts => { - if (scripts && scripts[task.definition['script']]) { - this.tooltip = scripts[task.definition['script']]; - } - }); + if (task.detail) { + this.tooltip = task.detail; + } } getFolder(): WorkspaceFolder { @@ -213,7 +209,7 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider { if (!uri) { return; } - let task = createTask('install', 'install', selection.folder.workspaceFolder, uri, []); + let task = createTask('install', 'install', selection.folder.workspaceFolder, uri, undefined, []); tasks.executeTask(task); } diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts index 0e6a28bfc33..c8a1eb85236 100644 --- a/extensions/npm/src/tasks.ts +++ b/extensions/npm/src/tasks.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { - TaskDefinition, Task, TaskGroup, WorkspaceFolder, RelativePattern, ShellExecution, Uri, workspace, - DebugConfiguration, debug, TaskProvider, TextDocument, tasks, TaskScope + TaskDefinition, Task2 as Task, TaskGroup, WorkspaceFolder, RelativePattern, ShellExecution, Uri, workspace, + DebugConfiguration, debug, TaskProvider, TextDocument, tasks, TaskScope, QuickPickItem } from 'vscode'; import * as path from 'path'; import * as fs from 'fs'; @@ -20,6 +20,11 @@ export interface NpmTaskDefinition extends TaskDefinition { path?: string; } +export interface FolderTaskItem extends QuickPickItem { + label: string; + task: Task; +} + type AutoDetect = 'on' | 'off'; let cachedTasks: Task[] | undefined = undefined; @@ -155,6 +160,29 @@ async function detectNpmScripts(): Promise { } } + +export async function detectNpmScriptsForFolder(folder: Uri): Promise { + + let folderTasks: FolderTaskItem[] = []; + + try { + let relativePattern = new RelativePattern(folder.fsPath, '**/package.json'); + let paths = await workspace.findFiles(relativePattern, '**/node_modules/**'); + + let visitedPackageJsonFiles: Set = new Set(); + for (const path of paths) { + if (!visitedPackageJsonFiles.has(path.fsPath)) { + let tasks = await provideNpmScriptsForFolder(path); + visitedPackageJsonFiles.add(path.fsPath); + folderTasks.push(...tasks.map(t => ({ label: t.name, task: t }))); + } + } + return folderTasks; + } catch (error) { + return Promise.reject(error); + } +} + export async function provideNpmScripts(): Promise { if (!cachedTasks) { cachedTasks = await detectNpmScripts(); @@ -209,7 +237,7 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise const prePostScripts = getPrePostScripts(scripts); Object.keys(scripts).forEach(each => { - const task = createTask(each, `run ${each}`, folder!, packageJsonUri); + const task = createTask(each, `run ${each}`, folder!, packageJsonUri, scripts![each]); const lowerCaseTaskName = each.toLowerCase(); if (isBuildTask(lowerCaseTaskName)) { task.group = TaskGroup.Build; @@ -225,7 +253,7 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise result.push(task); }); // always add npm install (without a problem matcher) - result.push(createTask('install', 'install', folder, packageJsonUri, [])); + result.push(createTask('install', 'install', folder, packageJsonUri, 'install dependencies from package', [])); return result; } @@ -236,7 +264,7 @@ export function getTaskName(script: string, relativePath: string | undefined) { return script; } -export function createTask(script: NpmTaskDefinition | string, cmd: string, folder: WorkspaceFolder, packageJsonUri: Uri, matcher?: any): Task { +export function createTask(script: NpmTaskDefinition | string, cmd: string, folder: WorkspaceFolder, packageJsonUri: Uri, detail?: string, matcher?: any): Task { let kind: NpmTaskDefinition; if (typeof script === 'string') { kind = { type: 'npm', script: script }; @@ -264,7 +292,9 @@ export function createTask(script: NpmTaskDefinition | string, cmd: string, fold } let taskName = getTaskName(kind.script, relativePackageJson); let cwd = path.dirname(packageJsonUri.fsPath); - return new Task(kind, folder, taskName, 'npm', new ShellExecution(getCommandLine(folder, cmd), { cwd: cwd }), matcher); + const task = new Task(kind, folder, taskName, 'npm', new ShellExecution(getCommandLine(folder, cmd), { cwd: cwd }), matcher); + task.detail = detail; + return task; } diff --git a/extensions/npm/src/typings/refs.d.ts b/extensions/npm/src/typings/refs.d.ts index bc057c55878..954bab971e3 100644 --- a/extensions/npm/src/typings/refs.d.ts +++ b/extensions/npm/src/typings/refs.d.ts @@ -4,4 +4,5 @@ *--------------------------------------------------------------------------------------------*/ /// +/// /// diff --git a/extensions/npm/yarn.lock b/extensions/npm/yarn.lock index 0f34421c9aa..4c6c723c3cb 100644 --- a/extensions/npm/yarn.lock +++ b/extensions/npm/yarn.lock @@ -7,18 +7,25 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== -agent-base@4, agent-base@^4.1.0: +agent-base@4: 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.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -64,12 +71,12 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -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== +https-proxy-agent@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== dependencies: - agent-base "^4.1.0" + agent-base "^4.3.0" debug "^3.1.0" jsonc-parser@^2.1.1: @@ -89,16 +96,21 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -request-light@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.4.tgz#3cea29c126682e6bcadf7915353322eeba01a755" - integrity sha512-pM9Fq5jRnSb+82V7M97rp8FE9/YNeP2L9eckB4Szd7lyeclSIx02aIpPO/6e4m6Dy31+FBN/zkFMTd2HkNO3ow== +request-light@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.5.tgz#38a3da7b2e56f7af8cbba57e8a94930ee2380746" + integrity sha512-eBEh+GzJAftUnex6tcL6eV2JCifY0+sZMIUpUPOVXbs2nV5hla4ZMmO3icYKGuGVuQ2zHE9evh4OrRcH4iyYYw== dependencies: http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" - vscode-nls "^4.0.0" + https-proxy-agent "^2.2.3" + vscode-nls "^4.1.1" 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== diff --git a/extensions/objective-c/cgmanifest.json b/extensions/objective-c/cgmanifest.json index 5f9ee15e2c1..9ff092c2ab0 100644 --- a/extensions/objective-c/cgmanifest.json +++ b/extensions/objective-c/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "jeff-hykin/cpp-textmate-grammar", "repositoryUrl": "https://github.com/jeff-hykin/cpp-textmate-grammar", - "commitHash": "218448eb46260864352d569db13be6cb20767e92" + "commitHash": "bc7dedd28eebe52b374744d3fb34d77ff441569e" } }, "license": "MIT", diff --git a/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json b/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json index cbfc86907a2..2510f2dc743 100644 --- a/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json +++ b/extensions/objective-c/syntaxes/objective-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/218448eb46260864352d569db13be6cb20767e92", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/bc7dedd28eebe52b374744d3fb34d77ff441569e", "name": "Objective-C++", "scopeName": "source.objcpp", "patterns": [ @@ -293,6 +293,186 @@ } ], "repository": { + "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" + } + ] + } + ] + } + ] + }, "cpp_lang": { "patterns": [ { @@ -6365,255 +6586,6 @@ } } }, - "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", @@ -7093,6 +7065,34 @@ "name": "variable.language.objcpp" } ] + }, + "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" + } + } + } + ] } } } \ 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 389300da8aa..c4f19d8db54 100644 --- a/extensions/objective-c/syntaxes/objective-c.tmLanguage.json +++ b/extensions/objective-c/syntaxes/objective-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/218448eb46260864352d569db13be6cb20767e92", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/bc7dedd28eebe52b374744d3fb34d77ff441569e", "name": "Objective-C", "scopeName": "source.objc", "patterns": [ @@ -290,6 +290,186 @@ } ], "repository": { + "bracketed_content": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.scope.begin.objc" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.scope.end.objc" + } + }, + "name": "meta.bracketed.objc", + "patterns": [ + { + "begin": "(?=predicateWithFormat:)(?<=NSPredicate )(predicateWithFormat:)", + "beginCaptures": { + "1": { + "name": "support.function.any-method.objc" + }, + "2": { + "name": "punctuation.separator.arguments.objc" + } + }, + "end": "(?=\\])", + "name": "meta.function-call.predicate.objc", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objc" + } + }, + "match": "\\bargument(Array|s)(:)", + "name": "support.function.any-method.name-of-parameter.objc" + }, + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objc" + } + }, + "match": "\\b\\w+(:)", + "name": "invalid.illegal.unknown-method.objc" + }, + { + "begin": "@\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objc" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objc" + } + }, + "name": "string.quoted.double.objc", + "patterns": [ + { + "match": "\\b(AND|OR|NOT|IN)\\b", + "name": "keyword.operator.logical.predicate.cocoa.objc" + }, + { + "match": "\\b(ALL|ANY|SOME|NONE)\\b", + "name": "constant.language.predicate.cocoa.objc" + }, + { + "match": "\\b(NULL|NIL|SELF|TRUE|YES|FALSE|NO|FIRST|LAST|SIZE)\\b", + "name": "constant.language.predicate.cocoa.objc" + }, + { + "match": "\\b(MATCHES|CONTAINS|BEGINSWITH|ENDSWITH|BETWEEN)\\b", + "name": "keyword.operator.comparison.predicate.cocoa.objc" + }, + { + "match": "\\bC(ASEINSENSITIVE|I)\\b", + "name": "keyword.other.modifier.predicate.cocoa.objc" + }, + { + "match": "\\b(ANYKEY|SUBQUERY|CAST|TRUEPREDICATE|FALSEPREDICATE)\\b", + "name": "keyword.other.predicate.cocoa.objc" + }, + { + "match": "\\\\(\\\\|[abefnrtv'\"?]|[0-3]\\d{,2}|[4-7]\\d?|x[a-zA-Z0-9]+)", + "name": "constant.character.escape.objc" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unknown-escape.objc" + } + ] + }, + { + "include": "#special_variables" + }, + { + "include": "#c_functions" + }, + { + "include": "$base" + } + ] + }, + { + "begin": "(?=\\w)(?<=[\\w\\])\"] )(\\w+(?:(:)|(?=\\])))", + "beginCaptures": { + "1": { + "name": "support.function.any-method.objc" + }, + "2": { + "name": "punctuation.separator.arguments.objc" + } + }, + "end": "(?=\\])", + "name": "meta.function-call.objc", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objc" + } + }, + "match": "\\b\\w+(:)", + "name": "support.function.any-method.name-of-parameter.objc" + }, + { + "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.objc" + }, + "2": { + "name": "support.function.C99.objc" + } + }, + "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.objc" + }, + "2": { + "name": "support.function.any-method.objc" + }, + "3": { + "name": "punctuation.definition.parameters.objc" + } + }, + "match": "(?x) (?: (?= \\s ) (?:(?<=else|new|return) | (?('validate.enable', true); - let inspect = section.inspect('validate.executablePath'); + this.validationEnabled = section.get(Setting.Enable, true); + let inspect = section.inspect(Setting.ExecutablePath); if (inspect && inspect.workspaceValue) { this.executable = inspect.workspaceValue; this.executableIsUserDefined = false; @@ -144,9 +149,9 @@ export default class PHPValidationProvider { this.executable = undefined; this.executableIsUserDefined = undefined; } - this.trigger = RunTrigger.from(section.get('validate.run', RunTrigger.strings.onSave)); + this.trigger = RunTrigger.from(section.get(Setting.Run, RunTrigger.strings.onSave)); } - if (this.executableIsUserDefined !== true && this.workspaceStore.get(CheckedExecutablePath, undefined) !== undefined) { + if (this.executableIsUserDefined !== true && this.workspaceStore.get(Setting.CheckedExecutablePath, undefined) !== undefined) { vscode.commands.executeCommand('setContext', 'php.untrustValidationExecutableContext', true); } this.delayers = Object.create(null); @@ -172,7 +177,7 @@ export default class PHPValidationProvider { } private untrustValidationExecutable() { - this.workspaceStore.update(CheckedExecutablePath, undefined); + this.workspaceStore.update(Setting.CheckedExecutablePath, undefined); vscode.commands.executeCommand('setContext', 'php.untrustValidationExecutableContext', false); } @@ -196,7 +201,7 @@ export default class PHPValidationProvider { }; if (this.executableIsUserDefined !== undefined && !this.executableIsUserDefined) { - let checkedExecutablePath = this.workspaceStore.get(CheckedExecutablePath, undefined); + let checkedExecutablePath = this.workspaceStore.get(Setting.CheckedExecutablePath, undefined); if (!checkedExecutablePath || checkedExecutablePath !== this.executable) { vscode.window.showInformationMessage( localize('php.useExecutablePath', 'Do you allow {0} (defined as a workspace setting) to be executed to lint PHP files?', this.executable), @@ -213,7 +218,7 @@ export default class PHPValidationProvider { if (!selected || selected.id === 'no') { this.pauseValidation = true; } else if (selected.id === 'yes') { - this.workspaceStore.update(CheckedExecutablePath, this.executable); + this.workspaceStore.update(Setting.CheckedExecutablePath, this.executable); vscode.commands.executeCommand('setContext', 'php.untrustValidationExecutableContext', true); trigger(); } @@ -286,7 +291,7 @@ export default class PHPValidationProvider { }); } - private showError(error: any, executable: string): void { + private async showError(error: any, executable: string): Promise { let message: string | null = null; if (error.code === 'ENOENT') { if (this.executable) { @@ -297,8 +302,13 @@ export default class PHPValidationProvider { } else { message = error.message ? error.message : localize('unknownReason', 'Failed to run php using path: {0}. Reason is unknown.', executable); } - if (message) { - vscode.window.showInformationMessage(message); + if (!message) { + return; + } + + const openSettings = localize('goToSetting', 'Open Settings'); + if (await vscode.window.showInformationMessage(message, openSettings) === openSettings) { + vscode.commands.executeCommand('workbench.action.openSettings', Setting.ExecutablePath); } } } diff --git a/extensions/php-language-features/yarn.lock b/extensions/php-language-features/yarn.lock index e6247e29255..7af62a72ce7 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.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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/php/build/update-grammar.js b/extensions/php/build/update-grammar.js index da01c30d40d..9de0d054233 100644 --- a/extensions/php/build/update-grammar.js +++ b/extensions/php/build/update-grammar.js @@ -21,6 +21,14 @@ function adaptInjectionScope(grammar) { injections[newInjectionKey] = injection; } +function includeDerivativeHtml(grammar) { + grammar.patterns.forEach(pattern => { + if (pattern.include === 'text.html.basic') { + pattern.include = 'text.html.derivative'; + } + }); +} + // Workaround for https://github.com/Microsoft/vscode/issues/40279 // and https://github.com/Microsoft/vscode-textmate/issues/59 function fixBadRegex(grammar) { @@ -61,4 +69,7 @@ function fixBadRegex(grammar) { } updateGrammar.update('atom/language-php', 'grammars/php.cson', './syntaxes/php.tmLanguage.json', fixBadRegex); -updateGrammar.update('atom/language-php', 'grammars/html.cson', './syntaxes/html.tmLanguage.json', adaptInjectionScope); +updateGrammar.update('atom/language-php', 'grammars/html.cson', './syntaxes/html.tmLanguage.json', grammar => { + adaptInjectionScope(grammar); + includeDerivativeHtml(grammar); +}); diff --git a/extensions/php/cgmanifest.json b/extensions/php/cgmanifest.json index c61d3054042..71caf1a84da 100644 --- a/extensions/php/cgmanifest.json +++ b/extensions/php/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "language-php", "repositoryUrl": "https://github.com/atom/language-php", - "commitHash": "0efbd42e73b52347f95ac5f00c9f288ed4958832" + "commitHash": "43a7b842fb58ac7561184db142344a1b127e0d52" } }, "license": "MIT", - "version": "0.44.1" + "version": "0.44.2" } ], "version": 1 diff --git a/extensions/php/language-configuration.json b/extensions/php/language-configuration.json index 2eb11e31045..b9b67d2be50 100644 --- a/extensions/php/language-configuration.json +++ b/extensions/php/language-configuration.json @@ -25,8 +25,8 @@ ["`", "`"] ], "indentationRules": { - "increaseIndentPattern": "({(?!.+}).*|\\(|\\[|((else(\\s)?)?if|else|for(each)?|while|switch).*:)\\s*(/[/*].*)?$", - "decreaseIndentPattern": "^(.*\\*\\/)?\\s*((\\})|(\\)+[;,])|(\\][;,])|\\b(else:)|\\b((end(if|for(each)?|while|switch));))" + "increaseIndentPattern": "({(?!.*}).*|\\(|\\[|((else(\\s)?)?if|else|for(each)?|while|switch|case).*:)\\s*((/[/*].*|)?$|\\?>)", + "decreaseIndentPattern": "^(.*\\*\\/)?\\s*((\\})|(\\)+[;,])|(\\][;,])|\\b(else:)|\\b((end(if|for(each)?|while|switch)|break);))" }, "folding": { "markers": { @@ -34,4 +34,4 @@ "end": "^\\s*(#|\/\/)endregion\\b" } } -} \ No newline at end of file +} diff --git a/extensions/php/syntaxes/html.tmLanguage.json b/extensions/php/syntaxes/html.tmLanguage.json index 09d631c14c2..4bf15294159 100644 --- a/extensions/php/syntaxes/html.tmLanguage.json +++ b/extensions/php/syntaxes/html.tmLanguage.json @@ -129,7 +129,7 @@ "name": "comment.line.shebang.php" }, { - "include": "text.html.basic" + "include": "text.html.derivative" } ], "repository": { diff --git a/extensions/php/syntaxes/php.tmLanguage.json b/extensions/php/syntaxes/php.tmLanguage.json index a480a7d1946..2b9370f917c 100644 --- a/extensions/php/syntaxes/php.tmLanguage.json +++ b/extensions/php/syntaxes/php.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-php/commit/0efbd42e73b52347f95ac5f00c9f288ed4958832", + "version": "https://github.com/atom/language-php/commit/43a7b842fb58ac7561184db142344a1b127e0d52", "scopeName": "source.php", "patterns": [ { @@ -448,6 +448,9 @@ "end": "(?={)", "name": "meta.function.closure.php", "patterns": [ + { + "include": "#comments" + }, { "begin": "\\(", "beginCaptures": { @@ -2736,7 +2739,7 @@ "name": "support.function.enchant.php" }, { - "match": "(?i)\\bsplit(i)?|sql_regcase|ereg(i)?(_replace)?\\b", + "match": "(?i)\\b(split(i)?|sql_regcase|ereg(i)?(_replace)?)\\b", "name": "support.function.ereg.php" }, { @@ -2744,7 +2747,7 @@ "name": "support.function.errorfunc.php" }, { - "match": "(?i)\\bshell_exec|system|passthru|proc_(nice|close|terminate|open|get_status)|escapeshell(arg|cmd)|exec\\b", + "match": "(?i)\\b(shell_exec|system|passthru|proc_(nice|close|terminate|open|get_status)|escapeshell(arg|cmd)|exec)\\b", "name": "support.function.exec.php" }, { @@ -3315,7 +3318,7 @@ "name": "keyword.operator.ternary.php" } }, - "end": ":", + "end": "(? diff --git a/extensions/php/test/colorize-results/issue-76997_php.json b/extensions/php/test/colorize-results/issue-76997_php.json new file mode 100644 index 00000000000..c6863dda6fb --- /dev/null +++ b/extensions/php/test/colorize-results/issue-76997_php.json @@ -0,0 +1,68 @@ +[ + { + "c": "<", + "t": "text.html.php meta.tag.other.unrecognized.html.derivative punctuation.definition.tag.begin.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "hello", + "t": "text.html.php meta.tag.other.unrecognized.html.derivative entity.name.tag.html", + "r": { + "dark_plus": "entity.name.tag: #569CD6", + "light_plus": "entity.name.tag: #800000", + "dark_vs": "entity.name.tag: #569CD6", + "light_vs": "entity.name.tag: #800000", + "hc_black": "entity.name.tag: #569CD6" + } + }, + { + "c": ">", + "t": "text.html.php meta.tag.other.unrecognized.html.derivative punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + }, + { + "c": "", + "t": "text.html.php meta.tag.other.unrecognized.html.derivative punctuation.definition.tag.end.html", + "r": { + "dark_plus": "punctuation.definition.tag: #808080", + "light_plus": "punctuation.definition.tag: #800000", + "dark_vs": "punctuation.definition.tag: #808080", + "light_vs": "punctuation.definition.tag: #800000", + "hc_black": "punctuation.definition.tag: #808080" + } + } +] \ No newline at end of file diff --git a/extensions/python/cgmanifest.json b/extensions/python/cgmanifest.json index 139ae46369b..3ee82895a82 100644 --- a/extensions/python/cgmanifest.json +++ b/extensions/python/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "MagicStack/MagicPython", "repositoryUrl": "https://github.com/MagicStack/MagicPython", - "commitHash": "38422d302fe0b3e7716d26ce8cd7d0b9685f3a38" + "commitHash": "c0f8d514bbe6e9d3899f2b002bcd6971aef5e34b" } }, "license": "MIT", diff --git a/extensions/python/syntaxes/MagicPython.tmLanguage.json b/extensions/python/syntaxes/MagicPython.tmLanguage.json index d89e7ed110d..f59618f75ff 100644 --- a/extensions/python/syntaxes/MagicPython.tmLanguage.json +++ b/extensions/python/syntaxes/MagicPython.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/MagicStack/MagicPython/commit/38422d302fe0b3e7716d26ce8cd7d0b9685f3a38", + "version": "https://github.com/MagicStack/MagicPython/commit/c0f8d514bbe6e9d3899f2b002bcd6971aef5e34b", "name": "MagicPython", "scopeName": "source.python", "patterns": [ @@ -374,6 +374,7 @@ ] }, "member-access": { + "name": "meta.member.access.python", "begin": "(\\.)\\s*(?!\\.)", "end": "(?x)\n # stop when you've just read non-whitespace followed by non-word\n # i.e. when finished reading an identifier or function call\n (?<=\\S)(?=\\W) |\n # stop when seeing the start of something that's not a word,\n # i.e. when seeing a non-identifier\n (^|(?<=\\s))(?=[^\\\\\\w\\s]) |\n $\n", "beginCaptures": { @@ -1067,6 +1068,7 @@ } }, "member-access-class": { + "name": "meta.member.access.python", "begin": "(\\.)\\s*(?!\\.)", "end": "(?<=\\S)(?=\\W)|$", "beginCaptures": { diff --git a/extensions/python/test/colorize-results/test-freeze-56377_py.json b/extensions/python/test/colorize-results/test-freeze-56377_py.json index 364269c8555..63889e26fee 100644 --- a/extensions/python/test/colorize-results/test-freeze-56377_py.json +++ b/extensions/python/test/colorize-results/test-freeze-56377_py.json @@ -287,7 +287,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -298,7 +298,7 @@ }, { "c": "request", - "t": "source.python", + "t": "source.python meta.member.access.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -309,7 +309,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -320,7 +320,7 @@ }, { "c": "META", - "t": "source.python constant.other.caps.python", + "t": "source.python meta.member.access.python constant.other.caps.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -331,7 +331,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -342,7 +342,7 @@ }, { "c": "items", - "t": "source.python meta.function-call.python meta.function-call.generic.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.generic.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -353,7 +353,7 @@ }, { "c": "(", - "t": "source.python meta.function-call.python punctuation.definition.arguments.begin.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.begin.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -364,7 +364,7 @@ }, { "c": ")", - "t": "source.python meta.function-call.python punctuation.definition.arguments.end.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.end.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -408,7 +408,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -419,7 +419,7 @@ }, { "c": "startswith", - "t": "source.python meta.function-call.python meta.function-call.generic.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.generic.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -430,7 +430,7 @@ }, { "c": "(", - "t": "source.python meta.function-call.python punctuation.definition.arguments.begin.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.begin.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -441,7 +441,7 @@ }, { "c": "'", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.quoted.single.python punctuation.definition.string.begin.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.quoted.single.python punctuation.definition.string.begin.python", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -452,7 +452,7 @@ }, { "c": "HTTP_", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.quoted.single.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.quoted.single.python", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -463,7 +463,7 @@ }, { "c": "'", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.quoted.single.python punctuation.definition.string.end.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.quoted.single.python punctuation.definition.string.end.python", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -474,7 +474,7 @@ }, { "c": ")", - "t": "source.python meta.function-call.python punctuation.definition.arguments.end.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.end.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/python/test/colorize-results/test_py.json b/extensions/python/test/colorize-results/test_py.json index 8586d7c9b9e..2c312658625 100644 --- a/extensions/python/test/colorize-results/test_py.json +++ b/extensions/python/test/colorize-results/test_py.json @@ -419,7 +419,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -430,7 +430,7 @@ }, { "c": "size", - "t": "source.python", + "t": "source.python meta.member.access.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2223,7 +2223,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2234,7 +2234,7 @@ }, { "c": "next", - "t": "source.python meta.function-call.python meta.function-call.generic.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.generic.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2245,7 +2245,7 @@ }, { "c": "(", - "t": "source.python meta.function-call.python punctuation.definition.arguments.begin.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.begin.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2256,7 +2256,7 @@ }, { "c": ")", - "t": "source.python meta.function-call.python punctuation.definition.arguments.end.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.end.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4533,7 +4533,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4543,7 +4543,18 @@ } }, { - "c": "fn ", + "c": "fn", + "t": "source.python meta.member.access.python", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", "t": "source.python", "r": { "dark_plus": "default: #D4D4D4", @@ -4599,7 +4610,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4609,7 +4620,18 @@ } }, { - "c": "memo ", + "c": "memo", + "t": "source.python meta.member.access.python", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", "t": "source.python", "r": { "dark_plus": "default: #D4D4D4", @@ -4885,7 +4907,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4896,7 +4918,7 @@ }, { "c": "memo", - "t": "source.python", + "t": "source.python meta.member.access.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4940,7 +4962,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4951,7 +4973,7 @@ }, { "c": "memo", - "t": "source.python meta.item-access.python", + "t": "source.python meta.member.access.python meta.item-access.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4962,7 +4984,7 @@ }, { "c": "[", - "t": "source.python meta.item-access.python punctuation.definition.arguments.begin.python", + "t": "source.python meta.member.access.python meta.item-access.python punctuation.definition.arguments.begin.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4973,7 +4995,7 @@ }, { "c": "args", - "t": "source.python meta.item-access.python meta.item-access.arguments.python", + "t": "source.python meta.member.access.python meta.item-access.python meta.item-access.arguments.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -4984,7 +5006,7 @@ }, { "c": "]", - "t": "source.python meta.item-access.python punctuation.definition.arguments.end.python", + "t": "source.python meta.member.access.python meta.item-access.python punctuation.definition.arguments.end.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5039,7 +5061,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5050,7 +5072,7 @@ }, { "c": "fn", - "t": "source.python meta.function-call.python meta.function-call.generic.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.generic.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5061,7 +5083,7 @@ }, { "c": "(", - "t": "source.python meta.function-call.python punctuation.definition.arguments.begin.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.begin.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5072,7 +5094,7 @@ }, { "c": "*", - "t": "source.python meta.function-call.python meta.function-call.arguments.python keyword.operator.unpacking.arguments.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python keyword.operator.unpacking.arguments.python", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -5083,7 +5105,7 @@ }, { "c": "args", - "t": "source.python meta.function-call.python meta.function-call.arguments.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5094,7 +5116,7 @@ }, { "c": ")", - "t": "source.python meta.function-call.python punctuation.definition.arguments.end.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.end.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5149,7 +5171,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5160,7 +5182,7 @@ }, { "c": "memo", - "t": "source.python meta.item-access.python", + "t": "source.python meta.member.access.python meta.item-access.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5171,7 +5193,7 @@ }, { "c": "[", - "t": "source.python meta.item-access.python punctuation.definition.arguments.begin.python", + "t": "source.python meta.member.access.python meta.item-access.python punctuation.definition.arguments.begin.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5182,7 +5204,7 @@ }, { "c": "args", - "t": "source.python meta.item-access.python meta.item-access.arguments.python", + "t": "source.python meta.member.access.python meta.item-access.python meta.item-access.arguments.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5193,7 +5215,7 @@ }, { "c": "]", - "t": "source.python meta.item-access.python punctuation.definition.arguments.end.python", + "t": "source.python meta.member.access.python meta.item-access.python punctuation.definition.arguments.end.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5237,7 +5259,7 @@ }, { "c": ".", - "t": "source.python punctuation.separator.period.python", + "t": "source.python meta.member.access.python punctuation.separator.period.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5248,7 +5270,7 @@ }, { "c": "search", - "t": "source.python meta.function-call.python meta.function-call.generic.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.generic.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5259,7 +5281,7 @@ }, { "c": "(", - "t": "source.python meta.function-call.python punctuation.definition.arguments.begin.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.begin.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5270,7 +5292,7 @@ }, { "c": "r", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python storage.type.string.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python storage.type.string.python", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -5281,7 +5303,7 @@ }, { "c": "\"", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python punctuation.definition.string.begin.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python punctuation.definition.string.begin.python", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -5292,7 +5314,7 @@ }, { "c": "(", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", "r": { "dark_plus": "support.other.parenthesis.regexp: #CE9178", "light_plus": "support.other.parenthesis.regexp: #D16969", @@ -5303,7 +5325,7 @@ }, { "c": "[", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp", "r": { "dark_plus": "punctuation.character.set.begin.regexp: #CE9178", "light_plus": "punctuation.character.set.begin.regexp: #D16969", @@ -5314,7 +5336,7 @@ }, { "c": "0-9-", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp constant.character.set.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp constant.character.set.regexp", "r": { "dark_plus": "constant.character.set.regexp: #D16969", "light_plus": "constant.character.set.regexp: #811F3F", @@ -5325,7 +5347,7 @@ }, { "c": "]", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.end.regexp constant.other.set.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.end.regexp constant.other.set.regexp", "r": { "dark_plus": "punctuation.character.set.end.regexp: #CE9178", "light_plus": "punctuation.character.set.end.regexp: #D16969", @@ -5336,7 +5358,7 @@ }, { "c": "*", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", "light_plus": "keyword.operator.quantifier.regexp: #000000", @@ -5347,7 +5369,7 @@ }, { "c": ")", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", "r": { "dark_plus": "support.other.parenthesis.regexp: #CE9178", "light_plus": "support.other.parenthesis.regexp: #D16969", @@ -5358,7 +5380,7 @@ }, { "c": "\\s", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.escape.special.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.escape.special.regexp", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -5369,7 +5391,7 @@ }, { "c": "*", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", "light_plus": "keyword.operator.quantifier.regexp: #000000", @@ -5380,7 +5402,7 @@ }, { "c": "(", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", "r": { "dark_plus": "support.other.parenthesis.regexp: #CE9178", "light_plus": "support.other.parenthesis.regexp: #D16969", @@ -5391,7 +5413,7 @@ }, { "c": "[", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp", "r": { "dark_plus": "punctuation.character.set.begin.regexp: #CE9178", "light_plus": "punctuation.character.set.begin.regexp: #D16969", @@ -5402,7 +5424,7 @@ }, { "c": "A-Za-z", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp constant.character.set.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp constant.character.set.regexp", "r": { "dark_plus": "constant.character.set.regexp: #D16969", "light_plus": "constant.character.set.regexp: #811F3F", @@ -5413,7 +5435,7 @@ }, { "c": "]", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.end.regexp constant.other.set.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.end.regexp constant.other.set.regexp", "r": { "dark_plus": "punctuation.character.set.end.regexp: #CE9178", "light_plus": "punctuation.character.set.end.regexp: #D16969", @@ -5424,7 +5446,7 @@ }, { "c": "+", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", "light_plus": "keyword.operator.quantifier.regexp: #000000", @@ -5435,7 +5457,7 @@ }, { "c": ")", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", "r": { "dark_plus": "support.other.parenthesis.regexp: #CE9178", "light_plus": "support.other.parenthesis.regexp: #D16969", @@ -5446,7 +5468,7 @@ }, { "c": ",", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -5457,7 +5479,7 @@ }, { "c": "\\s", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.escape.special.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.escape.special.regexp", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -5468,7 +5490,7 @@ }, { "c": "+", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", "light_plus": "keyword.operator.quantifier.regexp: #000000", @@ -5479,7 +5501,7 @@ }, { "c": "(", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp", "r": { "dark_plus": "support.other.parenthesis.regexp: #CE9178", "light_plus": "support.other.parenthesis.regexp: #D16969", @@ -5490,7 +5512,7 @@ }, { "c": ".", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.match.any.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.match.any.regexp", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -5501,7 +5523,7 @@ }, { "c": "*", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp", "r": { "dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D", "light_plus": "keyword.operator.quantifier.regexp: #000000", @@ -5512,7 +5534,7 @@ }, { "c": ")", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp", "r": { "dark_plus": "support.other.parenthesis.regexp: #CE9178", "light_plus": "support.other.parenthesis.regexp: #D16969", @@ -5523,7 +5545,7 @@ }, { "c": "\"", - "t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python punctuation.definition.string.end.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python punctuation.definition.string.end.python", "r": { "dark_plus": "string.regexp: #D16969", "light_plus": "string.regexp: #811F3F", @@ -5534,7 +5556,7 @@ }, { "c": ",", - "t": "source.python meta.function-call.python meta.function-call.arguments.python punctuation.separator.arguments.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python punctuation.separator.arguments.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5545,7 +5567,7 @@ }, { "c": " i", - "t": "source.python meta.function-call.python meta.function-call.arguments.python", + "t": "source.python meta.member.access.python meta.function-call.python meta.function-call.arguments.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -5556,7 +5578,7 @@ }, { "c": ")", - "t": "source.python meta.function-call.python punctuation.definition.arguments.end.python", + "t": "source.python meta.member.access.python meta.function-call.python punctuation.definition.arguments.end.python", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/ruby/cgmanifest.json b/extensions/ruby/cgmanifest.json index 8f04db20f54..d6b94faac3d 100644 --- a/extensions/ruby/cgmanifest.json +++ b/extensions/ruby/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "textmate/ruby.tmbundle", "repositoryUrl": "https://github.com/textmate/ruby.tmbundle", - "commitHash": "05698e99314d8653e2e9d8f198d3c83e387ee1eb" + "commitHash": "8d525dd4a0b77ae041593ff26dc883a694c648c5" } }, "licenseDetail": [ diff --git a/extensions/ruby/syntaxes/ruby.tmLanguage.json b/extensions/ruby/syntaxes/ruby.tmLanguage.json index 8b6c98616d8..d223655d8d5 100644 --- a/extensions/ruby/syntaxes/ruby.tmLanguage.json +++ b/extensions/ruby/syntaxes/ruby.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/ruby.tmbundle/commit/05698e99314d8653e2e9d8f198d3c83e387ee1eb", + "version": "https://github.com/textmate/ruby.tmbundle/commit/8d525dd4a0b77ae041593ff26dc883a694c648c5", "name": "Ruby", "scopeName": "source.ruby", "comment": "\n\tTODO: unresolved issues\n\n\ttext:\n\t\"p <+~|] # - Another selector\n | /\\* # - A block comment\n)", + "match": "(?x)\n(\\.) # Valid class-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n | ; # - A semicolon\n)", "name": "entity.other.attribute-name.class.css", "captures": { "1": { diff --git a/extensions/scss/test/colorize-results/test_scss.json b/extensions/scss/test/colorize-results/test_scss.json index 617eec833cb..25154050795 100644 --- a/extensions/scss/test/colorize-results/test_scss.json +++ b/extensions/scss/test/colorize-results/test_scss.json @@ -7436,7 +7436,7 @@ } }, { - "c": " .error", + "c": " ", "t": "source.css.scss meta.property-list.scss meta.at-rule.extend.scss", "r": { "dark_plus": "default: #D4D4D4", @@ -7446,6 +7446,28 @@ "hc_black": "default: #FFFFFF" } }, + { + "c": ".", + "t": "source.css.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.class.css punctuation.definition.entity.css", + "r": { + "dark_plus": "entity.other.attribute-name.class.css: #D7BA7D", + "light_plus": "entity.other.attribute-name.class.css: #800000", + "dark_vs": "entity.other.attribute-name.class.css: #D7BA7D", + "light_vs": "entity.other.attribute-name.class.css: #800000", + "hc_black": "entity.other.attribute-name.class.css: #D7BA7D" + } + }, + { + "c": "error", + "t": "source.css.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.class.css", + "r": { + "dark_plus": "entity.other.attribute-name.class.css: #D7BA7D", + "light_plus": "entity.other.attribute-name.class.css: #800000", + "dark_vs": "entity.other.attribute-name.class.css: #D7BA7D", + "light_vs": "entity.other.attribute-name.class.css: #800000", + "hc_black": "entity.other.attribute-name.class.css: #D7BA7D" + } + }, { "c": ";", "t": "source.css.scss meta.property-list.scss punctuation.terminator.rule.css", @@ -17798,7 +17820,7 @@ } }, { - "c": " .", + "c": " ", "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss", "r": { "dark_plus": "default: #D4D4D4", @@ -17808,20 +17830,31 @@ "hc_black": "default: #FFFFFF" } }, + { + "c": ".", + "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.class.css punctuation.definition.entity.css", + "r": { + "dark_plus": "entity.other.attribute-name.class.css: #D7BA7D", + "light_plus": "entity.other.attribute-name.class.css: #800000", + "dark_vs": "entity.other.attribute-name.class.css: #D7BA7D", + "light_vs": "entity.other.attribute-name.class.css: #800000", + "hc_black": "entity.other.attribute-name.class.css: #D7BA7D" + } + }, { "c": "#{", - "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss variable.interpolation.scss punctuation.definition.interpolation.begin.bracket.curly.scss", + "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.class.css variable.interpolation.scss punctuation.definition.interpolation.begin.bracket.curly.scss", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "entity.other.attribute-name.class.css: #D7BA7D", + "light_vs": "entity.other.attribute-name.class.css: #800000", "hc_black": "variable: #9CDCFE" } }, { "c": "$a", - "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss variable.interpolation.scss variable.scss", + "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.class.css variable.interpolation.scss variable.scss", "r": { "dark_plus": "variable.scss: #9CDCFE", "light_plus": "variable.scss: #FF0000", @@ -17832,12 +17865,12 @@ }, { "c": "}", - "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss variable.interpolation.scss punctuation.definition.interpolation.end.bracket.curly.scss", + "t": "source.css.scss meta.at-rule.each.scss meta.at-rule.while.scss meta.property-list.scss meta.property-list.scss meta.at-rule.extend.scss entity.other.attribute-name.class.css variable.interpolation.scss punctuation.definition.interpolation.end.bracket.curly.scss", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", + "dark_vs": "entity.other.attribute-name.class.css: #D7BA7D", + "light_vs": "entity.other.attribute-name.class.css: #800000", "hc_black": "variable: #9CDCFE" } }, diff --git a/extensions/shellscript/package.json b/extensions/shellscript/package.json index a55af2b08ff..211401a070c 100644 --- a/extensions/shellscript/package.json +++ b/extensions/shellscript/package.json @@ -23,6 +23,12 @@ "language": "shellscript", "scopeName": "source.shell", "path": "./syntaxes/shell-unix-bash.tmLanguage.json" - }] + }], + "configurationDefaults": { + "[shellscript]": { + "files.eol": "\n" + } + } + } } diff --git a/extensions/sql/language-configuration.json b/extensions/sql/language-configuration.json index a9c154bcec8..cf96472ffd8 100644 --- a/extensions/sql/language-configuration.json +++ b/extensions/sql/language-configuration.json @@ -12,8 +12,9 @@ ["{", "}"], ["[", "]"], ["(", ")"], - ["\"", "\""], - ["'", "'"] + { "open": "\"", "close": "\"", "notIn": ["string"] }, + { "open": "N'", "close": "'", "notIn": ["string", "comment"] }, + { "open": "'", "close": "'", "notIn": ["string", "comment"] } ], "surroundingPairs": [ ["{", "}"], diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 18c8235f79c..f0a326bb34d 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -3,14 +3,12 @@ "tokenColors": [ { "settings": { - "background": "#000c18", "foreground": "#6688cc" } }, { "scope": ["meta.embedded", "source.groovy.embedded"], "settings": { - "background": "#000c18", "foreground": "#6688cc" } }, @@ -173,7 +171,6 @@ "name": "Invalid", "scope": "invalid", "settings": { - "background": "#F92672", "fontStyle": "", "foreground": "#F8F8F0" } @@ -182,7 +179,6 @@ "name": "Invalid deprecated", "scope": "invalid.deprecated", "settings": { - "background": "#AE81FF", "foreground": "#F8F8F0" } }, @@ -193,7 +189,6 @@ "meta.diff.header" ], "settings": { - "background": "#b58900", "fontStyle": "italic", "foreground": "#E0EDDD" } @@ -202,7 +197,6 @@ "name": "diff: deleted", "scope": "markup.deleted", "settings": { - "background": "#eee8d5", "fontStyle": "", "foreground": "#dc322f" } @@ -211,7 +205,6 @@ "name": "diff: changed", "scope": "markup.changed", "settings": { - "background": "#eee8d5", "fontStyle": "", "foreground": "#cb4b16" } @@ -220,7 +213,6 @@ "name": "diff: inserted", "scope": "markup.inserted", "settings": { - "background": "#eee8d5", "foreground": "#219186" } }, @@ -378,7 +370,6 @@ "tab.border": "#2b2b4a", // "tab.activeBackground": "", "tab.inactiveBackground": "#10192c", - "tab.modifiedBorder": "#0072bf", // "tab.activeForeground": "", // "tab.inactiveForeground": "", diff --git a/extensions/theme-defaults/themes/dark_vs.json b/extensions/theme-defaults/themes/dark_vs.json index 34228835df1..479b5fd8988 100644 --- a/extensions/theme-defaults/themes/dark_vs.json +++ b/extensions/theme-defaults/themes/dark_vs.json @@ -171,8 +171,7 @@ }, { "scope": [ - "meta.preprocessor", - "keyword.control.directive" + "meta.preprocessor" ], "settings": { "foreground": "#569cd6" @@ -307,6 +306,7 @@ "keyword.operator.expression", "keyword.operator.cast", "keyword.operator.sizeof", + "keyword.operator.alignof", "keyword.operator.typeid", "keyword.operator.alignas", "keyword.operator.instanceof", diff --git a/extensions/theme-defaults/themes/light_vs.json b/extensions/theme-defaults/themes/light_vs.json index 96cb7a76fa6..886d1175c8b 100644 --- a/extensions/theme-defaults/themes/light_vs.json +++ b/extensions/theme-defaults/themes/light_vs.json @@ -169,8 +169,7 @@ }, { "scope": [ - "meta.preprocessor", - "keyword.control.directive" + "meta.preprocessor" ], "settings": { "foreground": "#0000ff" @@ -331,6 +330,7 @@ "keyword.operator.expression", "keyword.operator.cast", "keyword.operator.sizeof", + "keyword.operator.alignof", "keyword.operator.typeid", "keyword.operator.alignas", "keyword.operator.instanceof", 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 d3a76435f61..111a4a23d9b 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -23,7 +23,6 @@ "editorGroupHeader.tabsBackground": "#131510", "editorLineNumber.activeForeground": "#adadad", "tab.inactiveBackground": "#131510", - "tab.modifiedBorder": "#cd9731", "titleBar.activeBackground": "#423523", "statusBar.background": "#423523", "statusBar.debuggingBackground": "#423523", @@ -55,14 +54,12 @@ "tokenColors": [ { "settings": { - "background": "#221a0f", "foreground": "#d3af86" } }, { "scope": ["meta.embedded", "source.groovy.embedded"], "settings": { - "background": "#221a0f", "foreground": "#d3af86" } }, @@ -335,7 +332,6 @@ "name": "Separator", "scope": "meta.separator", "settings": { - "background": "#84613d", "foreground": "#d3af86" } }, 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 0a5851352b8..f0b6126d5fd 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -24,7 +24,6 @@ "editorGroupHeader.tabsBackground": "#282828", "tab.inactiveBackground": "#404040", "tab.border": "#303030", - "tab.modifiedBorder": "#6796e6", "tab.inactiveForeground": "#d8d8d8", "peekView.border": "#3655b5", "panelTitle.activeForeground": "#ffffff", @@ -48,24 +47,15 @@ "tokenColors": [ { "settings": { - "background": "#1e1e1e", "foreground": "#C5C8C6" } }, - { - "name": "By uonick", - "settings": { - "background": "#202025ff", - "foreground": "#c5c8c6ff" - } - }, { "scope": [ "meta.embedded", "source.groovy.embedded" ], "settings": { - "background": "#1e1e1e", "foreground": "#C5C8C6" } }, @@ -115,7 +105,6 @@ "settings": { "fontStyle": "", "foreground": "#8080FF", - "background": "#1e1e1e" } }, { @@ -148,7 +137,6 @@ "settings": { "fontStyle": "", "foreground": "#9B0000", - "background": "#1E1E1E" } }, { @@ -482,7 +470,6 @@ "name": "diff: header", "scope": "meta.diff, meta.diff.header", "settings": { - "background": "#b58900", "fontStyle": "italic", "foreground": "#E0EDDD" } @@ -491,7 +478,6 @@ "name": "diff: deleted", "scope": "markup.deleted", "settings": { - "background": "#eee8d5", "fontStyle": "", "foreground": "#dc322f" } @@ -500,7 +486,6 @@ "name": "diff: changed", "scope": "markup.changed", "settings": { - "background": "#eee8d5", "fontStyle": "", "foreground": "#cb4b16" } @@ -509,7 +494,6 @@ "name": "diff: inserted", "scope": "markup.inserted", "settings": { - "background": "#eee8d5", "foreground": "#219186" } }, diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index ebff3a44985..6bc2e84ce98 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -36,7 +36,6 @@ "editorGroup.dropBackground": "#41433980", "tab.inactiveBackground": "#34352f", "tab.border": "#1e1f1c", - "tab.modifiedBorder": "#007acc", "tab.inactiveForeground": "#ccccc7", // needs to be bright so it's readable when another editor group is focused "widget.shadow": "#000000", "progressBar.background": "#75715E", @@ -65,8 +64,8 @@ "focusBorder": "#75715E", "editorWidget.background": "#1e1f1c", "debugToolBar.background": "#1e1f1c", - "diffEditor.insertedTextBackground": "#66852880", // middle of #272822 and #a6e22e - "diffEditor.removedTextBackground": "#90274A80", // middle of #272822 and #f92672 + "diffEditor.insertedTextBackground": "#4b661680", // middle of #272822 and #a6e22e + "diffEditor.removedTextBackground": "#90274A70", // middle of #272822 and #f92672 "inputValidation.errorBackground": "#90274A", // middle of #272822 and #f92672 "inputValidation.errorBorder": "#f92672", "inputValidation.warningBackground": "#848528", // middle of #272822 and #e2e22e @@ -105,7 +104,6 @@ "tokenColors": [ { "settings": { - "background": "#272822", "foreground": "#F8F8F2" } }, @@ -115,7 +113,6 @@ "source.groovy.embedded" ], "settings": { - "background": "#272822", "foreground": "#F8F8F2" } }, @@ -123,7 +120,7 @@ "name": "Comment", "scope": "comment", "settings": { - "foreground": "#75715E" + "foreground": "#88846f" } }, { @@ -287,7 +284,6 @@ "name": "Invalid", "scope": "invalid", "settings": { - "background": "#F92672", "fontStyle": "", "foreground": "#F8F8F0" } @@ -296,7 +292,6 @@ "name": "Invalid deprecated", "scope": "invalid.deprecated", "settings": { - "background": "#AE81FF", "foreground": "#F8F8F0" } }, diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 355924fea21..ae19ba7889b 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -3,7 +3,6 @@ "tokenColors": [ { "settings": { - "background": "#F5F5F5", "foreground": "#333333" } }, @@ -13,7 +12,6 @@ "source.groovy.embedded" ], "settings": { - "background": "#F5F5F5", "foreground": "#333333" } }, @@ -47,18 +45,10 @@ "foreground": "#448C27" } }, - { - "name": "Invalid - Deprecated", - "scope": "invalid.deprecated", - "settings": { - "background": "#96000014" - } - }, { "name": "Invalid - Illegal", "scope": "invalid.illegal", "settings": { - "background": "#96000014", "foreground": "#660000" } }, @@ -195,20 +185,6 @@ "foreground": "#777777" } }, - { - "name": "Embedded Source", - "scope": [ - "string source", - "text source" - ], - "settings": { - "background": "#EAEBE6" - } - }, - { - "name": "-----------------------------------", - "settings": {} - }, { "name": "HTML: Doctype Declaration", "scope": [ @@ -261,10 +237,6 @@ "foreground": "#9C5D27" } }, - { - "name": "-----------------------------------", - "settings": {} - }, { "name": "CSS: Selectors", "scope": [ @@ -305,15 +277,10 @@ "fontStyle": "bold" } }, - { - "name": "-----------------------------------", - "settings": {} - }, { "name": "Markup: Changed", "scope": "markup.changed", "settings": { - "background": "#FFFFDD", "foreground": "#000000" } }, @@ -321,7 +288,6 @@ "name": "Markup: Deletion", "scope": "markup.deleted", "settings": { - "background": "#FFDDDD", "foreground": "#000000" } }, @@ -336,7 +302,6 @@ "name": "Markup: Error", "scope": "markup.error", "settings": { - "background": "#96000014", "foreground": "#660000" } }, @@ -344,7 +309,6 @@ "name": "Markup: Insertion", "scope": "markup.inserted", "settings": { - "background": "#DDFFDD", "foreground": "#000000" } }, @@ -432,10 +396,6 @@ "foreground": "#9C5D27" } }, - { - "name": "-----------------------------------", - "settings": {} - }, { "name": "Extra: Diff Range", "scope": [ @@ -444,7 +404,6 @@ "meta.separator" ], "settings": { - "background": "#DDDDFF", "foreground": "#434343" } }, @@ -452,7 +411,6 @@ "name": "Extra: Diff From", "scope": "meta.diff.header.from-file", "settings": { - "background": "#FFDDDD", "foreground": "#434343" } }, @@ -460,7 +418,6 @@ "name": "Extra: Diff To", "scope": "meta.diff.header.to-file", "settings": { - "background": "#DDFFDD", "foreground": "#434343" } }, @@ -500,7 +457,6 @@ "editorLineNumber.activeForeground": "#9769dc", "editor.selectionBackground": "#C9D0D9", "minimap.selectionHighlight": "#C9D0D9", - "tab.modifiedBorder": "#f1897f", "panel.background": "#F5F5F5", "sideBar.background": "#F2F2F2", "sideBarSectionHeader.background": "#ede8ef", diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index 309a4273fbd..277e7a8db3f 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -5,7 +5,6 @@ "activityBar.background": "#580000", "tab.inactiveBackground": "#300a0a", "tab.activeBackground": "#490000", - "tab.modifiedBorder": "#db7e58", "sideBar.background": "#330000", "statusBar.background": "#700000", "statusBar.noFolderBackground": "#700000", @@ -62,12 +61,7 @@ "tokenColors": [ { "settings": { - "background": "#390000", - "caret": "#970000", "foreground": "#F8F8F8", - "invisibles": "#c10000", - "lineHighlight": "#0000004A", - "selection": "#750000" } }, { @@ -76,7 +70,6 @@ "source.groovy.embedded" ], "settings": { - "background": "#390000", "foreground": "#F8F8F8" } }, @@ -148,24 +141,9 @@ "name": "Invalid", "scope": "invalid", "settings": { - "background": "#fd6209ff", "foreground": "#ffffffff" } }, - { - "name": "Embedded Source", - "scope": "text source", - "settings": { - "background": "#b0b3ba14" - } - }, - { - "name": "Embedded Source (Bright)", - "scope": "text.html.ruby source", - "settings": { - "background": "#b1b3ba21" - } - }, { "name": "Entity inherited-class", "scope": "entity.other.inherited-class", @@ -323,7 +301,6 @@ "meta.diff.header" ], "settings": { - "background": "#0b2f20ff", "fontStyle": "italic", "foreground": "#f8f8f8ff" } @@ -332,7 +309,6 @@ "name": "diff.deleted", "scope": "markup.deleted", "settings": { - "background": "#fedcddff", "foreground": "#ec9799ff" } }, @@ -340,7 +316,6 @@ "name": "diff.changed", "scope": "markup.changed", "settings": { - "background": "#c4b14aff", "foreground": "#f8f8f8ff" } }, @@ -348,7 +323,6 @@ "name": "diff.inserted", "scope": "markup.inserted", "settings": { - "background": "#9bf199ff", "foreground": "#41a83eff" } }, 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 0d6851d5318..682444485d5 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -3,14 +3,12 @@ "tokenColors": [ { "settings": { - "background": "#002B36", "foreground": "#93A1A1" } }, { "scope": ["meta.embedded", "source.groovy.embedded"], "settings": { - "background": "#002B36", "foreground": "#93A1A1" } }, @@ -221,7 +219,6 @@ "meta.diff.header" ], "settings": { - "background": "#b58900", "fontStyle": "italic", "foreground": "#E0EDDD" } @@ -230,7 +227,6 @@ "name": "diff: deleted", "scope": "markup.deleted", "settings": { - "background": "#eee8d5", "fontStyle": "", "foreground": "#dc322f" } @@ -239,7 +235,6 @@ "name": "diff: changed", "scope": "markup.changed", "settings": { - "background": "#eee8d5", "fontStyle": "", "foreground": "#cb4b16" } @@ -248,7 +243,6 @@ "name": "diff: inserted", "scope": "markup.inserted", "settings": { - "background": "#eee8d5", "foreground": "#219186" } }, @@ -425,7 +419,6 @@ "tab.inactiveForeground": "#93A1A1", "tab.inactiveBackground": "#004052", "tab.border": "#003847", - "tab.modifiedBorder": "#268bd2", // Workbench: Activity Bar "activityBar.background": "#003847", 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 b7020f8e7c5..a29c8fb32f0 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -3,14 +3,12 @@ "tokenColors": [ { "settings": { - "background": "#FDF6E3", "foreground": "#657B83" } }, { "scope": ["meta.embedded", "source.groovy.embedded"], "settings": { - "background": "#FDF6E3", "foreground": "#657B83" } }, diff --git a/extensions/typescript-basics/cgmanifest.json b/extensions/typescript-basics/cgmanifest.json index 692891f15c2..6323be5b029 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": "ce3979047399920f77d79272b3af45b4d86006ac" + "commitHash": "477c1b17e273b64af13040c064c9ed62c8b32fba" } }, "license": "MIT", diff --git a/extensions/typescript-basics/package.json b/extensions/typescript-basics/package.json index 185a8a2bc71..6fb73d06a9d 100644 --- a/extensions/typescript-basics/package.json +++ b/extensions/typescript-basics/package.json @@ -79,11 +79,17 @@ } }, { - "scopeName": "documentation.injection", - "path": "./syntaxes/jsdoc.injection.tmLanguage.json", + "scopeName": "documentation.injection.ts", + "path": "./syntaxes/jsdoc.ts.injection.tmLanguage.json", "injectTo": [ "source.ts", - "source.tsx", + "source.tsx" + ] + }, + { + "scopeName": "documentation.injection.js.jsx", + "path": "./syntaxes/jsdoc.js.injection.tmLanguage.json", + "injectTo": [ "source.js", "source.js.jsx" ] @@ -98,36 +104,6 @@ "language": "typescriptreact", "path": "./snippets/typescript.json" } - ], - "jsonValidation": [ - { - "fileMatch": "tsconfig.json", - "url": "https://schemastore.azurewebsites.net/schemas/json/tsconfig.json" - }, - { - "fileMatch": "tsconfig.json", - "url": "./schemas/tsconfig.schema.json" - }, - { - "fileMatch": "tsconfig.*.json", - "url": "https://schemastore.azurewebsites.net/schemas/json/tsconfig.json" - }, - { - "fileMatch": "tsconfig-*.json", - "url": "./schemas/tsconfig.schema.json" - }, - { - "fileMatch": "tsconfig-*.json", - "url": "https://schemastore.azurewebsites.net/schemas/json/tsconfig.json" - }, - { - "fileMatch": "tsconfig.*.json", - "url": "./schemas/tsconfig.schema.json" - }, - { - "fileMatch": "typings.json", - "url": "https://schemastore.azurewebsites.net/schemas/json/typings.json" - } ] } } diff --git a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json index 20833396bac..ccdd30167e3 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/ce3979047399920f77d79272b3af45b4d86006ac", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/477c1b17e273b64af13040c064c9ed62c8b32fba", "name": "TypeScript", "scopeName": "source.ts", "patterns": [ @@ -423,7 +423,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.ts", - "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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -481,7 +481,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.ts", - "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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -865,7 +865,7 @@ } }, { - "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)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -1078,7 +1078,7 @@ }, "field-declaration": { "name": "meta.field.declaration.ts", - "begin": "(?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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -2056,6 +2056,9 @@ }, "end": "(?=;|$|^)", "patterns": [ + { + "include": "#single-line-comment-consuming-line-ending" + }, { "include": "#comment" }, @@ -2097,6 +2100,9 @@ }, "end": "(?)\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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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 +2698,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2725,7 +2731,7 @@ ] }, { - "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2779,13 +2785,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "end": "(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", "patterns": [ { "name": "meta.function-call.ts", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "end": "(?=\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", "patterns": [ { "include": "#support-function-call-identifiers" @@ -2803,6 +2809,10 @@ "name": "meta.function-call.ts punctuation.accessor.optional.ts", "match": "\\?\\." }, + { + "name": "meta.function-call.ts keyword.operator.definiteassignment.ts", + "match": "\\!" + }, { "include": "#type-arguments" }, @@ -2869,7 +2879,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2953,7 +2963,7 @@ } }, { - "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)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\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*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -3607,7 +3617,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*([_$[: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))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -4120,7 +4130,7 @@ }, "patterns": [ { - "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))))", + "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))", "captures": { "1": { "name": "storage.modifier.ts" @@ -4320,8 +4330,47 @@ ] }, "type-predicate-operator": { - "name": "keyword.operator.expression.is.ts", - "match": "(?)\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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -484,7 +484,7 @@ "patterns": [ { "name": "meta.var-single-variable.expr.tsx", - "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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -868,7 +868,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*([_$[: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)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -1081,7 +1081,7 @@ }, "field-declaration": { "name": "meta.field.declaration.tsx", - "begin": "(?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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -2059,6 +2059,9 @@ }, "end": "(?=;|$|^)", "patterns": [ + { + "include": "#single-line-comment-consuming-line-ending" + }, { "include": "#comment" }, @@ -2100,6 +2103,9 @@ }, "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*([_$[: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)))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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 +2701,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2728,7 +2734,7 @@ ] }, { - "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?\\s*(\\()(?=\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2782,13 +2788,13 @@ ] }, "function-call": { - "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", - "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "begin": "(?=(((([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "end": "(?<=\\))(?!(((([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))|(?<=[\\)]))\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", "patterns": [ { "name": "meta.function-call.tsx", "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", - "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", + "end": "(?=\\s*(?:(\\?\\.\\s*)|(\\!))?(<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?))*(?)*(?\\s*)?\\()", "patterns": [ { "include": "#support-function-call-identifiers" @@ -2806,6 +2812,10 @@ "name": "meta.function-call.tsx punctuation.accessor.optional.tsx", "match": "\\?\\." }, + { + "name": "meta.function-call.tsx keyword.operator.definiteassignment.tsx", + "match": "\\!" + }, { "include": "#type-arguments" }, @@ -2872,7 +2882,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))))", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2956,7 +2966,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*([_$[: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)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*((([\\{\\[]\\s*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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*((:\\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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -3558,7 +3568,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*([_$[: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))", + "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*)?$)|((\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})\\s*((:\\s*\\{?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\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" @@ -4071,7 +4081,7 @@ }, "patterns": [ { - "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))))", + "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*(?\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*)))|((\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])\\s*((:\\s*\\[?$)|((\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*)?=\\s*))))))))", "captures": { "1": { "name": "storage.modifier.tsx" @@ -4271,8 +4281,47 @@ ] }, "type-predicate-operator": { - "name": "keyword.operator.expression.is.tsx", - "match": "(?(); + private readonly _pending = new ResourceMap(); constructor( private readonly client: ITypeScriptServiceClient ) { } - public open(args: Proto.OpenRequestArgs) { + public open(resource: vscode.Uri, args: Proto.OpenRequestArgs) { if (this.supportsBatching) { - this.updatePending(args.file, pending => { - pending.set(args.file, new OpenOperation(args)); + this.updatePending(resource, pending => { + pending.set(resource, new OpenOperation(args)); }); } else { this.client.executeWithoutWaitingForResponse('open', args); } } - public close(filepath: string) { + public close(resource: vscode.Uri, filepath: string) { if (this.supportsBatching) { - this.updatePending(filepath, pending => { - pending.set(filepath, new CloseOperation(filepath)); + this.updatePending(resource, pending => { + pending.set(resource, new CloseOperation(filepath)); }); } else { const args: Proto.FileRequestArgs = { file: filepath }; @@ -89,14 +90,14 @@ class BufferSynchronizer { } } - public change(filepath: string, events: readonly vscode.TextDocumentContentChangeEvent[]) { + public change(resource: vscode.Uri, filepath: string, events: readonly vscode.TextDocumentContentChangeEvent[]) { if (!events.length) { return; } if (this.supportsBatching) { - this.updatePending(filepath, pending => { - pending.set(filepath, new ChangeOperation({ + this.updatePending(resource, pending => { + pending.set(resource, new ChangeOperation({ fileName: filepath, textChanges: events.map((change): Proto.CodeEdit => ({ newText: change.text, @@ -135,14 +136,14 @@ class BufferSynchronizer { const closedFiles: string[] = []; const openFiles: Proto.OpenRequestArgs[] = []; const changedFiles: Proto.FileCodeEdits[] = []; - for (const change of this._pending.values()) { + 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.client.execute('updateOpen', { changedFiles, closedFiles, openFiles }, nulToken, { nonRecoverable: true }); this._pending.clear(); } } @@ -151,8 +152,8 @@ class BufferSynchronizer { return this.client.apiVersion.gte(API.v340) && vscode.workspace.getConfiguration('typescript', null).get('useBatchedBufferSync', true); } - private updatePending(filepath: string, f: (pending: Map) => void): void { - if (this._pending.has(filepath)) { + private updatePending(resource: vscode.Uri, f: (pending: ResourceMap) => void): void { + if (this._pending.has(resource)) { // we saw this file before, make sure we flush before working with it again this.flush(); } @@ -175,6 +176,7 @@ class SyncedBuffer { const args: Proto.OpenRequestArgs = { file: this.filepath, fileContent: this.document.getText(), + projectRootPath: this.client.getWorkspaceRootForResource(this.document.uri), }; const scriptKind = mode2ScriptKind(this.document.languageId); @@ -182,10 +184,6 @@ class SyncedBuffer { args.scriptKindName = scriptKind; } - if (this.client.apiVersion.gte(API.v230)) { - args.projectRootPath = this.client.getWorkspaceRootForResource(this.document.uri); - } - if (this.client.apiVersion.gte(API.v240)) { const tsPluginsForDocument = this.client.pluginManager.plugins .filter(x => x.languages.indexOf(this.document.languageId) >= 0); @@ -195,7 +193,7 @@ class SyncedBuffer { } } - this.synchronizer.open(args); + this.synchronizer.open(this.resource, args); this.state = BufferState.Open; } @@ -221,7 +219,7 @@ class SyncedBuffer { } public close(): void { - this.synchronizer.close(this.filepath); + this.synchronizer.close(this.resource, this.filepath); this.state = BufferState.Closed; } @@ -230,7 +228,7 @@ class SyncedBuffer { console.error(`Unexpected buffer state: ${this.state}`); } - this.synchronizer.change(this.filepath, events); + this.synchronizer.change(this.resource, this.filepath, events); } } @@ -348,6 +346,14 @@ export default class BufferSyncSupport extends Disposable { vscode.workspace.onDidOpenTextDocument(this.openTextDocument, this, this._disposables); vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, this._disposables); vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, this._disposables); + vscode.window.onDidChangeVisibleTextEditors(e => { + for (const { document } of e) { + const syncedBuffer = this.syncedBuffers.get(document.uri); + if (syncedBuffer) { + this.requestDiagnostic(syncedBuffer); + } + } + }, this, this._disposables); vscode.workspace.textDocuments.forEach(this.openTextDocument, this); } @@ -355,6 +361,29 @@ export default class BufferSyncSupport extends Disposable { return this.syncedBuffers.has(resource); } + public ensureHasBuffer(resource: vscode.Uri): boolean { + if (this.syncedBuffers.has(resource)) { + return true; + } + + const existingDocument = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === resource.toString()); + if (existingDocument) { + return this.openTextDocument(existingDocument); + } + + return false; + } + + public toVsCodeResource(resource: vscode.Uri): vscode.Uri { + const filepath = this.client.normalizedPath(resource); + for (const buffer of this.syncedBuffers.allBuffers) { + if (buffer.filepath === filepath) { + return buffer.resource; + } + } + return resource; + } + public toResource(filePath: string): vscode.Uri { const buffer = this.syncedBuffers.getForPath(filePath); if (buffer) { @@ -369,24 +398,25 @@ export default class BufferSyncSupport extends Disposable { } } - public openTextDocument(document: vscode.TextDocument): void { + public openTextDocument(document: vscode.TextDocument): boolean { if (!this.modeIds.has(document.languageId)) { - return; + return false; } const resource = document.uri; const filepath = this.client.normalizedPath(resource); if (!filepath) { - return; + return false; } if (this.syncedBuffers.has(resource)) { - return; + return true; } const syncedBuffer = new SyncedBuffer(document, filepath, this.client, this.synchronizer); this.syncedBuffers.set(resource, syncedBuffer); syncedBuffer.open(); this.requestDiagnostic(syncedBuffer); + return true; } public closeResource(resource: vscode.Uri): void { diff --git a/extensions/typescript-language-features/src/features/completions.ts b/extensions/typescript-language-features/src/features/completions.ts index 0f5aa0560d9..dde8a7f2f68 100644 --- a/extensions/typescript-language-features/src/features/completions.ts +++ b/extensions/typescript-language-features/src/features/completions.ts @@ -301,6 +301,7 @@ interface CompletionConfiguration { readonly nameSuggestions: boolean; readonly pathSuggestions: boolean; readonly autoImportSuggestions: boolean; + readonly includeAutomaticOptionalChainCompletions: boolean; } namespace CompletionConfiguration { @@ -308,6 +309,7 @@ namespace CompletionConfiguration { export const nameSuggestions = 'suggest.names'; export const pathSuggestions = 'suggest.paths'; export const autoImportSuggestions = 'suggest.autoImports'; + export const includeAutomaticOptionalChainCompletions = 'suggest.includeAutomaticOptionalChainCompletions'; export function getConfigurationForResource( modeId: string, @@ -318,14 +320,15 @@ namespace CompletionConfiguration { useCodeSnippetsOnMethodSuggest: config.get(CompletionConfiguration.useCodeSnippetsOnMethodSuggest, false), pathSuggestions: config.get(CompletionConfiguration.pathSuggestions, true), autoImportSuggestions: config.get(CompletionConfiguration.autoImportSuggestions, true), - nameSuggestions: config.get(CompletionConfiguration.nameSuggestions, true) + nameSuggestions: config.get(CompletionConfiguration.nameSuggestions, true), + includeAutomaticOptionalChainCompletions: config.get(CompletionConfiguration.includeAutomaticOptionalChainCompletions, true), }; } } class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider { - public static readonly triggerCharacters = ['.', '"', '\'', '/', '@', '<']; + public static readonly triggerCharacters = ['.', '"', '\'', '`', '/', '@', '<']; constructor( private readonly client: ITypeScriptServiceClient, @@ -372,11 +375,12 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider await this.client.interruptGetErr(() => this.fileConfigurationManager.ensureConfigurationForDocument(document, token)); - const args: Proto.CompletionsRequestArgs = { + const args: Proto.CompletionsRequestArgs & { includeAutomaticOptionalChainCompletions?: boolean } = { ...typeConverters.Position.toFileLocationRequestArgs(file, position), includeExternalModuleExports: completionConfiguration.autoImportSuggestions, includeInsertTextCompletions: true, triggerCharacter: this.getTsTriggerCharacter(context), + includeAutomaticOptionalChainCompletions: completionConfiguration.includeAutomaticOptionalChainCompletions, }; let isNewIdentifierLocation = true; @@ -416,7 +420,7 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider isNewIdentifierLocation = response.body.isNewIdentifierLocation; isMemberCompletion = response.body.isMemberCompletion; if (isMemberCompletion) { - const dotMatch = line.text.slice(0, position.character).match(/\.\s*$/) || undefined; + const dotMatch = line.text.slice(0, position.character).match(/\??\.\s*$/) || undefined; if (dotMatch) { const range = new vscode.Range(position.translate({ characterDelta: -dotMatch[0].length }), position); const text = document.getText(range); diff --git a/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts b/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts index 0b1ddeca929..c0a222e47df 100644 --- a/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts +++ b/extensions/typescript-language-features/src/features/directiveCommentCompletions.ts @@ -6,8 +6,6 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { ITypeScriptServiceClient } from '../typescriptService'; -import API from '../utils/api'; -import { VersionDependentRegistration } from '../utils/dependentRegistration'; const localize = nls.loadMessageBundle(); @@ -36,7 +34,6 @@ const directives: Directive[] = [ ]; class DirectiveCommentCompletionProvider implements vscode.CompletionItemProvider { - public static readonly minVersion = API.v230; constructor( private readonly client: ITypeScriptServiceClient, @@ -71,9 +68,7 @@ export function register( selector: vscode.DocumentSelector, client: ITypeScriptServiceClient, ) { - return new VersionDependentRegistration(client, DirectiveCommentCompletionProvider.minVersion, () => { - return vscode.languages.registerCompletionItemProvider(selector, - new DirectiveCommentCompletionProvider(client), - '@'); - }); + return vscode.languages.registerCompletionItemProvider(selector, + new DirectiveCommentCompletionProvider(client), + '@'); } diff --git a/extensions/typescript-language-features/src/features/documentSymbol.ts b/extensions/typescript-language-features/src/features/documentSymbol.ts index 68635b346a6..abcd43238a1 100644 --- a/extensions/typescript-language-features/src/features/documentSymbol.ts +++ b/extensions/typescript-language-features/src/features/documentSymbol.ts @@ -25,6 +25,8 @@ const getSymbolKind = (kind: string): vscode.SymbolKind => { case PConst.Kind.localVariable: return vscode.SymbolKind.Variable; case PConst.Kind.function: return vscode.SymbolKind.Function; case PConst.Kind.localFunction: return vscode.SymbolKind.Function; + case PConst.Kind.constructSignature: return vscode.SymbolKind.Constructor; + case PConst.Kind.constructorImplementation: return vscode.SymbolKind.Constructor; } return vscode.SymbolKind.Variable; }; diff --git a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts index 2d0ac268693..ff9245b4a5e 100644 --- a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts @@ -167,7 +167,7 @@ export default class FileConfigurationManager extends Disposable { insertSpaceAfterTypeAssertion: config.get('insertSpaceAfterTypeAssertion'), placeOpenBraceOnNewLineForFunctions: config.get('placeOpenBraceOnNewLineForFunctions'), placeOpenBraceOnNewLineForControlBlocks: config.get('placeOpenBraceOnNewLineForControlBlocks'), - semicolons: config.get('semicolons'), + semicolons: config.get('semicolons'), }; return settings; diff --git a/extensions/typescript-language-features/src/features/folding.ts b/extensions/typescript-language-features/src/features/folding.ts index 0867c86fdc7..963c4fbb9e0 100644 --- a/extensions/typescript-language-features/src/features/folding.ts +++ b/extensions/typescript-language-features/src/features/folding.ts @@ -55,7 +55,7 @@ class TypeScriptFoldingProvider implements vscode.FoldingRangeProvider { const start = range.start.line; // workaround for #47240 - const end = (range.end.character > 0 && new Set(['}', ']']).has(document.getText(new vscode.Range(range.end.translate(0, -1), range.end)))) + const end = (range.end.character > 0 && ['}', ']'].includes(document.getText(new vscode.Range(range.end.translate(0, -1), range.end)))) ? Math.max(range.end.line - 1, range.start.line) : range.end.line; diff --git a/extensions/typescript-language-features/src/features/implementations.ts b/extensions/typescript-language-features/src/features/implementations.ts index 7b7dc130175..c7cdeeb755f 100644 --- a/extensions/typescript-language-features/src/features/implementations.ts +++ b/extensions/typescript-language-features/src/features/implementations.ts @@ -5,13 +5,9 @@ import * as vscode from 'vscode'; import { ITypeScriptServiceClient } from '../typescriptService'; -import API from '../utils/api'; -import { VersionDependentRegistration } from '../utils/dependentRegistration'; import DefinitionProviderBase from './definitionProviderBase'; class TypeScriptImplementationProvider extends DefinitionProviderBase implements vscode.ImplementationProvider { - public static readonly minVersion = API.v220; - public provideImplementation(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise { return this.getSymbolLocations('implementation', document, position, token); } @@ -21,8 +17,6 @@ export function register( selector: vscode.DocumentSelector, client: ITypeScriptServiceClient, ) { - return new VersionDependentRegistration(client, TypeScriptImplementationProvider.minVersion, () => { - return vscode.languages.registerImplementationProvider(selector, - new TypeScriptImplementationProvider(client)); - }); -} \ No newline at end of file + return vscode.languages.registerImplementationProvider(selector, + new TypeScriptImplementationProvider(client)); +} diff --git a/extensions/typescript-language-features/src/features/implementationsCodeLens.ts b/extensions/typescript-language-features/src/features/implementationsCodeLens.ts index c732ade5223..eccb5433e76 100644 --- a/extensions/typescript-language-features/src/features/implementationsCodeLens.ts +++ b/extensions/typescript-language-features/src/features/implementationsCodeLens.ts @@ -8,8 +8,7 @@ import * as nls from 'vscode-nls'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { ITypeScriptServiceClient } from '../typescriptService'; -import API from '../utils/api'; -import { ConfigurationDependentRegistration, VersionDependentRegistration } from '../utils/dependentRegistration'; +import { ConfigurationDependentRegistration } from '../utils/dependentRegistration'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens, getSymbolRange } from './baseCodeLensProvider'; import { CachedResponse } from '../tsServer/cachedResponse'; import * as typeConverters from '../utils/typeConverters'; @@ -17,7 +16,6 @@ import * as typeConverters from '../utils/typeConverters'; const localize = nls.loadMessageBundle(); export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider { - public static readonly minVersion = API.v220; public async resolveCodeLens( inputCodeLens: vscode.CodeLens, @@ -96,9 +94,8 @@ export function register( client: ITypeScriptServiceClient, cachedResponse: CachedResponse, ) { - return new VersionDependentRegistration(client, TypeScriptImplementationsCodeLensProvider.minVersion, () => - new ConfigurationDependentRegistration(modeId, 'implementationsCodeLens.enabled', () => { - return vscode.languages.registerCodeLensProvider(selector, - new TypeScriptImplementationsCodeLensProvider(client, cachedResponse)); - })); + return new ConfigurationDependentRegistration(modeId, 'implementationsCodeLens.enabled', () => { + return vscode.languages.registerCodeLensProvider(selector, + new TypeScriptImplementationsCodeLensProvider(client, cachedResponse)); + }); } diff --git a/extensions/typescript-language-features/src/features/jsDocCompletions.ts b/extensions/typescript-language-features/src/features/jsDocCompletions.ts index 36f7a751522..82aacc8927a 100644 --- a/extensions/typescript-language-features/src/features/jsDocCompletions.ts +++ b/extensions/typescript-language-features/src/features/jsDocCompletions.ts @@ -81,13 +81,13 @@ class JsDocCompletionProvider implements vscode.CompletionItemProvider { // or could be the opening of a comment const line = document.lineAt(position.line).text; const prefix = line.slice(0, position.character); - if (prefix.match(/^\s*$|\/\*\*\s*$|^\s*\/\*\*+\s*$/) === null) { + if (!/^\s*$|\/\*\*\s*$|^\s*\/\*\*+\s*$/.test(prefix)) { return false; } // And everything after is possibly a closing comment or more whitespace const suffix = line.slice(position.character); - return suffix.match(/^\s*\*+\//) !== null; + return /^\s*(\*+\/)?\s*$/.test(suffix); } } diff --git a/extensions/typescript-language-features/src/features/updatePathsOnRename.ts b/extensions/typescript-language-features/src/features/updatePathsOnRename.ts index 9333e6f75c0..8dad613683c 100644 --- a/extensions/typescript-language-features/src/features/updatePathsOnRename.ts +++ b/extensions/typescript-language-features/src/features/updatePathsOnRename.ts @@ -3,18 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as path from 'path'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; +import { Delayer } from '../utils/async'; import { nulToken } from '../utils/cancellation'; import { VersionDependentRegistration } from '../utils/dependentRegistration'; import { Disposable } from '../utils/dispose'; import * as fileSchemes from '../utils/fileSchemes'; -import { isTypeScriptDocument } from '../utils/languageModeIds'; +import { doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription'; import * as typeConverters from '../utils/typeConverters'; import FileConfigurationManager from './fileConfigurationManager'; @@ -22,15 +22,12 @@ const localize = nls.loadMessageBundle(); const updateImportsOnFileMoveName = 'updateImportsOnFileMove.enabled'; -function isDirectory(path: string): Promise { - return new Promise((resolve, reject) => { - fs.stat(path, (err, stat) => { - if (err) { - return reject(err); - } - return resolve(stat.isDirectory()); - }); - }); +async function isDirectory(resource: vscode.Uri): Promise { + try { + return (await vscode.workspace.fs.stat(resource)).type === vscode.FileType.Directory; + } catch { + return false; + } } const enum UpdateImportsOnFileMoveSetting { @@ -39,9 +36,20 @@ const enum UpdateImportsOnFileMoveSetting { Never = 'never', } +interface RenameAction { + readonly oldUri: vscode.Uri; + readonly newUri: vscode.Uri; + readonly newFilePath: string; + readonly oldFilePath: string; + readonly jsTsFileThatIsBeingMoved: vscode.Uri; +} + class UpdateImportsOnFileRenameHandler extends Disposable { public static readonly minVersion = API.v300; + private readonly _delayer = new Delayer(50); + private readonly _pendingRenames = new Set(); + public constructor( private readonly client: ITypeScriptServiceClient, private readonly fileConfigurationManager: FileConfigurationManager, @@ -49,64 +57,75 @@ class UpdateImportsOnFileRenameHandler extends Disposable { ) { super(); - this._register(vscode.workspace.onDidRenameFile(e => { - vscode.window.withProgress({ - location: vscode.ProgressLocation.Window, - title: localize('renameProgress.title', "Checking for update of JS/TS imports") - }, () => { - return this.doRename(e.oldUri, e.newUri); + this._register(vscode.workspace.onDidRenameFiles(async (e) => { + const [{ newUri, oldUri }] = e.renamed; + const newFilePath = this.client.toPath(newUri); + if (!newFilePath) { + return; + } + + const oldFilePath = this.client.toPath(oldUri); + if (!oldFilePath) { + return; + } + + const config = this.getConfiguration(newUri); + const setting = config.get(updateImportsOnFileMoveName); + if (setting === UpdateImportsOnFileMoveSetting.Never) { + return; + } + + // Try to get a js/ts file that is being moved + // For directory moves, this returns a js/ts file under the directory. + const jsTsFileThatIsBeingMoved = await this.getJsTsFileBeingMoved(newUri); + if (!jsTsFileThatIsBeingMoved || !this.client.toPath(jsTsFileThatIsBeingMoved)) { + return; + } + + this._pendingRenames.add({ oldUri, newUri, newFilePath, oldFilePath, jsTsFileThatIsBeingMoved }); + + this._delayer.trigger(() => { + vscode.window.withProgress({ + location: vscode.ProgressLocation.Window, + title: localize('renameProgress.title', "Checking for update of JS/TS imports") + }, () => this.flushRenames()); }); })); } - private async doRename( - oldResource: vscode.Uri, - newResource: vscode.Uri, - ): Promise { - // Try to get a js/ts file that is being moved - // For directory moves, this returns a js/ts file under the directory. - const jsTsFileThatIsBeingMoved = await this.getJsTsFileBeingMoved(newResource); - if (!jsTsFileThatIsBeingMoved || !this.client.toPath(jsTsFileThatIsBeingMoved)) { - return; - } + private async flushRenames(): Promise { + const renames = Array.from(this._pendingRenames); + this._pendingRenames.clear(); + for (const group of this.groupRenames(renames)) { + const edits = new vscode.WorkspaceEdit(); + const resourcesBeingRenamed: vscode.Uri[] = []; - const newFile = this.client.toPath(newResource); - if (!newFile) { - return; - } + for (const { oldUri, newUri, newFilePath, oldFilePath, jsTsFileThatIsBeingMoved } of group) { + const document = await vscode.workspace.openTextDocument(jsTsFileThatIsBeingMoved); - const oldFile = this.client.toPath(oldResource); - if (!oldFile) { - return; - } + // Make sure TS knows about file + this.client.bufferSyncSupport.closeResource(oldUri); + this.client.bufferSyncSupport.openTextDocument(document); - const document = await vscode.workspace.openTextDocument(jsTsFileThatIsBeingMoved); + if (await this.withEditsForFileRename(edits, document, oldFilePath, newFilePath)) { + resourcesBeingRenamed.push(newUri); + } + } - const config = this.getConfiguration(document); - const setting = config.get(updateImportsOnFileMoveName); - if (setting === UpdateImportsOnFileMoveSetting.Never) { - return; - } - - // Make sure TS knows about file - this.client.bufferSyncSupport.closeResource(oldResource); - this.client.bufferSyncSupport.openTextDocument(document); - - const edits = await this.getEditsForFileRename(document, oldFile, newFile); - if (!edits || !edits.size) { - return; - } - - if (await this.confirmActionWithUser(newResource, document)) { - await vscode.workspace.applyEdit(edits); + if (edits.size) { + if (await this.confirmActionWithUser(resourcesBeingRenamed)) { + await vscode.workspace.applyEdit(edits); + } + } } } - private async confirmActionWithUser( - newResource: vscode.Uri, - newDocument: vscode.TextDocument - ): Promise { - const config = this.getConfiguration(newDocument); + private async confirmActionWithUser(newResources: readonly vscode.Uri[]): Promise { + if (!newResources.length) { + return false; + } + + const config = this.getConfiguration(newResources[0]); const setting = config.get(updateImportsOnFileMoveName); switch (setting) { case UpdateImportsOnFileMoveSetting.Always: @@ -115,18 +134,19 @@ class UpdateImportsOnFileRenameHandler extends Disposable { return false; case UpdateImportsOnFileMoveSetting.Prompt: default: - return this.promptUser(newResource, newDocument); + return this.promptUser(newResources); } } - private getConfiguration(newDocument: vscode.TextDocument) { - return vscode.workspace.getConfiguration(isTypeScriptDocument(newDocument) ? 'typescript' : 'javascript', newDocument.uri); + private getConfiguration(resource: vscode.Uri) { + return vscode.workspace.getConfiguration(doesResourceLookLikeATypeScriptFile(resource) ? 'typescript' : 'javascript', resource); } - private async promptUser( - newResource: vscode.Uri, - newDocument: vscode.TextDocument - ): Promise { + private async promptUser(newResources: readonly vscode.Uri[]): Promise { + if (!newResources.length) { + return false; + } + const enum Choice { None = 0, Accept = 1, @@ -136,11 +156,14 @@ class UpdateImportsOnFileRenameHandler extends Disposable { } interface Item extends vscode.MessageItem { - choice: Choice; + readonly choice: Choice; } + const response = await vscode.window.showInformationMessage( - localize('prompt', "Update imports for moved file: '{0}'?", path.basename(newResource.fsPath)), { + newResources.length === 1 + ? localize('prompt', "Update imports for '{0}'?", path.basename(newResources[0].fsPath)) + : this.getConfirmMessage(localize('promptMoreThanOne', "Update imports for the following {0} files?", newResources.length), newResources), { modal: true, }, { title: localize('reject.title', "No"), @@ -172,7 +195,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable { } case Choice.Always: { - const config = this.getConfiguration(newDocument); + const config = this.getConfiguration(newResources[0]); config.update( updateImportsOnFileMoveName, UpdateImportsOnFileMoveSetting.Always, @@ -181,7 +204,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable { } case Choice.Never: { - const config = this.getConfiguration(newDocument); + const config = this.getConfiguration(newResources[0]); config.update( updateImportsOnFileMoveName, UpdateImportsOnFileMoveSetting.Never, @@ -198,7 +221,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable { return undefined; } - if (await isDirectory(resource.fsPath)) { + if (await isDirectory(resource)) { const files = await vscode.workspace.findFiles({ base: resource.fsPath, pattern: '**/*.{ts,tsx,js,jsx}', @@ -209,24 +232,60 @@ class UpdateImportsOnFileRenameHandler extends Disposable { return (await this._handles(resource)) ? resource : undefined; } - private async getEditsForFileRename( + private async withEditsForFileRename( + edits: vscode.WorkspaceEdit, document: vscode.TextDocument, - oldFile: string, - newFile: string, - ): Promise { + oldFilePath: string, + newFilePath: string, + ): Promise { const response = await this.client.interruptGetErr(() => { this.fileConfigurationManager.setGlobalConfigurationFromDocument(document, nulToken); const args: Proto.GetEditsForFileRenameRequestArgs = { - oldFilePath: oldFile, - newFilePath: newFile, + oldFilePath, + newFilePath, }; return this.client.execute('getEditsForFileRename', args, nulToken); }); - if (response.type !== 'response' || !response.body) { - return; + if (response.type !== 'response' || !response.body.length) { + return false; } - return typeConverters.WorkspaceEdit.fromFileCodeEdits(this.client, response.body); + typeConverters.WorkspaceEdit.withFileCodeEdits(edits, this.client, response.body); + return true; + } + + private groupRenames(renames: Iterable): Iterable> { + const groups = new Map>(); + + for (const rename of renames) { + // Group renames by type (js/ts) and by workspace. + const key = `${this.client.getWorkspaceRootForResource(rename.jsTsFileThatIsBeingMoved)}@@@${doesResourceLookLikeATypeScriptFile(rename.jsTsFileThatIsBeingMoved)}`; + if (!groups.has(key)) { + groups.set(key, new Set()); + } + groups.get(key)!.add(rename); + } + + return groups.values(); + } + + private getConfirmMessage(start: string, resourcesToConfirm: readonly vscode.Uri[]): string { + const MAX_CONFIRM_FILES = 10; + + const paths = [start]; + paths.push(''); + paths.push(...resourcesToConfirm.slice(0, MAX_CONFIRM_FILES).map(r => path.basename(r.fsPath))); + + if (resourcesToConfirm.length > MAX_CONFIRM_FILES) { + if (resourcesToConfirm.length - MAX_CONFIRM_FILES === 1) { + paths.push(localize('moreFile', "...1 additional file not shown")); + } else { + paths.push(localize('moreFiles', "...{0} additional files not shown", resourcesToConfirm.length - MAX_CONFIRM_FILES)); + } + } + + paths.push(''); + return paths.join('\n'); } } diff --git a/extensions/typescript-language-features/src/features/workspaceSymbols.ts b/extensions/typescript-language-features/src/features/workspaceSymbols.ts index a8aefa64db7..857969be008 100644 --- a/extensions/typescript-language-features/src/features/workspaceSymbols.ts +++ b/extensions/typescript-language-features/src/features/workspaceSymbols.ts @@ -6,6 +6,8 @@ import * as vscode from 'vscode'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; +import * as fileSchemes from '../utils/fileSchemes'; +import { doesResourceLookLikeAJavaScriptFile, doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription'; import * as typeConverters from '../utils/typeConverters'; function getSymbolKind(item: Proto.NavtoItem): vscode.SymbolKind { @@ -35,7 +37,7 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide return []; } - const filepath = this.client.toOpenedFilePath(document); + const filepath = await this.toOpenedFiledPath(document); if (!filepath) { return []; } @@ -62,10 +64,25 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide return result; } + private async toOpenedFiledPath(document: vscode.TextDocument) { + if (document.uri.scheme === fileSchemes.git) { + try { + const path = vscode.Uri.file(JSON.parse(document.uri.query)?.path); + if (doesResourceLookLikeATypeScriptFile(path) || doesResourceLookLikeAJavaScriptFile(path)) { + const document = await vscode.workspace.openTextDocument(path); + return this.client.toOpenedFilePath(document); + } + } catch { + // noop + } + } + return this.client.toOpenedFilePath(document); + } + private static getLabel(item: Proto.NavtoItem) { - let label = item.name; + const label = item.name; if (item.kind === 'method' || item.kind === 'function') { - label += '()'; + return label + '()'; } return label; } @@ -75,17 +92,16 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide // general questions so we check the active editor. If this // doesn't match we take the first TS document. - const editor = vscode.window.activeTextEditor; - if (editor) { - const document = editor.document; - if (document && this.modeIds.indexOf(document.languageId) >= 0) { - return document; + const activeDocument = vscode.window.activeTextEditor?.document; + if (activeDocument) { + if (this.modeIds.includes(activeDocument.languageId)) { + return activeDocument; } } const documents = vscode.workspace.textDocuments; for (const document of documents) { - if (this.modeIds.indexOf(document.languageId) >= 0) { + if (this.modeIds.includes(document.languageId)) { return document; } } @@ -98,4 +114,4 @@ export function register( modeIds: string[], ) { return vscode.languages.registerWorkspaceSymbolProvider(new TypeScriptWorkspaceSymbolProvider(client, modeIds)); -} \ No newline at end of file +} diff --git a/extensions/typescript-language-features/src/test/completions.test.ts b/extensions/typescript-language-features/src/test/completions.test.ts index 4d1d79dccdb..f35d0cae73c 100644 --- a/extensions/typescript-language-features/src/test/completions.test.ts +++ b/extensions/typescript-language-features/src/test/completions.test.ts @@ -7,6 +7,8 @@ import * as assert from 'assert'; import 'mocha'; import * as vscode from 'vscode'; import { disposeAll } from '../utils/dispose'; +import { createTestEditor, joinLines, wait } from './testUtils'; +import { acceptFirstSuggestion, typeCommitCharacter } from './suggestTestHelpers'; const testDocumentUri = vscode.Uri.parse('untitled:test.ts'); @@ -292,71 +294,3 @@ suite('TypeScript Completions', () => { }); }); -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[], options?: { useLineRange?: boolean }) { - const didChangeDocument = onChangedDocument(uri, _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 - // Make sure we have time to resolve the suggestion because `acceptSelectedSuggestion` doesn't - await wait(40); - await vscode.commands.executeCommand('acceptSelectedSuggestion'); - return await didChangeDocument; -} - -async function typeCommitCharacter(uri: vscode.Uri, character: string, _disposables: vscode.Disposable[]) { - const didChangeDocument = onChangedDocument(uri, _disposables); - const didSuggest = onDidSuggest(_disposables); - await vscode.commands.executeCommand('editor.action.triggerSuggest'); - await didSuggest; - await vscode.commands.executeCommand('type', { text: character }); - return await didChangeDocument; -} - -function onChangedDocument(documentUri: vscode.Uri, disposables: vscode.Disposable[]) { - return new Promise(resolve => vscode.workspace.onDidChangeTextDocument(e => { - if (e.document.uri.toString() === documentUri.toString()) { - resolve(e.document); - } - }, undefined, disposables)); -} - -async function createTestEditor(uri: vscode.Uri, ...lines: string[]) { - const document = await vscode.workspace.openTextDocument(uri); - await vscode.window.showTextDocument(document); - const activeEditor = vscode.window.activeTextEditor; - if (!activeEditor) { - throw new Error('no active editor'); - } - - await activeEditor.insertSnippet(new vscode.SnippetString(joinLines(...lines)), new vscode.Range(0, 0, 1000, 0)); -} - -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 = options && options.useLineRange - ? new vscode.Range(new vscode.Position(position.line, 0), position) - : doc.getWordRangeAtPosition(position); - return [{ - label: '🦄', - insertText: doc.getText(range), - filterText: doc.getText(range), - preselect: true, - sortText: '\0', - range: range - }]; - } - async resolveCompletionItem(item: vscode.CompletionItem) { - await vscode.commands.executeCommand('selectNextSuggestion'); - resolve(); - return item; - } - }))); -} \ No newline at end of file diff --git a/extensions/typescript-language-features/src/test/jsDocCompletions.test.ts b/extensions/typescript-language-features/src/test/jsDocCompletions.test.ts new file mode 100644 index 00000000000..ffd836f5ab3 --- /dev/null +++ b/extensions/typescript-language-features/src/test/jsDocCompletions.test.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import 'mocha'; +import * as vscode from 'vscode'; +import { disposeAll } from '../utils/dispose'; +import { createTestEditor, joinLines, wait } from './testUtils'; +import { acceptFirstSuggestion } from './suggestTestHelpers'; + +const testDocumentUri = vscode.Uri.parse('untitled:test.ts'); + +suite('JSDoc Completions', () => { + const _disposables: vscode.Disposable[] = []; + + setup(async () => { + await wait(100); + }); + + teardown(async () => { + disposeAll(_disposables); + }); + + test('Should complete jsdoc inside single line comment', async () => { + await createTestEditor(testDocumentUri, + `/**$0 */`, + `function abcdef(x, y) { }`, + ); + + const document = await acceptFirstSuggestion(testDocumentUri, _disposables, { useLineRange: true}); + assert.strictEqual( + document.getText(), + joinLines( + `/**`, + ` *`, + ` * @param {*} x `, + ` * @param {*} y `, + ` */`, + `function abcdef(x, y) { }`, + )); + }); +}); diff --git a/extensions/typescript-language-features/src/test/suggestTestHelpers.ts b/extensions/typescript-language-features/src/test/suggestTestHelpers.ts new file mode 100644 index 00000000000..7c64a26ad5c --- /dev/null +++ b/extensions/typescript-language-features/src/test/suggestTestHelpers.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 'mocha'; +import * as vscode from 'vscode'; +import { wait } from './testUtils'; + +export async function acceptFirstSuggestion(uri: vscode.Uri, _disposables: vscode.Disposable[], options?: { useLineRange?: boolean }) { + const didChangeDocument = onChangedDocument(uri, _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 + // Make sure we have time to resolve the suggestion because `acceptSelectedSuggestion` doesn't + await wait(40); + await vscode.commands.executeCommand('acceptSelectedSuggestion'); + return await didChangeDocument; +} + +export async function typeCommitCharacter(uri: vscode.Uri, character: string, _disposables: vscode.Disposable[]) { + const didChangeDocument = onChangedDocument(uri, _disposables); + const didSuggest = onDidSuggest(_disposables); + await vscode.commands.executeCommand('editor.action.triggerSuggest'); + await didSuggest; + await vscode.commands.executeCommand('type', { text: character }); + return await didChangeDocument; +} + +export function onChangedDocument(documentUri: vscode.Uri, disposables: vscode.Disposable[]) { + return new Promise(resolve => vscode.workspace.onDidChangeTextDocument(e => { + if (e.document.uri.toString() === documentUri.toString()) { + resolve(e.document); + } + }, undefined, disposables)); +} + + +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 = options && options.useLineRange + ? new vscode.Range(new vscode.Position(position.line, 0), position) + : doc.getWordRangeAtPosition(position.translate({ characterDelta: -1 })); + return [{ + label: '🦄', + insertText: doc.getText(range), + filterText: doc.getText(range), + preselect: true, + sortText: 'a', + range: range + }]; + } + async resolveCompletionItem(item: vscode.CompletionItem) { + await vscode.commands.executeCommand('selectNextSuggestion'); + resolve(); + return item; + } + }))); +} diff --git a/extensions/typescript-language-features/src/test/testUtils.ts b/extensions/typescript-language-features/src/test/testUtils.ts index d8efdc3f9c4..753814a99bd 100644 --- a/extensions/typescript-language-features/src/test/testUtils.ts +++ b/extensions/typescript-language-features/src/test/testUtils.ts @@ -65,4 +65,19 @@ export function withRandomFileEditor( }); }); }); -} \ No newline at end of file +} + +export const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + +export const joinLines = (...args: string[]) => args.join('\n'); + +export async function createTestEditor(uri: vscode.Uri, ...lines: string[]) { + const document = await vscode.workspace.openTextDocument(uri); + await vscode.window.showTextDocument(document); + const activeEditor = vscode.window.activeTextEditor; + if (!activeEditor) { + throw new Error('no active editor'); + } + + await activeEditor.insertSnippet(new vscode.SnippetString(joinLines(...lines)), new vscode.Range(0, 0, 1000, 0)); +} diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index f10b02abf8e..e4f9acd1975 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -59,6 +59,10 @@ export interface ITypeScriptServer { dispose(): void; } +export interface TsServerDelegate { + onFatalError(command: string): void; +} + export interface TsServerProcess { readonly stdout: stream.Readable; write(serverRequest: Proto.Request): void; @@ -305,6 +309,7 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ public constructor( private readonly syntaxServer: ITypeScriptServer, private readonly semanticServer: ITypeScriptServer, + private readonly _delegate: TsServerDelegate, ) { super(); @@ -362,14 +367,18 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ } else if (SyntaxRoutingTsServer.sharedCommands.has(command)) { // Dispatch to both server but only return from syntax one + const enum RequestState { Unresolved, Resolved, Errored } + let syntaxRequestState = RequestState.Unresolved; + let semanticRequestState = RequestState.Unresolved; + // 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) { + if (syntaxRequestState !== RequestState.Unresolved && semanticRequestState === RequestState.Unresolved + || syntaxRequestState === RequestState.Unresolved && semanticRequestState !== RequestState.Unresolved + ) { // Don't cancel. // One of the servers completed this request so we don't want to leave the other // in a different state @@ -382,11 +391,41 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ const semanticRequest = this.semanticServer.executeImpl(command, args, { ...executeInfo, token }); if (semanticRequest) { - semanticRequest.finally(() => { hasCompletedSemantic = true; }); + semanticRequest + .then(result => { + semanticRequestState = RequestState.Resolved; + if (syntaxRequestState === RequestState.Errored) { + // We've gone out of sync + this._delegate.onFatalError(command); + } + return result; + }, err => { + semanticRequestState = RequestState.Errored; + if (syntaxRequestState === RequestState.Resolved) { + // We've gone out of sync + this._delegate.onFatalError(command); + } + throw err; + }); } const syntaxRequest = this.syntaxServer.executeImpl(command, args, { ...executeInfo, token }); if (syntaxRequest) { - syntaxRequest.finally(() => { hasCompletedSyntax = true; }); + syntaxRequest + .then(result => { + syntaxRequestState = RequestState.Resolved; + if (semanticRequestState === RequestState.Errored) { + // We've gone out of sync + this._delegate.onFatalError(command); + } + return result; + }, err => { + syntaxRequestState = RequestState.Errored; + if (semanticRequestState === RequestState.Resolved) { + // We've gone out of sync + this._delegate.onFatalError(command); + } + throw err; + }); } return syntaxRequest; } else { diff --git a/extensions/typescript-language-features/src/tsServer/serverError.ts b/extensions/typescript-language-features/src/tsServer/serverError.ts index b51ca545bff..7f58aa6b0f5 100644 --- a/extensions/typescript-language-features/src/tsServer/serverError.ts +++ b/extensions/typescript-language-features/src/tsServer/serverError.ts @@ -14,7 +14,7 @@ export class TypeScriptServerError extends Error { response: Proto.Response ): TypeScriptServerError { const parsedResult = TypeScriptServerError.parseErrorText(version, response); - return new TypeScriptServerError(serverId, version, response, parsedResult ? parsedResult.message : undefined, parsedResult ? parsedResult.stack : undefined); + return new TypeScriptServerError(serverId, version, response, parsedResult?.message, parsedResult?.stack); } private constructor( @@ -24,7 +24,7 @@ export class TypeScriptServerError extends Error { public readonly serverMessage: string | undefined, public readonly serverStack: string | undefined ) { - super(`<${serverId}> TypeScript Server Error (${version.versionString})\n${serverMessage}\n${serverStack}`); + super(`<${serverId}> TypeScript Server Error (${version.displayName})\n${serverMessage}\n${serverStack}`); } public get serverErrorText() { return this.response.message; } diff --git a/extensions/typescript-language-features/src/tsServer/spawner.ts b/extensions/typescript-language-features/src/tsServer/spawner.ts index de55136d020..171f204703e 100644 --- a/extensions/typescript-language-features/src/tsServer/spawner.ts +++ b/extensions/typescript-language-features/src/tsServer/spawner.ts @@ -18,7 +18,7 @@ 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'; +import { ITypeScriptServer, PipeRequestCanceller, ProcessBasedTsServer, SyntaxRoutingTsServer, TsServerProcess, TsServerDelegate } from './server'; type ServerKind = 'main' | 'syntax' | 'semantic'; @@ -35,12 +35,13 @@ export class TypeScriptServerSpawner { public spawn( version: TypeScriptVersion, configuration: TypeScriptServiceConfiguration, - pluginManager: PluginManager + pluginManager: PluginManager, + delegate: TsServerDelegate, ): 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 new SyntaxRoutingTsServer(syntaxServer, semanticServer, delegate); } return this.spawnTsServer('main', version, configuration, pluginManager); @@ -63,16 +64,16 @@ export class TypeScriptServerSpawner { const { args, cancellationPipeName, tsServerLogFile } = this.getTsServerArgs(kind, configuration, version, apiVersion, pluginManager); - if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { + if (TypeScriptServerSpawner.isLoggingEnabled(configuration)) { if (tsServerLogFile) { - this._logger.info(`<${kind}> Log file: ${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)); + const childProcess = electron.fork(version.tsServerPath, args, this.getForkOptions(kind, configuration)); this._logger.info(`<${kind}> Starting...`); return new ProcessBasedTsServer( @@ -85,10 +86,13 @@ export class TypeScriptServerSpawner { this._tracer); } - private getForkOptions(kind: ServerKind) { + private getForkOptions(kind: ServerKind, configuration: TypeScriptServiceConfiguration) { const debugPort = TypeScriptServerSpawner.getDebugPort(kind); const tsServerForkOptions: electron.ForkOptions = { - execArgv: debugPort ? [`--inspect=${debugPort}`] : [], + execArgv: [ + ...(debugPort ? [`--inspect=${debugPort}`] : []), + ...(configuration.maxTsServerMemory ? [`--max-old-space-size=${configuration.maxTsServerMemory}`] : []) + ] }; return tsServerForkOptions; } @@ -99,9 +103,8 @@ export class TypeScriptServerSpawner { currentVersion: TypeScriptVersion, apiVersion: API, pluginManager: PluginManager, - ): { args: string[], cancellationPipeName: string | undefined, tsServerLogFile: string | undefined } { + ): { args: string[], cancellationPipeName: string, tsServerLogFile: string | undefined } { const args: string[] = []; - let cancellationPipeName: string | undefined; let tsServerLogFile: string | undefined; if (kind === 'syntax') { @@ -122,12 +125,10 @@ export class TypeScriptServerSpawner { args.push('--enableTelemetry'); } - if (apiVersion.gte(API.v222)) { - cancellationPipeName = electron.getTempFile('tscancellation'); - args.push('--cancellationPipeName', cancellationPipeName + '*'); - } + const cancellationPipeName = electron.getTempFile('tscancellation'); + args.push('--cancellationPipeName', cancellationPipeName + '*'); - if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { + if (TypeScriptServerSpawner.isLoggingEnabled(configuration)) { const logDir = this._logDirectoryProvider.getNewLogDirectory(); if (logDir) { tsServerLogFile = path.join(logDir, `tsserver.log`); @@ -136,29 +137,25 @@ export class TypeScriptServerSpawner { } } - if (apiVersion.gte(API.v230)) { - const pluginPaths = this._pluginPathsProvider.getPluginPaths(); + const pluginPaths = this._pluginPathsProvider.getPluginPaths(); - if (pluginManager.plugins.length) { - args.push('--globalPlugins', pluginManager.plugins.map(x => x.name).join(',')); + 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); - } + 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 (pluginPaths.length !== 0) { + args.push('--pluginProbeLocations', pluginPaths.join(',')); + } + + if (configuration.npmLocation) { + args.push('--npmLocation', `"${configuration.npmLocation}"`); } if (apiVersion.gte(API.v260)) { @@ -191,9 +188,8 @@ export class TypeScriptServerSpawner { return undefined; } - private static isLoggingEnabled(apiVersion: API, configuration: TypeScriptServiceConfiguration) { - return apiVersion.gte(API.v222) && - configuration.tsServerLogLevel !== TsServerLogLevel.Off; + private static isLoggingEnabled(configuration: TypeScriptServiceConfiguration) { + return configuration.tsServerLogLevel !== TsServerLogLevel.Off; } private static getTsLocale(configuration: TypeScriptServiceConfiguration): string { diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index 2571d395a5f..7e0d159132c 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -15,7 +15,6 @@ import LanguageProvider from './languageProvider'; import * as Proto from './protocol'; import * as PConst from './protocol.const'; import TypeScriptServiceClient from './typescriptServiceClient'; -import API from './utils/api'; import { CommandManager } from './utils/commandManager'; import { Disposable } from './utils/dispose'; import { DiagnosticLanguage, LanguageDescription } from './utils/languageDescription'; @@ -105,10 +104,6 @@ export default class TypeScriptServiceClientHost extends Disposable { this.client.ensureServiceStarted(); this.client.onReady(() => { - if (this.client.apiVersion.lt(API.v230)) { - return; - } - const languages = new Set(); for (const plugin of pluginManager.plugins) { for (const language of plugin.languages) { diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index 3fd9b4fa32a..10c48afcae9 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -126,13 +126,13 @@ interface StandardTsServerRequests { 'selectionRange': [Proto.SelectionRangeRequestArgs, Proto.SelectionRangeResponse]; 'signatureHelp': [Proto.SignatureHelpRequestArgs, Proto.SignatureHelpResponse]; 'typeDefinition': [Proto.FileLocationRequestArgs, Proto.TypeDefinitionResponse]; + 'updateOpen': [Proto.UpdateOpenRequestArgs, Proto.Response]; } interface NoResponseTsServerRequests { 'open': [Proto.OpenRequestArgs, null]; - 'close': [Proto.FileRequestArgs]; + 'close': [Proto.FileRequestArgs, null]; 'change': [Proto.ChangeRequestArgs, null]; - 'updateOpen': [Proto.UpdateOpenRequestArgs, null]; 'compilerOptionsForInferredProjects': [Proto.SetCompilerOptionsForInferredProjectsArgs, null]; 'reloadProjects': [null, null]; 'configurePlugin': [Proto.ConfigurePluginRequest, Proto.ConfigurePluginResponse]; @@ -145,7 +145,8 @@ interface AsyncTsServerRequests { export type TypeScriptRequests = StandardTsServerRequests & NoResponseTsServerRequests & AsyncTsServerRequests; export type ExecConfig = { - lowPriority?: boolean; + readonly lowPriority?: boolean; + readonly nonRecoverable?: boolean; }; export interface ITypeScriptServiceClient { diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index d8f8921d7db..e1a2b10270f 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -91,7 +91,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType private lastStart: number; private numberRestarts: number; private isRestarting: boolean = false; - private loadingIndicator = new ServerInitializingIndicator(); + private readonly loadingIndicator = new ServerInitializingIndicator(); public readonly telemetryReporter: TelemetryReporter; @@ -159,7 +159,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType return this.serverState.tsserverVersion; } } - return this.apiVersion.versionString; + return this.apiVersion.version; })); this.typescriptServerSpawner = new TypeScriptServerSpawner(this.versionProvider, this.logDirectoryProvider, this.pluginPathsProvider, this.logger, this.telemetryReporter, this.tracer); @@ -288,7 +288,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType const apiVersion = this.versionPicker.currentVersion.apiVersion || API.defaultVersion; this.onDidChangeTypeScriptVersion(currentVersion); let mytoken = ++this.token; - const handle = this.typescriptServerSpawner.spawn(currentVersion, this.configuration, this.pluginManager); + const handle = this.typescriptServerSpawner.spawn(currentVersion, this.configuration, this.pluginManager, { + onFatalError: (command) => this.fatalError(command), + }); this.serverState = new ServerState.Running(handle, apiVersion, undefined, true); this.lastStart = Date.now(); @@ -297,11 +299,13 @@ export default class TypeScriptServiceClient extends Disposable implements IType "${include}": [ "${TypeScriptCommonProperties}" ], - "localTypeScriptVersion": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "localTypeScriptVersion": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "typeScriptVersionSource": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.logTelemetry('tsserver.spawned', { - localTypeScriptVersion: this.versionProvider.localVersion ? this.versionProvider.localVersion.versionString : '', + localTypeScriptVersion: this.versionProvider.localVersion ? this.versionProvider.localVersion.displayName : '', + typeScriptVersionSource: currentVersion.source, }); handle.onError((err: Error) => { @@ -388,14 +392,6 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public async openTsServerLogFile(): Promise { - if (this.apiVersion.lt(API.v222)) { - vscode.window.showErrorMessage( - localize( - 'typescript.openTsServerLog.notSupported', - 'TS Server logging requires TS 2.2.2+')); - return false; - } - if (this._configuration.tsServerLogLevel === TsServerLogLevel.Off) { vscode.window.showErrorMessage( localize( @@ -515,7 +511,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType } */ this.logTelemetry('serviceExited'); - } else if (diff < 60 * 1000 /* 1 Minutes */) { + } else if (diff < 60 * 1000 * 5 /* 5 Minutes */) { this.lastStart = Date.now(); prompt = vscode.window.showWarningMessage( localize('serverDied', 'The TypeScript language service died unexpectedly 5 times in the last 5 Minutes.'), @@ -543,7 +539,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType if (resource.scheme === fileSchemes.walkThroughSnippet || resource.scheme === fileSchemes.untitled) { const dirName = path.dirname(resource.path); const fileName = this.inMemoryResourcePrefix + path.basename(resource.path); - return resource.with({ path: path.posix.join(dirName, fileName) }).toString(true); + return resource.with({ path: path.posix.join(dirName, fileName), query: '' }).toString(true); } if (resource.scheme !== fileSchemes.file) { @@ -564,7 +560,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public toOpenedFilePath(document: vscode.TextDocument): string | undefined { - if (!this.bufferSyncSupport.handles(document.uri)) { + if (!this.bufferSyncSupport.ensureHasBuffer(document.uri)) { console.error(`Unexpected resource ${document.uri}`); return undefined; } @@ -583,10 +579,12 @@ export default class TypeScriptServiceClient extends Disposable implements IType const dirName = path.dirname(resource.path); const fileName = path.basename(resource.path); if (fileName.startsWith(this.inMemoryResourcePrefix)) { - resource = resource.with({ path: path.posix.join(dirName, fileName.slice(this.inMemoryResourcePrefix.length)) }); + resource = resource.with({ + path: path.posix.join(dirName, fileName.slice(this.inMemoryResourcePrefix.length)) + }); } } - return resource; + return this.bufferSyncSupport.toVsCodeResource(resource); } return this.bufferSyncSupport.toResource(filepath); @@ -611,12 +609,18 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public execute(command: keyof TypeScriptRequests, args: any, token: vscode.CancellationToken, config?: ExecConfig): Promise> { - return this.executeImpl(command, args, { + const execution = this.executeImpl(command, args, { isAsync: false, token, expectsResult: true, - lowPriority: config ? config.lowPriority : undefined + lowPriority: config?.lowPriority }); + + if (config?.nonRecoverable) { + execution.catch(() => this.fatalError(command)); + } + + return execution; } public executeWithoutWaitingForResponse(command: keyof TypeScriptRequests, args: any): void { @@ -647,6 +651,24 @@ export default class TypeScriptServiceClient extends Disposable implements IType return this.bufferSyncSupport.interuptGetErr(f); } + private fatalError(command: string): void { + /* __GDPR__ + "fatalError" : { + "${include}": [ + "${TypeScriptCommonProperties}", + "command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + ] + } + */ + this.logTelemetry('fatalError', { command }); + console.error(`A non-recoverable error occured while executing tsserver command: ${command}`); + + if (this.serverState.type === ServerState.Type.Running) { + this.info('Killing TS Server'); + this.serverState.server.kill(); + } + } + private dispatchEvent(event: Proto.Event) { switch (event.event) { case 'syntaxDiag': @@ -689,7 +711,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType } case 'projectsUpdatedInBackground': const body = (event as Proto.ProjectsUpdatedInBackgroundEvent).body; - const resources = body.openFiles.map(vscode.Uri.file); + const resources = body.openFiles.map(file => this.toResource(file)); this.bufferSyncSupport.getErr(resources); break; diff --git a/extensions/typescript-language-features/src/utils/api.ts b/extensions/typescript-language-features/src/utils/api.ts index ab3c0673ac8..c30bee16c7e 100644 --- a/extensions/typescript-language-features/src/utils/api.ts +++ b/extensions/typescript-language-features/src/utils/api.ts @@ -5,6 +5,7 @@ import * as semver from 'semver'; import * as nls from 'vscode-nls'; + const localize = nls.loadMessageBundle(); export default class API { @@ -13,10 +14,6 @@ export default class API { } public static readonly defaultVersion = API.fromSimpleString('1.0.0'); - public static readonly v220 = API.fromSimpleString('2.2.0'); - public static readonly v222 = API.fromSimpleString('2.2.2'); - public static readonly v230 = API.fromSimpleString('2.3.0'); - public static readonly v234 = API.fromSimpleString('2.3.4'); public static readonly v240 = API.fromSimpleString('2.4.0'); public static readonly v250 = API.fromSimpleString('2.5.0'); public static readonly v260 = API.fromSimpleString('2.6.0'); @@ -35,7 +32,6 @@ export default class API { public static readonly v345 = API.fromSimpleString('3.4.5'); public static readonly v350 = API.fromSimpleString('3.5.0'); - public static fromVersionString(versionString: string): API { let version = semver.valid(versionString); if (!version) { @@ -51,8 +47,8 @@ export default class API { } private constructor( - public readonly versionString: string, - private readonly version: string + public readonly displayName: string, + public readonly version: string ) { } public gte(other: API): boolean { diff --git a/extensions/typescript-language-features/src/utils/configuration.ts b/extensions/typescript-language-features/src/utils/configuration.ts index f0e602e810a..54c3a19b001 100644 --- a/extensions/typescript-language-features/src/utils/configuration.ts +++ b/extensions/typescript-language-features/src/utils/configuration.ts @@ -55,6 +55,7 @@ export class TypeScriptServiceConfiguration { public readonly experimentalDecorators: boolean; public readonly disableAutomaticTypeAcquisition: boolean; public readonly useSeparateSyntaxServer: boolean; + public readonly maxTsServerMemory: number; public static loadFromWorkspace(): TypeScriptServiceConfiguration { return new TypeScriptServiceConfiguration(); @@ -73,6 +74,7 @@ export class TypeScriptServiceConfiguration { this.experimentalDecorators = TypeScriptServiceConfiguration.readExperimentalDecorators(configuration); this.disableAutomaticTypeAcquisition = TypeScriptServiceConfiguration.readDisableAutomaticTypeAcquisition(configuration); this.useSeparateSyntaxServer = TypeScriptServiceConfiguration.readUseSeparateSyntaxServer(configuration); + this.maxTsServerMemory = TypeScriptServiceConfiguration.readMaxTsServerMemory(configuration); } public isEqualTo(other: TypeScriptServiceConfiguration): boolean { @@ -85,7 +87,8 @@ export class TypeScriptServiceConfiguration { && this.experimentalDecorators === other.experimentalDecorators && this.disableAutomaticTypeAcquisition === other.disableAutomaticTypeAcquisition && arrays.equals(this.tsServerPluginPaths, other.tsServerPluginPaths) - && this.useSeparateSyntaxServer === other.useSeparateSyntaxServer; + && this.useSeparateSyntaxServer === other.useSeparateSyntaxServer + && this.maxTsServerMemory === other.maxTsServerMemory; } private static fixPathPrefixes(inspectValue: string): string { @@ -146,4 +149,14 @@ export class TypeScriptServiceConfiguration { private static readUseSeparateSyntaxServer(configuration: vscode.WorkspaceConfiguration): boolean { return configuration.get('typescript.tsserver.useSeparateSyntaxServer', true); } + + private static readMaxTsServerMemory(configuration: vscode.WorkspaceConfiguration): number { + const defaultMaxMemory = 3072; + const minimumMaxMemory = 128; + const memoryInMB = configuration.get('typescript.tsserver.maxTsServerMemory', defaultMaxMemory); + if (!Number.isSafeInteger(memoryInMB)) { + return defaultMaxMemory; + } + return Math.max(memoryInMB, minimumMaxMemory); + } } diff --git a/extensions/typescript-language-features/src/utils/fileSchemes.ts b/extensions/typescript-language-features/src/utils/fileSchemes.ts index 285ea43f331..6efcfab4d3b 100644 --- a/extensions/typescript-language-features/src/utils/fileSchemes.ts +++ b/extensions/typescript-language-features/src/utils/fileSchemes.ts @@ -4,9 +4,8 @@ *--------------------------------------------------------------------------------------------*/ export const file = 'file'; - export const untitled = 'untitled'; - +export const git = 'git'; export const walkThroughSnippet = 'walkThroughSnippet'; export const supportedSchemes = [ @@ -17,4 +16,4 @@ export const supportedSchemes = [ export function isSupportedScheme(scheme: string): boolean { return supportedSchemes.indexOf(scheme) >= 0; -} \ No newline at end of file +} diff --git a/extensions/typescript-language-features/src/utils/languageDescription.ts b/extensions/typescript-language-features/src/utils/languageDescription.ts index f6b066bd400..686590091e5 100644 --- a/extensions/typescript-language-features/src/utils/languageDescription.ts +++ b/extensions/typescript-language-features/src/utils/languageDescription.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { basename } from 'path'; +import * as vscode from 'vscode'; import * as languageModeIds from './languageModeIds'; export const enum DiagnosticLanguage { @@ -48,3 +49,11 @@ export function isTsConfigFileName(fileName: string): boolean { export function isJsConfigOrTsConfigFileName(fileName: string): boolean { return /^[jt]sconfig\.(.+\.)?json$/i.test(basename(fileName)); } + +export function doesResourceLookLikeATypeScriptFile(resource: vscode.Uri): boolean { + return /\.tsx?$/i.test(resource.fsPath); +} + +export function doesResourceLookLikeAJavaScriptFile(resource: vscode.Uri): boolean { + return /\.jsx?$/i.test(resource.fsPath); +} diff --git a/extensions/typescript-language-features/src/utils/typingsStatus.ts b/extensions/typescript-language-features/src/utils/typingsStatus.ts index 70418b736a6..a070b205621 100644 --- a/extensions/typescript-language-features/src/utils/typingsStatus.ts +++ b/extensions/typescript-language-features/src/utils/typingsStatus.ts @@ -13,27 +13,25 @@ const localize = loadMessageBundle(); const typingsInstallTimeout = 30 * 1000; export default class TypingsStatus extends Disposable { - private _acquiringTypings: { [eventId: string]: NodeJS.Timer } = Object.create({}); - private _client: ITypeScriptServiceClient; - private _subscriptions: vscode.Disposable[] = []; + private readonly _acquiringTypings = new Map(); + private readonly _client: ITypeScriptServiceClient; constructor(client: ITypeScriptServiceClient) { super(); this._client = client; - this._subscriptions.push( + this._register( this._client.onDidBeginInstallTypings(event => this.onBeginInstallTypings(event.eventId))); - this._subscriptions.push( + this._register( this._client.onDidEndInstallTypings(event => this.onEndInstallTypings(event.eventId))); } public dispose(): void { super.dispose(); - this._subscriptions.forEach(x => x.dispose()); - for (const eventId of Object.keys(this._acquiringTypings)) { - clearTimeout(this._acquiringTypings[eventId]); + for (const timeout of this._acquiringTypings.values()) { + clearTimeout(timeout); } } @@ -42,37 +40,36 @@ export default class TypingsStatus extends Disposable { } private onBeginInstallTypings(eventId: number): void { - if (this._acquiringTypings[eventId]) { + if (this._acquiringTypings.has(eventId)) { return; } - this._acquiringTypings[eventId] = setTimeout(() => { + this._acquiringTypings.set(eventId, setTimeout(() => { this.onEndInstallTypings(eventId); - }, typingsInstallTimeout); + }, typingsInstallTimeout)); } private onEndInstallTypings(eventId: number): void { - const timer = this._acquiringTypings[eventId]; + const timer = this._acquiringTypings.get(eventId); if (timer) { clearTimeout(timer); } - delete this._acquiringTypings[eventId]; + this._acquiringTypings.delete(eventId); } } -export class AtaProgressReporter { +export class AtaProgressReporter extends Disposable { - private _promises = new Map(); - private _disposable: vscode.Disposable; + private readonly _promises = new Map(); constructor(client: ITypeScriptServiceClient) { - this._disposable = vscode.Disposable.from( - client.onDidBeginInstallTypings(e => this._onBegin(e.eventId)), - client.onDidEndInstallTypings(e => this._onEndOrTimeout(e.eventId)), - client.onTypesInstallerInitializationFailed(_ => this.onTypesInstallerInitializationFailed())); + super(); + this._register(client.onDidBeginInstallTypings(e => this._onBegin(e.eventId))); + this._register(client.onDidEndInstallTypings(e => this._onEndOrTimeout(e.eventId))); + this._register(client.onTypesInstallerInitializationFailed(_ => this.onTypesInstallerInitializationFailed())); } dispose(): void { - this._disposable.dispose(); + super.dispose(); this._promises.forEach(value => value()); } diff --git a/extensions/typescript-language-features/src/utils/versionPicker.ts b/extensions/typescript-language-features/src/utils/versionPicker.ts index d1827002ee3..20bae2ab64d 100644 --- a/extensions/typescript-language-features/src/utils/versionPicker.ts +++ b/extensions/typescript-language-features/src/utils/versionPicker.ts @@ -58,8 +58,8 @@ export class TypeScriptVersionPicker { pickOptions.push({ label: (!this.useWorkspaceTsdkSetting ? '• ' - : '') + localize('useVSCodeVersionOption', 'Use VS Code\'s Version'), - description: shippedVersion.versionString, + : '') + localize('useVSCodeVersionOption', "Use VS Code's Version"), + description: shippedVersion.displayName, detail: shippedVersion.pathLabel, id: MessageAction.useBundled, }); @@ -68,8 +68,8 @@ export class TypeScriptVersionPicker { pickOptions.push({ label: (this.useWorkspaceTsdkSetting && this.currentVersion.path === version.path ? '• ' - : '') + localize('useWorkspaceVersionOption', 'Use Workspace Version'), - description: version.versionString, + : '') + localize('useWorkspaceVersionOption', "Use Workspace Version"), + description: version.displayName, detail: version.pathLabel, id: MessageAction.useLocal, version @@ -85,7 +85,7 @@ export class TypeScriptVersionPicker { const selected = await vscode.window.showQuickPick(pickOptions, { placeHolder: localize( 'selectTsVersion', - 'Select the TypeScript version used for JavaScript and TypeScript language features'), + "Select the TypeScript version used for JavaScript and TypeScript language features"), ignoreFocusOut: firstRun, }); @@ -120,4 +120,4 @@ export class TypeScriptVersionPicker { return { oldVersion: this.currentVersion }; } } -} \ No newline at end of file +} diff --git a/extensions/typescript-language-features/src/utils/versionProvider.ts b/extensions/typescript-language-features/src/utils/versionProvider.ts index 8e9e9a2a8c6..2864d9f9273 100644 --- a/extensions/typescript-language-features/src/utils/versionProvider.ts +++ b/extensions/typescript-language-features/src/utils/versionProvider.ts @@ -12,8 +12,17 @@ import { RelativeWorkspacePathResolver } from './relativePathResolver'; const localize = nls.loadMessageBundle(); +export const enum TypeScriptVersionSource { + Bundled = 'bundled', + TsNightlyExtension = 'ts-nightly-extension', + NodeModules = 'node-modules', + UserSetting = 'user-setting', + WorkspaceSetting = 'workspace-setting', +} + export class TypeScriptVersion { constructor( + public readonly source: TypeScriptVersionSource, public readonly path: string, private readonly _pathLabel?: string ) { } @@ -23,7 +32,7 @@ export class TypeScriptVersion { } public get pathLabel(): string { - return typeof this._pathLabel === 'undefined' ? this.path : this._pathLabel; + return this._pathLabel ?? this.path; } public get isValid(): boolean { @@ -45,9 +54,9 @@ export class TypeScriptVersion { return undefined; } - public get versionString(): string { + public get displayName(): string { const version = this.apiVersion; - return version ? version.versionString : localize( + return version ? version.displayName : localize( 'couldNotLoadTsVersion', 'Could not load the TypeScript version at this path'); } @@ -103,7 +112,7 @@ export class TypeScriptVersionProvider { public get globalVersion(): TypeScriptVersion | undefined { if (this.configuration.globalTsdk) { - const globals = this.loadVersionsFromSetting(this.configuration.globalTsdk); + const globals = this.loadVersionsFromSetting(TypeScriptVersionSource.UserSetting, this.configuration.globalTsdk); if (globals && globals.length) { return globals[0]; } @@ -137,7 +146,7 @@ export class TypeScriptVersionProvider { } public get bundledVersion(): TypeScriptVersion { - const version = this.getContributedVersion('vscode.typescript-language-features', ['..', 'node_modules']); + const version = this.getContributedVersion(TypeScriptVersionSource.Bundled, 'vscode.typescript-language-features', ['..', 'node_modules']); if (version) { return version; } @@ -149,15 +158,15 @@ export class TypeScriptVersionProvider { } private get contributedTsNextVersion(): TypeScriptVersion | undefined { - return this.getContributedVersion('ms-vscode.vscode-typescript-next', ['node_modules']); + return this.getContributedVersion(TypeScriptVersionSource.TsNightlyExtension, 'ms-vscode.vscode-typescript-next', ['node_modules']); } - private getContributedVersion(extensionId: string, pathToTs: readonly string[]): TypeScriptVersion | undefined { + private getContributedVersion(source: TypeScriptVersionSource, 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, ''); + const bundledVersion = new TypeScriptVersion(source, typescriptPath, ''); if (bundledVersion.isValid) { return bundledVersion; } @@ -170,28 +179,28 @@ export class TypeScriptVersionProvider { private get localTsdkVersions(): TypeScriptVersion[] { const localTsdk = this.configuration.localTsdk; - return localTsdk ? this.loadVersionsFromSetting(localTsdk) : []; + return localTsdk ? this.loadVersionsFromSetting(TypeScriptVersionSource.WorkspaceSetting, localTsdk) : []; } - private loadVersionsFromSetting(tsdkPathSetting: string): TypeScriptVersion[] { + private loadVersionsFromSetting(source: TypeScriptVersionSource, tsdkPathSetting: string): TypeScriptVersion[] { if (path.isAbsolute(tsdkPathSetting)) { - return [new TypeScriptVersion(tsdkPathSetting)]; + return [new TypeScriptVersion(source, tsdkPathSetting)]; } const workspacePath = RelativeWorkspacePathResolver.asAbsoluteWorkspacePath(tsdkPathSetting); if (workspacePath !== undefined) { - return [new TypeScriptVersion(workspacePath, tsdkPathSetting)]; + return [new TypeScriptVersion(source, workspacePath, tsdkPathSetting)]; } - return this.loadTypeScriptVersionsFromPath(tsdkPathSetting); + return this.loadTypeScriptVersionsFromPath(source, tsdkPathSetting); } private get localNodeModulesVersions(): TypeScriptVersion[] { - return this.loadTypeScriptVersionsFromPath(path.join('node_modules', 'typescript', 'lib')) + return this.loadTypeScriptVersionsFromPath(TypeScriptVersionSource.NodeModules, path.join('node_modules', 'typescript', 'lib')) .filter(x => x.isValid); } - private loadTypeScriptVersionsFromPath(relativePath: string): TypeScriptVersion[] { + private loadTypeScriptVersionsFromPath(source: TypeScriptVersionSource, relativePath: string): TypeScriptVersion[] { if (!vscode.workspace.workspaceFolders) { return []; } @@ -203,7 +212,7 @@ export class TypeScriptVersionProvider { label = path.join(root.name, relativePath); } - versions.push(new TypeScriptVersion(path.join(root.uri.fsPath, relativePath), label)); + versions.push(new TypeScriptVersion(source, path.join(root.uri.fsPath, relativePath), label)); } return versions; } diff --git a/extensions/typescript-language-features/src/utils/versionStatus.ts b/extensions/typescript-language-features/src/utils/versionStatus.ts index 07bd2e5921a..9d6ebeda69e 100644 --- a/extensions/typescript-language-features/src/utils/versionStatus.ts +++ b/extensions/typescript-language-features/src/utils/versionStatus.ts @@ -29,7 +29,7 @@ export default class VersionStatus extends Disposable { public onDidChangeTypeScriptVersion(version: TypeScriptVersion) { this.showHideStatus(); - this._versionBarEntry.text = version.versionString; + this._versionBarEntry.text = version.displayName; this._versionBarEntry.tooltip = version.path; this._versionBarEntry.command = 'typescript.selectTypeScriptVersion'; } diff --git a/extensions/typescript-language-features/yarn.lock b/extensions/typescript-language-features/yarn.lock index 682bc093c6c..a45e26290c6 100644 --- a/extensions/typescript-language-features/yarn.lock +++ b/extensions/typescript-language-features/yarn.lock @@ -26,10 +26,10 @@ 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/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== "@types/rimraf@2.0.2": version "2.0.2" diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index beaa216d77d..92dd07f59b2 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -6,8 +6,10 @@ "license": "MIT", "enableProposedApi": true, "private": true, - "main": "horse", - "activationEvents": [], + "activationEvents": [ + "onFileSystem:memfs" + ], + "main": "./out/extension", "engines": { "vscode": "^1.25.0" }, @@ -50,7 +52,7 @@ }, "devDependencies": { "@types/mocha": "2.2.43", - "@types/node": "^10.14.8", + "@types/node": "^12.11.7", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "typescript": "^1.6.2", diff --git a/extensions/vscode-api-tests/src/extension.ts b/extensions/vscode-api-tests/src/extension.ts new file mode 100644 index 00000000000..e47f906bf24 --- /dev/null +++ b/extensions/vscode-api-tests/src/extension.ts @@ -0,0 +1,343 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// +// ############################################################################ +// +// ! USED FOR RUNNING VSCODE OUT OF SOURCES FOR WEB ! +// ! DO NOT REMOVE ! +// +// ############################################################################ +// + +import * as vscode from 'vscode'; + +let textEncoder = new TextEncoder(); + +export function activate(context: vscode.ExtensionContext) { + + console.log('MemFS says "Hello"'); + + const memFs = new MemFS(); + context.subscriptions.push(vscode.workspace.registerFileSystemProvider('memfs', memFs, { isCaseSensitive: true })); + let initialized = false; + + function init() { + if (initialized) { + return; + } + initialized = true; + + // most common files types + memFs.writeFile(vscode.Uri.parse(`memfs:/file.txt`), textEncoder.encode('foo'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.html`), textEncoder.encode('

Hello

'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.js`), textEncoder.encode('console.log("JavaScript")'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.json`), textEncoder.encode('{ "json": true }'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.ts`), textEncoder.encode('console.log("TypeScript")'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.css`), textEncoder.encode('* { color: green; }'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.md`), textEncoder.encode('Hello _World_'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.xml`), textEncoder.encode(''), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.py`), textEncoder.encode('import base64, sys; base64.decode(open(sys.argv[1], "rb"), open(sys.argv[2], "wb"))'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.php`), textEncoder.encode('&1\'); ?>'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/file.yaml`), textEncoder.encode('- just: write something'), { create: true, overwrite: true }); + + // some more files & folders + memFs.createDirectory(vscode.Uri.parse(`memfs:/folder/`)); + memFs.createDirectory(vscode.Uri.parse(`memfs:/large/`)); + memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/`)); + memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/abc`)); + memFs.createDirectory(vscode.Uri.parse(`memfs:/xyz/def`)); + + memFs.writeFile(vscode.Uri.parse(`memfs:/folder/empty.txt`), new Uint8Array(0), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/folder/empty.foo`), new Uint8Array(0), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/folder/file.ts`), textEncoder.encode('let a:number = true; console.log(a);'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/large/rnd.foo`), randomData(50000), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/UPPER.txt`), textEncoder.encode('UPPER'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/upper.txt`), textEncoder.encode('upper'), { create: true, overwrite: true }); + memFs.writeFile(vscode.Uri.parse(`memfs:/xyz/def/foo.md`), textEncoder.encode('*MemFS*'), { create: true, overwrite: true }); + } + + init(); +} + +function randomData(lineCnt: number, lineLen = 155): Uint8Array { + let lines: string[] = []; + for (let i = 0; i < lineCnt; i++) { + let line = ''; + while (line.length < lineLen) { + line += Math.random().toString(2 + (i % 34)).substr(2); + } + lines.push(line.substr(0, lineLen)); + } + return textEncoder.encode(lines.join('\n')); +} + +export 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; + } +} + +export 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 { + + 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 = this._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 = this._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: this._dirname(uri.path) }); + let basename = this._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 = this._basename(uri.path); + let dirname = uri.with({ path: this._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: this._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); + } + + // --- path utils + + private _basename(path: string): string { + path = this._rtrim(path, '/'); + if (!path) { + return ''; + } + + return path.substr(path.lastIndexOf('/') + 1); + } + + private _dirname(path: string): string { + path = this._rtrim(path, '/'); + if (!path) { + return '/'; + } + + return path.substr(0, path.lastIndexOf('/')); + } + + private _rtrim(haystack: string, needle: string): string { + if (!haystack || !needle) { + return haystack; + } + + const needleLen = needle.length, + haystackLen = haystack.length; + + if (needleLen === 0 || haystackLen === 0) { + return haystack; + } + + let offset = haystackLen, + idx = -1; + + while (true) { + idx = haystack.lastIndexOf(needle, offset - 1); + if (idx === -1 || idx + needleLen !== offset) { + break; + } + if (idx === 0) { + return ''; + } + offset = idx; + } + + return haystack.substring(0, offset); + } +} 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 7dba2cfa93c..fba9348435c 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts @@ -6,7 +6,7 @@ import 'mocha'; import * as assert from 'assert'; import { join } from 'path'; -import { commands, workspace, window, Uri, ViewColumn, Range, Position } from 'vscode'; +import { commands, workspace, window, Uri, Range, Position, ViewColumn } from 'vscode'; suite('commands namespace tests', () => { 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 9b6c6d82897..4b6ee382120 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { workspace, window, Position, Range, commands, TextEditor, TextDocument, TextEditorCursorStyle, TextEditorLineNumbersStyle, SnippetString, Selection } from 'vscode'; +import { workspace, window, Position, Range, commands, TextEditor, TextDocument, TextEditorCursorStyle, TextEditorLineNumbersStyle, SnippetString, Selection, Uri } from 'vscode'; import { createRandomFile, deleteFile, closeAllEditors } from '../utils'; suite('editor tests', () => { @@ -197,11 +197,8 @@ 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(() => { @@ -216,6 +213,21 @@ suite('editor tests', () => { }); }); }); - }); + + test('editor contents are correctly read (small file)', function () { + return testEditorContents('/far.js'); + }); + + test('editor contents are correctly read (large file)', async function () { + return testEditorContents('/lorem.txt'); + }); + + async function testEditorContents(relativePath: string) { + const root = workspace.workspaceFolders![0]!.uri; + const file = Uri.parse(root.toString() + relativePath); + const document = await workspace.openTextDocument(file); + + assert.equal(document.getText(), Buffer.from(await workspace.fs.readFile(file)).toString()); + } }); 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 4189615c09e..318b0d07bb3 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, extensions, ExtensionKind, UIKind } from 'vscode'; +import { env, extensions, ExtensionKind, UIKind, Uri } from 'vscode'; suite('env-namespace', () => { @@ -38,15 +38,38 @@ suite('env-namespace', () => { } else if (typeof remoteName === 'string') { // running in remote, so we only expect workspace extensions assert.ok(knownWorkspaceExtension); - assert.ok(!knownUiExtension); // we currently can only access extensions that run on same host + if (env.uiKind === UIKind.Desktop) { + assert.ok(!knownUiExtension); // we currently can only access extensions that run on same host + } assert.equal(ExtensionKind.Workspace, knownWorkspaceExtension!.extensionKind); } else { assert.fail(); } }); - test('env.uiKind', function () { + test('env.uiKind', async function () { + const uri = Uri.parse(`${env.uriScheme}:://vscode.vscode-api-tests/path?key=value&other=false`); + const result = await env.asExternalUri(uri); + const kind = env.uiKind; - assert.equal(kind, UIKind.Desktop); + if (result.scheme === 'http' || result.scheme === 'https') { + assert.equal(kind, UIKind.Web); + } else { + assert.equal(kind, UIKind.Desktop); + } + }); + + test('env.asExternalUri - with env.uriScheme', async function () { + const uri = Uri.parse(`${env.uriScheme}:://vscode.vscode-api-tests/path?key=value&other=false`); + const result = await env.asExternalUri(uri); + assert.ok(result); + + if (env.uiKind === UIKind.Desktop) { + assert.equal(uri.scheme, result.scheme); + assert.equal(uri.authority, result.authority); + assert.equal(uri.path, result.path); + } else { + assert.ok(result.scheme === 'http' || result.scheme === 'https'); + } }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index 1cde9257d52..3df611b17b4 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget } from 'vscode'; +import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget, Disposable } from 'vscode'; import { doesNotThrow, equal, ok, deepEqual } from 'assert'; suite('window namespace tests', () => { @@ -12,75 +12,91 @@ suite('window namespace tests', () => { await workspace.getConfiguration('terminal.integrated').update('windowsEnableConpty', false, ConfigurationTarget.Global); }); suite('Terminal', () => { + let disposables: Disposable[] = []; + + teardown(() => { + disposables.forEach(d => d.dispose()); + disposables.length = 0; + }); + test('sendText immediately after createTerminal should not throw', (done) => { - const reg1 = window.onDidOpenTerminal(term => { - equal(terminal, term); + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(terminal, term); + } catch (e) { + done(e); + } terminal.dispose(); - reg1.dispose(); - const reg2 = window.onDidCloseTerminal(() => { - reg2.dispose(); - done(); - }); - }); + disposables.push(window.onDidCloseTerminal(() => 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); + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(terminal, term); + } catch (e) { + done(e); + } terminal.dispose(); - reg1.dispose(); - const reg2 = window.onDidCloseTerminal(() => { - reg2.dispose(); - done(); - }); - }); + disposables.push(window.onDidCloseTerminal(() => 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(); + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(terminal, term); + } catch (e) { + done(e); + } terminal.processId.then(id => { - ok(id > 0); + try { + ok(id > 0); + } catch (e) { + done(e); + } terminal.dispose(); - const reg2 = window.onDidCloseTerminal(() => { - reg2.dispose(); - done(); - }); + disposables.push(window.onDidCloseTerminal(() => done())); }); - }); + })); const terminal = window.createTerminal(); }); test('name in constructor should set terminal.name', (done) => { - const reg1 = window.onDidOpenTerminal(term => { - equal(terminal, term); + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(terminal, term); + } catch (e) { + done(e); + } terminal.dispose(); - reg1.dispose(); - const reg2 = window.onDidCloseTerminal(() => { - reg2.dispose(); - done(); - }); - }); + disposables.push(window.onDidCloseTerminal(() => done())); + })); const terminal = window.createTerminal('a'); - equal(terminal.name, 'a'); + try { + equal(terminal.name, 'a'); + } catch (e) { + done(e); + } }); 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(); - }); + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(term.name, 'b'); + } catch (e) { + done(e); + } + disposables.push(window.onDidCloseTerminal(() => done())); terminal.dispose(); - }); + })); const terminal = window.createTerminal('b'); }); + // test('onDidChangeActiveTerminal should fire when new terminals are created', (done) => { // const reg1 = window.onDidChangeActiveTerminal((active: Terminal | undefined) => { // equal(active, terminal); @@ -154,16 +170,20 @@ suite('window namespace tests', () => { suite('hideFromUser', () => { 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(); + disposables.push(window.onDidOpenTerminal(t => { + try { + equal(t, terminal); + equal(t.name, 'bg'); + ok(window.terminals.indexOf(terminal) !== -1); + } catch (e) { + done(e); + } + disposables.push(window.onDidCloseTerminal(() => { + // reg3.dispose(); done(); - }); + })); terminal.dispose(); - }); + })); }); }); @@ -172,61 +192,96 @@ suite('window namespace tests', () => { const openEvents: string[] = []; const dataEvents: { name: string, data: string }[] = []; const closeEvents: string[] = []; - const reg1 = window.onDidOpenTerminal(e => openEvents.push(e.name)); - const reg2 = window.onDidWriteTerminalData(e => dataEvents.push({ name: e.terminal.name, data: e.data })); - const reg3 = window.onDidCloseTerminal(e => { + disposables.push(window.onDidOpenTerminal(e => openEvents.push(e.name))); + + let resolveOnceDataWritten: (() => void) | undefined; + let resolveOnceClosed: (() => void) | undefined; + + disposables.push(window.onDidWriteTerminalData(e => { + dataEvents.push({ name: e.terminal.name, data: e.data }); + + resolveOnceDataWritten!(); + })); + + disposables.push(window.onDidCloseTerminal(e => { closeEvents.push(e.name); - if (closeEvents.length === 2) { - deepEqual(openEvents, [ 'test1', 'test2' ]); - deepEqual(dataEvents, [ { name: 'test1', data: 'write1' }, { name: 'test2', data: 'write2' } ]); - deepEqual(closeEvents, [ 'test1', 'test2' ]); - reg1.dispose(); - reg2.dispose(); - reg3.dispose(); - done(); + try { + if (closeEvents.length === 1) { + deepEqual(openEvents, ['test1']); + deepEqual(dataEvents, [{ name: 'test1', data: 'write1' }]); + deepEqual(closeEvents, ['test1']); + } else if (closeEvents.length === 2) { + deepEqual(openEvents, ['test1', 'test2']); + deepEqual(dataEvents, [{ name: 'test1', data: 'write1' }, { name: 'test2', data: 'write2' }]); + deepEqual(closeEvents, ['test1', 'test2']); + } + resolveOnceClosed!(); + } catch (e) { + done(e); } - }); + })); const term1Write = new EventEmitter(); const term1Close = new EventEmitter(); - window.createTerminal({ name: 'test1', pty: { - onDidWrite: term1Write.event, - onDidClose: term1Close.event, - open: () => { - term1Write.fire('write1'); - term1Close.fire(); - const term2Write = new EventEmitter(); - const term2Close = new EventEmitter(); - window.createTerminal({ name: 'test2', pty: { - onDidWrite: term2Write.event, - onDidClose: term2Close.event, - open: () => { - term2Write.fire('write2'); - term2Close.fire(); - }, - close: () => {} - }}); - }, - close: () => {} - }}); + window.createTerminal({ + name: 'test1', pty: { + onDidWrite: term1Write.event, + onDidClose: term1Close.event, + open: async () => { + term1Write.fire('write1'); + + // Wait until the data is written + await new Promise(resolve => { resolveOnceDataWritten = resolve; }); + + term1Close.fire(); + + // Wait until the terminal is closed + await new Promise(resolve => { resolveOnceClosed = resolve; }); + + const term2Write = new EventEmitter(); + const term2Close = new EventEmitter(); + window.createTerminal({ + name: 'test2', pty: { + onDidWrite: term2Write.event, + onDidClose: term2Close.event, + open: async () => { + term2Write.fire('write2'); + + // Wait until the data is written + await new Promise(resolve => { resolveOnceDataWritten = resolve; }); + + term2Close.fire(); + + // Wait until the terminal is closed + await new Promise(resolve => { resolveOnceClosed = resolve; }); + + done(); + }, + close: () => { } + } + }); + }, + close: () => { } + } + }); }); }); suite('Extension pty 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(); - }); + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(term.name, 'c'); + } catch (e) { + done(e); + } + disposables.push(window.onDidCloseTerminal(() => done())); term.dispose(); - }); + })); const pty: Pseudoterminal = { onDidWrite: new EventEmitter().event, - open: () => {}, - close: () => {} + open: () => { }, + close: () => { } }; window.createTerminal({ name: 'c', pty }); }); @@ -279,22 +334,29 @@ suite('window namespace tests', () => { // }); test('should respect dimension overrides', (done) => { - const reg1 = window.onDidOpenTerminal(term => { - equal(terminal, term); - reg1.dispose(); + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(terminal, term); + } catch (e) { + done(e); + } 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(); - }); + disposables.push(window.onDidChangeTerminalDimensions(e => { + if (e.dimensions.columns === 0 || e.dimensions.rows === 0) { + // HACK: Ignore the event if dimension(s) are zero (#83778) + return; + } + try { + equal(e.dimensions.columns, 10); + equal(e.dimensions.rows, 5); + equal(e.terminal, terminal); + } catch (e) { + done(e); + } + disposables.push(window.onDidCloseTerminal(() => done())); terminal.dispose(); - }); - }); + })); + })); const writeEmitter = new EventEmitter(); const overrideDimensionsEmitter = new EventEmitter(); const pty: Pseudoterminal = { @@ -303,7 +365,7 @@ suite('window namespace tests', () => { open: () => { overrideDimensionsEmitter.fire({ columns: 10, rows: 5 }); }, - close: () => {} + close: () => { } }; const terminal = window.createTerminal({ name: 'foo', pty }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts new file mode 100644 index 00000000000..070b6818d72 --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.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 * as assert from 'assert'; +import * as vscode from 'vscode'; +import { createRandomFile } from '../utils'; + +suite('workspace-event', () => { + + const disposables: vscode.Disposable[] = []; + + teardown(() => { + for (const dispo of disposables) { + dispo.dispose(); + } + disposables.length = 0; + }); + + test('onWillCreate/onDidCreate', async function () { + + const base = await createRandomFile(); + const newUri = base.with({ path: base.path + '-foo' }); + + let onWillCreate: vscode.FileWillCreateEvent | undefined; + let onDidCreate: vscode.FileCreateEvent | undefined; + + disposables.push(vscode.workspace.onWillCreateFiles(e => onWillCreate = e)); + disposables.push(vscode.workspace.onDidCreateFiles(e => onDidCreate = e)); + + const edit = new vscode.WorkspaceEdit(); + edit.createFile(newUri); + + const success = await vscode.workspace.applyEdit(edit); + assert.ok(success); + + assert.ok(onWillCreate); + assert.equal(onWillCreate?.creating.length, 1); + assert.equal(onWillCreate?.creating[0].toString(), newUri.toString()); + + assert.ok(onDidCreate); + assert.equal(onDidCreate?.created.length, 1); + assert.equal(onDidCreate?.created[0].toString(), newUri.toString()); + }); + + test('onWillDelete/onDidDelete', async function () { + + const base = await createRandomFile(); + + let onWilldelete: vscode.FileWillDeleteEvent | undefined; + let onDiddelete: vscode.FileDeleteEvent | undefined; + + disposables.push(vscode.workspace.onWillDeleteFiles(e => onWilldelete = e)); + disposables.push(vscode.workspace.onDidDeleteFiles(e => onDiddelete = e)); + + const edit = new vscode.WorkspaceEdit(); + edit.deleteFile(base); + + const success = await vscode.workspace.applyEdit(edit); + assert.ok(success); + + assert.ok(onWilldelete); + assert.equal(onWilldelete?.deleting.length, 1); + assert.equal(onWilldelete?.deleting[0].toString(), base.toString()); + + assert.ok(onDiddelete); + assert.equal(onDiddelete?.deleted.length, 1); + assert.equal(onDiddelete?.deleted[0].toString(), base.toString()); + }); + + test('onWillRename/onDidRename', async function () { + + const oldUri = await createRandomFile(); + const newUri = oldUri.with({ path: oldUri.path + '-NEW' }); + + let onWillRename: vscode.FileWillRenameEvent | undefined; + let onDidRename: vscode.FileRenameEvent | undefined; + + disposables.push(vscode.workspace.onWillRenameFiles(e => onWillRename = e)); + disposables.push(vscode.workspace.onDidRenameFiles(e => onDidRename = e)); + + const edit = new vscode.WorkspaceEdit(); + edit.renameFile(oldUri, newUri); + + const success = await vscode.workspace.applyEdit(edit); + assert.ok(success); + + assert.ok(onWillRename); + assert.equal(onWillRename?.renaming.length, 1); + assert.equal(onWillRename?.renaming[0].oldUri.toString(), oldUri.toString()); + assert.equal(onWillRename?.renaming[0].newUri.toString(), newUri.toString()); + + assert.ok(onDidRename); + assert.equal(onDidRename?.renamed.length, 1); + assert.equal(onDidRename?.renamed[0].oldUri.toString(), oldUri.toString()); + assert.equal(onDidRename?.renamed[0].newUri.toString(), newUri.toString()); + }); + + test('onWillRename - make changes', async function () { + + const oldUri = await createRandomFile('BAR'); + const newUri = oldUri.with({ path: oldUri.path + '-NEW' }); + + const anotherFile = await createRandomFile('BAR'); + + let onWillRename: vscode.FileWillRenameEvent | undefined; + + disposables.push(vscode.workspace.onWillRenameFiles(e => { + onWillRename = e; + const edit = new vscode.WorkspaceEdit(); + edit.insert(e.renaming[0].oldUri, new vscode.Position(0, 0), 'FOO'); + edit.replace(anotherFile, new vscode.Range(0, 0, 0, 3), 'FARBOO'); + e.waitUntil(Promise.resolve(edit)); + })); + + const edit = new vscode.WorkspaceEdit(); + edit.renameFile(oldUri, newUri); + + const success = await vscode.workspace.applyEdit(edit); + assert.ok(success); + + assert.ok(onWillRename); + assert.equal(onWillRename?.renaming.length, 1); + assert.equal(onWillRename?.renaming[0].oldUri.toString(), oldUri.toString()); + assert.equal(onWillRename?.renaming[0].newUri.toString(), newUri.toString()); + + assert.equal((await vscode.workspace.openTextDocument(newUri)).getText(), 'FOOBAR'); + assert.equal((await vscode.workspace.openTextDocument(anotherFile)).getText(), 'FARBOO'); + }); +}); 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 index 7f21223b344..edb404b8653 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -4,14 +4,20 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import * as vscode from 'vscode'; +import { window, tasks, Disposable, TaskDefinition, Task, EventEmitter, CustomExecution, Pseudoterminal, TaskScope, commands, Task2 } from 'vscode'; suite('workspace-namespace', () => { suite('Tasks', () => { + let disposables: Disposable[] = []; - test('CustomExecution2 task should start and shutdown successfully', (done) => { - interface CustomTestingTaskDefinition extends vscode.TaskDefinition { + teardown(() => { + disposables.forEach(d => d.dispose()); + disposables.length = 0; + }); + + test('CustomExecution task should start and shutdown successfully', (done) => { + interface CustomTestingTaskDefinition extends TaskDefinition { /** * One of the task properties. This can be used to customize the task in the tasks.json */ @@ -19,45 +25,58 @@ suite('workspace-namespace', () => { } const taskType: string = 'customTesting'; const taskName = 'First custom task'; - const reg1 = vscode.window.onDidOpenTerminal(term => { - reg1.dispose(); - const reg2 = vscode.window.onDidWriteTerminalData(e => { - reg2.dispose(); - assert.equal(e.data, 'testing\r\n'); + let isPseudoterminalClosed = false; + disposables.push(window.onDidOpenTerminal(term => { + disposables.push(window.onDidWriteTerminalData(e => { + try { + assert.equal(e.data, 'testing\r\n'); + } catch (e) { + done(e); + } + disposables.push(window.onDidCloseTerminal(() => { + try { + // Pseudoterminal.close should have fired by now, additionally we want + // to make sure all events are flushed before continuing with more tests + assert.ok(isPseudoterminalClosed); + } catch (e) { + done(e); + return; + } + done(); + })); term.dispose(); - }); - }); - const taskProvider = vscode.tasks.registerTaskProvider(taskType, { + })); + })); + disposables.push(tasks.registerTaskProvider(taskType, { provideTasks: () => { - const result: vscode.Task[] = []; + const result: 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 = { + const writeEmitter = new EventEmitter(); + const execution = new CustomExecution((): Thenable => { + const pty: Pseudoterminal = { onDidWrite: writeEmitter.event, - open: () => { - writeEmitter.fire('testing\r\n'); - }, - close: () => { - taskProvider.dispose(); - done(); - } + open: () => writeEmitter.fire('testing\r\n'), + close: () => isPseudoterminalClosed = true }; return Promise.resolve(pty); }); - const task = new vscode.Task2(kind, vscode.TaskScope.Workspace, taskName, taskType, execution); + const task = new Task2(kind, TaskScope.Workspace, taskName, taskType, execution); result.push(task); return result; }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { + resolveTask(_task: Task): Task | undefined { + try { assert.fail('resolveTask should not trigger during the test'); + } catch (e) { + done(e); + } return undefined; } - }); - vscode.commands.executeCommand('workbench.action.tasks.runTask', `${taskType}: ${taskName}`); + })); + commands.executeCommand('workbench.action.tasks.runTask', `${taskType}: ${taskName}`); }); }); }); diff --git a/extensions/vscode-api-tests/testWorkspace/lorem.txt b/extensions/vscode-api-tests/testWorkspace/lorem.txt new file mode 100644 index 00000000000..88c7aaee6b0 --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/lorem.txt @@ -0,0 +1,1135 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vulputate, ipsum quis interdum fermentum, lorem sem fermentum eros, vitae auctor neque lacus in nisi. Suspendisse potenti. Maecenas et scelerisque elit, in tincidunt quam. Sed eu tincidunt quam. Nullam justo ex, imperdiet a imperdiet et, fermentum sit amet eros. Aenean quis tempus sem. Pellentesque accumsan magna mi, ut mollis velit sagittis id. Etiam quis ipsum orci. Fusce purus ante, accumsan a lobortis at, venenatis eu nisl. Praesent ornare sed ante placerat accumsan. Suspendisse tempus dignissim fermentum. Nunc a leo ac lacus sodales iaculis eu vitae mi. In feugiat ante at massa finibus cursus. Suspendisse posuere fringilla ornare. Mauris elementum ac quam id convallis. Vestibulum non elit quis urna volutpat aliquam a eu lacus. + +Aliquam vestibulum imperdiet neque, suscipit aliquam elit ultrices bibendum. Suspendisse ultrices pulvinar cursus. Morbi risus nisi, cursus consequat rutrum vitae, molestie sed dui. Fusce posuere, augue quis dignissim aliquam, nisi ipsum porttitor ante, quis fringilla nisl turpis ac nisi. Nulla varius enim eget lorem vehicula gravida. Donec finibus malesuada leo nec semper. Proin ac enim eros. Vivamus non tincidunt nisi, vel tristique lorem. + +Nunc consequat ex id eros dignissim, id rutrum risus laoreet. Sed euismod non erat eu ultricies. Etiam vehicula gravida lacus ut porta. Vestibulum eu eros quis nunc aliquet luctus. Cras quis semper ligula. Nullam gravida vehicula quam sed porta. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In porta cursus vulputate. Quisque porta a nisi eget cursus. Aliquam risus leo, luctus ac magna in, efficitur cursus magna. In condimentum non mi id semper. Donec interdum ante eget commodo maximus. + +Vivamus sit amet vestibulum lectus. Fusce tincidunt mi sapien, dictum sollicitudin diam vulputate in. Integer fringilla consequat mollis. Cras aliquet consequat felis eget feugiat. Nunc tempor cursus arcu, vitae ornare nunc varius et. Vestibulum et tortor vel ante viverra porttitor. Nam at tortor ullamcorper, facilisis augue quis, tristique erat. Aenean ut euismod nibh. Quisque eu tincidunt est, nec euismod eros. + +Proin vehicula nibh non viverra egestas. Phasellus sem dolor, ultricies ac sagittis tristique, lacinia a purus. Vestibulum in ante eros. Pellentesque lacus nulla, tristique vitae interdum vel, malesuada ac diam. Aenean bibendum posuere turpis in accumsan. Ut est nulla, ullamcorper quis turpis at, viverra sagittis mauris. Sed in interdum purus. Praesent scelerisque nibh eget sem euismod, ut imperdiet mi venenatis. Vivamus pulvinar orci sed dapibus auctor. Nulla facilisi. Vestibulum tincidunt erat nec porttitor egestas. Mauris quis risus ante. Nulla facilisi. + +Aliquam ullamcorper ornare lobortis. Phasellus quis sem et ipsum mollis malesuada sed in ex. Ut aliquam ex eget metus finibus maximus. Proin suscipit mauris eu nibh lacinia, quis feugiat dui dapibus. Nam sed libero est. Aenean vulputate orci sit amet diam faucibus, eu sagittis sapien volutpat. Nam imperdiet felis turpis, at pretium odio pulvinar in. Sed vestibulum id eros nec ultricies. Sed quis aliquam tortor, vitae ullamcorper tellus. Donec egestas laoreet eros, id suscipit est rutrum nec. Sed auctor nulla eget metus aliquam, ut condimentum enim elementum. + +Aliquam suscipit non turpis sit amet bibendum. Fusce velit ligula, euismod et maximus at, luctus sed neque. Quisque pretium, nisl at ullamcorper finibus, lectus leo mattis sapien, vel euismod mauris diam ullamcorper ex. Nulla ut risus finibus, lacinia ligula at, auctor erat. Mauris consectetur sagittis ligula vel dapibus. Nullam libero libero, lobortis aliquam libero vel, venenatis ultricies leo. Duis porttitor, nibh congue fermentum posuere, erat libero pulvinar tortor, a pellentesque nunc ipsum vel sem. Nullam volutpat, eros sit amet facilisis consectetur, ipsum est vehicula massa, non vestibulum neque elit in mauris. Nunc hendrerit ipsum non enim bibendum, vitae rhoncus mi egestas. Etiam ullamcorper massa vel nisl sagittis, nec bibendum arcu malesuada. Aenean aliquet turpis justo, a consectetur arcu mollis convallis. Etiam tellus ipsum, ultricies vitae lorem et, ornare facilisis orci. Praesent fringilla justo urna, vel mollis neque pulvinar vestibulum. + +Donec non iaculis erat. Aliquam et mi sed nunc pulvinar ultricies in ut ipsum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Praesent feugiat lacus ac dignissim semper. Phasellus vitae quam nisi. Morbi vel diam ultricies risus lobortis ornare. Fusce maximus et ligula quis iaculis. Sed congue ex eget felis convallis, sit amet hendrerit elit tempor. Donec vehicula blandit ante eget commodo. Vestibulum eleifend diam at feugiat euismod. Etiam magna tellus, dignissim eget fermentum vel, vestibulum vitae mauris. Nam accumsan et erat id sagittis. Donec lacinia, odio ut ornare ultricies, dolor velit accumsan tortor, non finibus erat tellus quis ligula. Nunc quis metus in leo volutpat ornare vulputate eu nisl. + +Donec quis viverra ex. Nullam id feugiat mauris, eu fringilla nulla. Vestibulum id maximus elit. Cras elementum elit sed felis lobortis, eget sagittis nisi hendrerit. Vivamus vitae elit neque. Donec vulputate lacus ut libero ultrices accumsan. Vivamus accumsan nulla orci, in dignissim est laoreet sagittis. Proin at commodo velit. Curabitur in velit felis. Aliquam erat volutpat. Sed consequat, nulla et cursus sodales, nisi lacus mattis risus, quis eleifend erat ex nec turpis. Sed suscipit ultrices lorem in hendrerit. + +Morbi vitae lacus nec libero ornare tempus eu et diam. Suspendisse magna ipsum, fermentum vel odio quis, molestie aliquam urna. Fusce mollis turpis a eros accumsan porttitor. Pellentesque rhoncus dolor sit amet magna rutrum, et dapibus justo tempor. Sed purus nisi, maximus vitae fringilla eu, molestie nec urna. Fusce malesuada finibus pretium. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec sed aliquet eros. Pellentesque luctus diam ante, eget euismod nisl aliquet eu. Sed accumsan elit purus, tempor varius ligula tempus nec. Curabitur ornare leo suscipit suscipit fermentum. Morbi eget nulla est. Maecenas faucibus interdum tristique. + +Etiam ut elit eros. Nulla pharetra suscipit molestie. Nulla facilisis bibendum nisl non molestie. Curabitur turpis lectus, facilisis vel diam non, vulputate ultrices mauris. Aenean placerat aliquam convallis. Suspendisse sed scelerisque tellus. Vivamus lacinia neque eget risus cursus suscipit. Proin consequat dolor vel neque tempor, eu aliquam sem scelerisque. Duis non eros a purus malesuada pharetra non et nulla. Suspendisse potenti. Mauris libero eros, finibus vel nulla id, sagittis dapibus ante. Proin iaculis sed nunc et cursus. + +Quisque accumsan lorem sit amet lorem aliquet euismod. Curabitur fermentum rutrum posuere. Etiam ultricies, sem id pellentesque suscipit, urna magna lacinia eros, quis efficitur risus nisl at lacus. Nulla quis lacus tortor. Mauris placerat ex in dolor tincidunt, vel aliquet nisi pretium. Cras iaculis risus vitae pellentesque aliquet. Quisque a enim imperdiet, ullamcorper arcu vitae, rutrum risus. Nullam consectetur libero at felis fringilla, nec congue nibh dignissim. Nam et lobortis felis, eu pellentesque ligula. Aenean facilisis, ligula non imperdiet maximus, massa orci gravida sapien, at sagittis lacus nisl in lacus. Nulla quis mauris luctus, scelerisque felis consequat, tempus risus. Fusce auctor nisl non nulla luctus molestie. Maecenas sapien nisl, auctor non dolor et, iaculis scelerisque lorem. Suspendisse egestas enim aliquet, accumsan mauris nec, posuere quam. Nulla iaculis dui dui, sit amet vestibulum erat ultricies ac. + +Cras eget dolor erat. Proin at nisl ut leo consectetur ultricies vel ut arcu. Nulla in felis malesuada, ullamcorper tortor et, convallis massa. Nunc urna justo, ornare in nibh vitae, hendrerit condimentum libero. Etiam vitae libero in purus venenatis fringilla. Nullam velit nulla, consequat ut turpis non, egestas hendrerit nibh. Duis tortor turpis, interdum non ante ac, cursus accumsan lectus. Cras pharetra bibendum augue quis dictum. Sed euismod vestibulum justo. Proin porta lobortis purus. Duis venenatis diam tortor, sit amet condimentum eros rhoncus a. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc at magna nec diam lobortis efficitur sit amet ut lacus. Nulla quis orci tortor. Pellentesque tempus velit a odio finibus porta. + +Proin feugiat mauris a tellus scelerisque convallis. Maecenas libero magna, blandit nec ultrices id, congue vel mi. Aliquam lacinia, quam vel condimentum convallis, tortor turpis aliquam odio, sed blandit libero lacus et eros. In eleifend iaculis magna ac finibus. Praesent auctor facilisis tellus in congue. Sed molestie lobortis dictum. Nam quis dignissim augue, vel euismod lorem. Curabitur posuere dapibus luctus. Donec ultricies dictum lectus, quis blandit arcu commodo ac. Aenean tincidunt ligula in nunc imperdiet dignissim. Curabitur egestas sollicitudin sapien ut semper. Aenean nec dignissim lacus. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec aliquam dictum vehicula. Donec tortor est, volutpat non nisi nec, varius gravida ex. Nunc vel tristique nunc, vitae mattis nisi. Nunc nec luctus ex, vitae tincidunt lectus. In hac habitasse platea dictumst. Curabitur lobortis ex eget tincidunt tempor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut a vehicula mi. + +Fusce eu libero finibus, interdum nulla a, placerat neque. Cras bibendum tempor libero nec feugiat. Cras ut sodales eros. Proin viverra, massa sit amet viverra egestas, neque nisl porta ex, sit amet hendrerit libero ligula vel urna. Mauris suscipit lacus id justo rhoncus suscipit. Etiam vel libero tellus. Maecenas non diam molestie, condimentum tellus a, bibendum enim. Mauris aliquet imperdiet tellus, eget sagittis dolor. Sed blandit in neque et luctus. Cras elementum sagittis nunc, vel mollis lorem euismod et. Donec posuere at lacus eget suscipit. + +Nulla nunc mi, pretium non massa vel, tempor semper magna. Nunc a leo pulvinar, tincidunt nunc at, dignissim mi. Aliquam erat volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut viverra nulla a nisl finibus, at hendrerit ligula ullamcorper. Donec a lorem semper, tempor magna et, lobortis libero. Mauris id sapien leo. Donec dignissim, quam vitae porttitor dignissim, quam justo mattis dui, vel consequat odio elit quis orci. Etiam nec pretium neque, sit amet pretium orci. Duis ac tortor venenatis, feugiat purus non, feugiat nunc. Proin scelerisque nisl in turpis aliquam vulputate. + +Praesent sed est semper, fringilla lorem vitae, tincidunt nibh. Cras eros metus, auctor at mauris sit amet, sodales semper orci. Nunc a ornare ex. Curabitur bibendum arcu congue urna vulputate egestas. Vestibulum finibus id risus et accumsan. Aenean ut volutpat tellus. Aenean tincidunt malesuada urna sit amet vestibulum. Mauris vel tellus dictum, varius lacus quis, dictum arcu. + +Aenean quis metus eu erat feugiat cursus vel at ligula. Proin dapibus sodales urna, id euismod lectus tempus id. Pellentesque ex ligula, convallis et erat vel, vulputate condimentum nisl. Pellentesque pharetra nulla quis massa eleifend hendrerit. Praesent sed massa ipsum. Maecenas vehicula dolor massa, id sodales urna faucibus et. Mauris ac quam non massa tincidunt feugiat et at lacus. Fusce libero massa, vulputate vel scelerisque non, mollis in leo. Ut sit amet ultricies odio. Suspendisse in sapien viverra, facilisis purus ut, pretium libero. + +Vivamus tristique pharetra molestie. Nam a volutpat purus. Praesent consequat gravida nisi, ac blandit nisi suscipit ut. Quisque posuere, ligula a ultrices laoreet, ligula nunc vulputate libero, ut rutrum erat odio tincidunt justo. Sed vitae leo at leo fringilla bibendum. Vestibulum ut augue nec dolor auctor accumsan. Praesent laoreet id eros pulvinar commodo. Suspendisse potenti. Ut pharetra, mauris vitae blandit fringilla, odio ante tincidunt lorem, sit amet tempor metus diam ut turpis. + +Praesent quis egestas arcu. Nullam at porta arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi vulputate ligula malesuada ligula luctus, vulputate tempus erat bibendum. Nunc ullamcorper non lectus at euismod. Etiam nibh felis, tincidunt a metus vel, pellentesque rhoncus neque. Etiam at diam in erat luctus interdum. Nunc vel ipsum pulvinar, sollicitudin lacus ac, tempus urna. Etiam vel lacinia sapien. Pellentesque sagittis velit vel mi efficitur iaculis. Integer euismod sit amet urna in sagittis. Cras eleifend ut nibh in facilisis. Donec et lacus vitae nunc placerat sodales. Nulla sed hendrerit ligula, at dapibus sapien. + +Praesent at iaculis ex. Curabitur est purus, cursus a faucibus quis, dictum id velit. Donec dignissim fringilla viverra. Nunc mauris felis, laoreet sit amet sagittis at, vestibulum in libero. Maecenas quis orci turpis. Quisque ut nibh vitae magna mollis consequat id at mauris. Aliquam eu odio eget nulla bibendum sodales. Quisque vel orci eleifend nisi pretium lacinia. Suspendisse eget risus eget mi volutpat molestie eget quis lacus. Duis nisi libero, tincidunt nec nulla id, faucibus cursus felis. + +Donec tempor eget risus pellentesque molestie. Phasellus porta neque vel arcu egestas, nec blandit velit fringilla. Nullam porta faucibus justo vitae laoreet. Pellentesque viverra id nunc eu varius. Nulla pulvinar lobortis iaculis. Etiam vestibulum odio nec velit tristique, a tristique nisi mattis. In sed fringilla orci, vitae efficitur odio. Quisque dui odio, ornare eget velit at, lacinia consequat libero. Quisque lectus nulla, aliquet eu leo in, porta rutrum diam. Donec nec mattis neque. Nam rutrum, odio ac eleifend bibendum, dolor arcu rutrum neque, eget porta elit tellus a lacus. Sed massa metus, sollicitudin et sapien eu, finibus tempus orci. Proin et sapien sit amet erat molestie interdum. In quis rutrum velit, faucibus ultrices tellus. + +Sed sagittis sed justo eget tincidunt. Maecenas ut leo sagittis, feugiat magna et, viverra velit. Maecenas ex arcu, feugiat at consequat vitae, auctor eu massa. Integer egestas, enim vitae maximus convallis, est lectus pretium mauris, ac posuere lectus nisl quis quam. Aliquam tempus laoreet mi, vitae dapibus dolor varius dapibus. Suspendisse potenti. Donec sit amet purus nec libero dapibus tristique. Pellentesque viverra bibendum ligula. Donec sed felis et ex lobortis laoreet. Phasellus a fringilla libero, vitae malesuada nulla. Pellentesque blandit mattis lacus, et blandit tortor laoreet consequat. Suspendisse libero nunc, viverra sed fermentum in, accumsan egestas arcu. Proin in placerat elit. Sed interdum imperdiet malesuada. Suspendisse aliquet quis mauris eget sollicitudin. + +Vivamus accumsan tellus non erat volutpat, quis dictum dolor feugiat. Praesent rutrum nunc ac est mollis cursus. Fusce semper volutpat dui ut egestas. Curabitur sit amet posuere massa. Cras tincidunt nulla et mi mollis imperdiet. Suspendisse scelerisque ex id sodales vulputate. In nunc augue, pharetra in placerat eu, mattis id tellus. Vivamus cursus efficitur vehicula. Nulla aliquet vehicula aliquet. + +Sed cursus tellus sed porta pulvinar. Sed vitae nisi neque. Nullam aliquet, lorem et efficitur scelerisque, arcu diam aliquam felis, sed pulvinar lorem odio et turpis. Praesent convallis pulvinar turpis eu iaculis. Aliquam nec gravida mi. Curabitur eu nibh tempor, blandit justo in, ultrices felis. Fusce placerat metus non mi sagittis rutrum. Morbi sed dui fringilla, sagittis mauris eget, imperdiet nunc. Phasellus hendrerit sem elit, id hendrerit libero auctor sit amet. Integer sodales elit sit amet consequat cursus. + +Nam semper est eget nunc mollis, in pellentesque lectus fringilla. In finibus vel diam id semper. Nunc mattis quis erat eu consectetur. In hac habitasse platea dictumst. Nullam et ipsum vestibulum ex pulvinar ultricies sit amet id velit. Aenean suscipit mi tortor, a lobortis magna viverra non. Nulla condimentum aliquet ante et ullamcorper. Pellentesque porttitor arcu a posuere tempus. Aenean lacus quam, imperdiet eu justo vitae, pretium efficitur ex. Duis id purus id magna rhoncus ultrices id eu risus. Nunc dignissim et libero id dictum. + +Quisque a tincidunt neque. Phasellus commodo mi sit amet tempor fringilla. Ut rhoncus, neque non porttitor elementum, libero nulla egestas augue, sed fringilla sapien felis ac velit. Phasellus viverra rhoncus mollis. Nam ullamcorper leo vel erat laoreet luctus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus semper a metus a cursus. Nulla sed orci egestas, efficitur purus ac, malesuada tellus. Aenean rutrum velit at tellus fermentum mollis. Aliquam eleifend euismod metus. + +In hac habitasse platea dictumst. Vestibulum volutpat neque vitae porttitor laoreet. Nam at tellus consequat, sodales quam in, pulvinar arcu. Maecenas varius convallis diam, ac lobortis tellus pellentesque quis. Maecenas eget augue massa. Nullam volutpat nibh ac justo rhoncus, ut iaculis tellus rutrum. Fusce efficitur efficitur libero quis condimentum. Curabitur congue neque non tincidunt tristique. Fusce eget tempor ex, at pellentesque odio. Praesent luctus dictum vestibulum. Etiam non orci nunc. Vivamus vitae laoreet purus, a lobortis velit. Curabitur tincidunt purus ac lectus elementum pellentesque. Quisque sed tincidunt est. + +Sed vel ultrices massa, vitae ultricies justo. Cras finibus mauris nec lacus tempus dignissim. Cras faucibus maximus velit, eget faucibus orci luctus vehicula. Nulla massa nunc, porta ac consequat eget, rhoncus non tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce sed maximus metus, vel imperdiet ipsum. Ut scelerisque lectus at blandit porttitor. Ut vulputate nunc pharetra, aliquet sapien ac, sollicitudin sapien. Aenean eget ante lorem. Nam accumsan venenatis tellus id dignissim. + +Curabitur fringilla, magna non maximus dapibus, nulla sapien vestibulum lectus, sit amet semper dolor neque vitae nisl. Nunc ultrices vehicula augue sed iaculis. Maecenas nec diam mollis, suscipit orci et, vestibulum ante. Pellentesque eu nisl tortor. Nunc eleifend, lacus quis volutpat volutpat, nisi mi molestie sem, quis mollis ipsum libero a tellus. Ut viverra dolor mattis convallis interdum. Sed tempus nisl at nunc scelerisque aliquet. Quisque tempor tempor lorem id feugiat. Nullam blandit lectus velit, vitae porta lacus tincidunt a. Vivamus sit amet arcu ultrices, tincidunt mi quis, viverra quam. Aenean fringilla libero elementum lorem semper, quis pulvinar eros gravida. Nullam sodales blandit mauris, sed fermentum velit fermentum sit amet. Donec malesuada mauris in augue sodales vulputate. Vestibulum gravida turpis id elit rhoncus dignissim. Integer non congue lorem, eu viverra orci. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at dolor magna. Aliquam consectetur erat augue, id iaculis velit pharetra ac. Integer rutrum venenatis dignissim. Integer non sodales elit. Curabitur ut magna ut nibh feugiat aliquam ac ut risus. Morbi nibh quam, aliquam id placerat nec, vestibulum eget velit. Suspendisse at dignissim quam. Vivamus aliquet sem sed nisl volutpat, ut cursus orci ultrices. Aliquam ultrices lacinia enim, vitae aliquet neque. + +Quisque scelerisque finibus diam in mattis. Cras cursus auctor velit. Aliquam sem leo, fermentum et maximus et, molestie a libero. Aenean justo elit, rutrum a ornare id, egestas eget enim. Aenean auctor tristique erat. Curabitur condimentum libero lacus, nec consequat orci vestibulum sed. Fusce elit ligula, blandit vitae sapien vitae, dictum ultrices risus. Nam laoreet suscipit sapien, at interdum velit faucibus sit amet. Duis quis metus egestas lectus elementum posuere non nec libero. Aliquam a dolor bibendum, facilisis nunc a, maximus diam. Vestibulum suscipit tristique magna, non dignissim turpis sodales sed. Nunc ornare, velit ac facilisis fringilla, dolor mi consectetur lorem, vitae finibus erat justo suscipit urna. Maecenas sit amet eros erat. Nunc non arcu ornare, suscipit lorem eget, sodales mauris. Aliquam tincidunt, quam nec mollis lacinia, nisi orci fermentum libero, consequat eleifend lectus quam et sapien. Vestibulum a quam urna. + +Cras arcu leo, euismod ac ullamcorper at, faucibus sed massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus porttitor velit in enim interdum, non commodo metus ornare. Morbi vel lorem quis nisl luctus tristique quis vitae nisl. Suspendisse condimentum tortor enim, nec eleifend ipsum euismod et. Sed gravida quam ut tristique lacinia. Mauris eu interdum ipsum, ac ultrices odio. Nullam auctor tellus a risus porttitor vehicula. Nulla blandit euismod dictum. In pharetra, enim iaculis pulvinar interdum, dui nunc placerat nunc, sit amet pretium lectus nulla vitae quam. Phasellus quis enim sollicitudin, varius nulla id, ornare purus. Donec quam lacus, vestibulum quis nunc ac, mollis dictum nisi. Cras ut mollis elit. Maecenas ultrices ligula at risus faucibus scelerisque. Etiam vitae porttitor purus. Curabitur blandit lectus urna, ut hendrerit tortor feugiat ut. + +Phasellus fringilla, sapien pellentesque commodo pharetra, ante libero aliquam tellus, ut consectetur augue libero a sapien. Maecenas blandit luctus nisl eget aliquet. Maecenas vitae porta dolor, faucibus laoreet sapien. Suspendisse lobortis, ipsum sed vehicula aliquam, elit purus scelerisque dui, rutrum consectetur diam odio et lorem. In nec lacinia metus. Donec viverra libero est, vel bibendum erat condimentum quis. Donec feugiat purus leo. In laoreet vitae felis a porttitor. Mauris ullamcorper, lacus id condimentum suscipit, neque magna pellentesque arcu, eget cursus neque tellus id metus. Curabitur volutpat ac orci vel ultricies. + +Sed ut finibus erat. Sed diam purus, varius non tincidunt quis, ultrices sit amet ipsum. Donec et egestas nulla. Suspendisse placerat nisi at dui laoreet iaculis. Aliquam aliquet leo at augue faucibus molestie. Nullam lacus augue, hendrerit sed nisi eu, faucibus porta est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam ut leo aliquet sem fermentum rutrum quis ac justo. Integer placerat aliquam nisl ut sagittis. Proin erat orci, lobortis et sem eget, eleifend fringilla augue. Mauris varius laoreet arcu, sed tincidunt felis. Pellentesque venenatis lorem odio, id pulvinar velit molestie feugiat. Donec mattis lacus sed eleifend pulvinar. + +Sed condimentum ex in tincidunt hendrerit. Etiam eget risus lacinia, euismod nibh eu, pellentesque quam. Proin elit eros, convallis id mauris ac, bibendum ultrices lectus. Morbi venenatis, purus id fermentum consequat, nunc libero tincidunt ligula, non dictum ligula orci nec quam. Nulla nec ultrices lorem. Aenean maximus augue vel dictum pharetra. Etiam turpis urna, pellentesque quis malesuada eu, molestie faucibus felis. + +Vestibulum pharetra augue ut quam blandit congue in nec risus. Proin eu nibh eu dui eleifend porta vitae id lectus. Proin lacus nibh, lobortis sed ligula vitae, interdum lobortis erat. Suspendisse potenti. In sollicitudin quis sapien ut aliquet. Mauris ac nulla arcu. Fusce tristique justo quis lectus mollis, eu volutpat lectus finibus. Vivamus venenatis facilisis ex ut vestibulum. + +Etiam varius lobortis purus, in hendrerit elit tristique at. In tempus, augue vestibulum fermentum gravida, ligula tellus vulputate arcu, eu molestie ex sapien at purus. Vestibulum nec egestas metus. Duis pulvinar quam nec consequat interdum. Aenean non dapibus lacus. Aliquam sit amet aliquet nulla. Sed venenatis volutpat purus nec convallis. Phasellus aliquet semper sodales. Cras risus sapien, condimentum auctor urna a, pulvinar ornare nisl. Sed tincidunt felis elit, ut elementum est bibendum ac. Morbi interdum justo vel dui faucibus condimentum. + +Sed convallis eu sem at tincidunt. Nullam at auctor est, et ullamcorper ipsum. Pellentesque eget ante ante. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer euismod, sapien sed dapibus ornare, nibh enim maximus lacus, lacinia placerat urna quam quis felis. Morbi accumsan id nisl ut condimentum. Donec bibendum nisi est, sed volutpat lorem rhoncus in. Vestibulum ac lacinia nunc, eget volutpat magna. Integer aliquam pharetra ipsum, id placerat nunc volutpat quis. Etiam urna diam, rhoncus sit amet varius vel, euismod vel sem. Nullam vel molestie urna. Vivamus ornare erat at venenatis euismod. Suspendisse potenti. Fusce diam justo, tincidunt vel sem at, commodo faucibus nisl. Duis gravida efficitur diam, vel sagittis erat pulvinar ut. + +Quisque vel pharetra felis. Duis efficitur tortor dolor, vitae porttitor erat fermentum sed. Sed eu mi purus. Etiam dignissim tortor eu tempus molestie. Aenean pretium erat enim, in hendrerit ante hendrerit at. Sed ut risus vel nunc venenatis ultricies quis in lacus. Pellentesque vitae purus euismod, placerat risus non, ullamcorper augue. Quisque varius quam ligula, nec aliquet ex faucibus vitae. Quisque rhoncus sit amet leo tincidunt mattis. Cras id mauris eget purus pretium gravida sit amet eu augue. Aliquam dapibus odio augue, id lacinia velit pulvinar eu. + +Mauris fringilla, tellus nec pharetra iaculis, neque nisi ultrices massa, et tincidunt sem dui sed mi. Curabitur erat lorem, venenatis quis tempus lacinia, tempus sit amet nunc. Aliquam at neque ac metus commodo dictum quis vitae justo. Phasellus eget lacus tempus, blandit lorem vel, rutrum est. Aenean pharetra sem ut augue lobortis dignissim. Sed rhoncus at nulla id ultrices. Cras id condimentum felis. In suscipit luctus vulputate. Donec tincidunt lacus nec enim tincidunt sollicitudin ut quis enim. Nam at libero urna. Praesent sit amet massa vitae massa ullamcorper vehicula. + +Nullam bibendum augue ut turpis condimentum bibendum. Proin sit amet urna hendrerit, sodales tortor a, lobortis lectus. Integer sagittis velit turpis, et tincidunt nisi commodo eget. Duis tincidunt elit finibus accumsan cursus. Aenean dignissim scelerisque felis vel lacinia. Nunc lacinia maximus luctus. In hac habitasse platea dictumst. Vestibulum eget urna et enim tempor tempor. Nam feugiat, felis vel vestibulum tempus, orci justo viverra diam, id dapibus lorem justo in ligula. + +Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In ac pellentesque sem. Vestibulum lacinia magna dui, eu lacinia augue placerat et. Maecenas pulvinar congue est. Pellentesque commodo dui non pulvinar scelerisque. Etiam interdum est posuere sem bibendum, ac commodo magna dictum. Cras ipsum turpis, rhoncus nec posuere vitae, laoreet a arcu. Integer ac massa sit amet enim placerat lacinia sed ultrices arcu. Suspendisse sem nibh, luctus sit amet volutpat in, pellentesque eu metus. Ut gravida neque eget mi accumsan tempus. Nam sit amet aliquet nibh. + +Pellentesque a purus cursus nulla hendrerit congue quis et odio. Aenean hendrerit, leo ullamcorper sagittis hendrerit, erat dui molestie quam, sed condimentum lacus risus sed tellus. Morbi a dapibus lectus, ut feugiat ex. Phasellus pretium quam et sapien mollis, vel iaculis dui dignissim. Sed ullamcorper est turpis, a viverra lorem consectetur in. Aenean aliquet nibh non cursus rutrum. Suspendisse at tristique urna, id lobortis urna. In hac habitasse platea dictumst. Phasellus libero velit, rutrum sed tellus nec, dapibus tincidunt ligula. Quisque vel dui venenatis, consequat nisl ut, lacinia ipsum. Phasellus vitae magna pellentesque, lobortis est id, faucibus quam. Nam eleifend faucibus dui vel pellentesque. + +Etiam ut est non lacus tincidunt interdum. Maecenas sed massa urna. Quisque ut nibh tortor. Pellentesque felis ipsum, tempor finibus ipsum et, euismod pretium metus. Donec sit amet est ipsum. Quisque rhoncus justo non finibus elementum. Nulla nec lectus ac tortor placerat fringilla. Phasellus ac ultrices nunc, eu efficitur nisl. Nulla rhoncus nunc vitae ante dictum tincidunt. Nunc ultrices, massa sit amet malesuada dignissim, lectus lacus consequat sapien, non eleifend metus sem in eros. Phasellus mauris ante, dictum sit amet suscipit ac, rhoncus eget nisi. Phasellus at orci mollis, imperdiet neque eget, faucibus nulla. In at purus massa. Pellentesque quis rutrum lectus. + +Integer eu faucibus turpis, sit amet mollis massa. Vestibulum id nulla commodo, rutrum ipsum sed, semper ante. Phasellus condimentum orci nec nibh convallis, ac maximus orci ullamcorper. Maecenas vitae sollicitudin mi. Integer et finibus lectus, et condimentum ligula. Donec elementum tristique quam vitae dapibus. Morbi euismod ipsum in tristique ullamcorper. + +Duis fermentum non enim eu auctor. Quisque lacinia nibh vehicula nibh posuere, eu volutpat turpis facilisis. Ut ac faucibus nulla. Sed eleifend quis ex et pellentesque. Vestibulum sollicitudin in libero id fringilla. Phasellus dignissim purus consequat, condimentum dui sit amet, condimentum ante. Pellentesque ac consectetur massa, quis sagittis est. Nulla maximus tristique risus accumsan convallis. Curabitur imperdiet ac lacus a ultrices. Nulla facilisi. Sed quis quam quis lectus placerat lobortis vel sed turpis. In mollis dui id neque iaculis, ut aliquet tellus malesuada. Proin at luctus odio, vel blandit sapien. Praesent dignissim tortor vehicula libero fringilla, nec ultrices erat suscipit. Maecenas scelerisque purus in dapibus fermentum. + +Curabitur magna odio, mattis in tortor ut, porttitor congue est. Vestibulum mollis lacinia elementum. Fusce maximus erat vitae nunc rutrum lobortis. Integer ligula eros, auctor vel elit non, posuere luctus lacus. Maecenas quis auctor massa. Ut ipsum lacus, efficitur posuere euismod et, hendrerit efficitur est. Phasellus fringilla, quam id tincidunt pretium, nunc dui sollicitudin orci, eu dignissim nisi metus ut magna. Integer lobortis interdum dolor, non bibendum purus posuere et. Donec non lectus aliquet, pretium dolor eu, cursus massa. Sed ut dui sapien. In sed vestibulum massa. Pellentesque blandit, dui non sodales vehicula, orci metus mollis nunc, non pharetra ex tellus ac est. Mauris sagittis metus et fermentum pretium. Nulla facilisi. Quisque quis ante ut nulla placerat mattis ut quis nisi. + +Sed quis nulla ligula. Quisque dignissim ligula urna, sed aliquam purus semper at. Suspendisse potenti. Nunc massa lectus, pharetra vehicula arcu bibendum, imperdiet sodales ipsum. Nam ac sapien diam. Mauris iaculis fringilla mattis. Pellentesque tempus eros sit amet justo volutpat mollis. Phasellus ac turpis ipsum. Morbi vel ante elit. Aenean posuere quam consequat velit varius suscipit. Donec tempor quam ut nibh cursus efficitur. + +Morbi molestie dolor nec sem egestas suscipit. Etiam placerat pharetra lectus, et ullamcorper risus tristique in. Sed faucibus ullamcorper lectus eget fringilla. Maecenas malesuada hendrerit congue. Sed eget neque a erat placerat tincidunt. Aliquam vitae dignissim turpis. Fusce at placerat magna, a laoreet lectus. Maecenas a purus nec diam gravida fringilla. Nam malesuada euismod ante non vehicula. In faucibus bibendum leo, faucibus posuere nisl pretium quis. Fusce finibus bibendum finibus. Vestibulum eu justo maximus, hendrerit diam nec, dignissim sapien. Aenean dolor lacus, malesuada quis vestibulum ac, venenatis ac ipsum. Cras a est id nunc finibus facilisis. Cras lacinia neque et interdum vehicula. Suspendisse vulputate tellus elit, eget tempor dui finibus vel. + +Cras sed pretium odio. Proin hendrerit elementum felis in tincidunt. Nam sed turpis vel justo molestie accumsan condimentum eu nunc. Praesent lobortis euismod rhoncus. Nulla vitae euismod nibh, quis mattis mi. Fusce ultrices placerat porttitor. Duis sem ipsum, pellentesque sit amet odio a, molestie vulputate mauris. + +Duis blandit mollis ligula, sit amet mattis ligula finibus sit amet. Nunc a leo molestie, placerat diam et, vestibulum leo. Suspendisse facilisis neque purus, nec pellentesque ligula fermentum nec. Aenean malesuada mauris lorem, eu blandit arcu pulvinar quis. Duis laoreet urna lacus, non maximus arcu rutrum ultricies. Nulla augue dolor, suscipit eu mollis eu, aliquam condimentum diam. Ut semper orci luctus, pharetra turpis at, euismod mi. Nulla leo diam, finibus sit amet purus sed, maximus dictum lorem. Integer eu mi id turpis laoreet rhoncus. + +Integer a mauris tincidunt, finibus orci ut, pretium mauris. Nulla molestie nunc mi, id finibus lorem elementum sed. Proin quis laoreet ante. Integer nulla augue, commodo id molestie quis, rutrum ut turpis. Suspendisse et tortor turpis. Sed ut pharetra massa. Pellentesque elementum blandit sem, ut elementum tellus egestas a. Fusce eu purus nibh. + +Cras dignissim ligula scelerisque magna faucibus ullamcorper. Proin at condimentum risus, auctor malesuada quam. Nullam interdum interdum egestas. Nulla aliquam nisi vitae felis mollis dictum. Suspendisse dapibus consectetur tortor. Ut ut nisi non sem bibendum tincidunt. Vivamus suscipit leo quis gravida dignissim. + +Aliquam interdum, leo id vehicula mollis, eros eros rhoncus diam, non mollis ligula mi eu mauris. Sed ultrices vel velit sollicitudin tincidunt. Nunc auctor metus at ligula gravida elementum. Praesent interdum eu elit et mollis. Duis egestas quam sit amet velit dignissim consequat. Aliquam ac turpis nec nunc convallis sagittis. Fusce blandit, erat ac fringilla consectetur, dolor eros sodales leo, vel aliquet risus nisl et diam. Aliquam luctus felis vitae est eleifend euismod facilisis et lacus. Sed leo tellus, auctor eu arcu in, volutpat sagittis nisl. Pellentesque nisl ligula, placerat vel ullamcorper at, vulputate ac odio. Morbi ac faucibus orci, et tempus nulla. Proin rhoncus rutrum dolor, in venenatis mauris. Suspendisse a fermentum augue, non semper mi. Nunc eget pretium neque. Phasellus augue erat, feugiat ac aliquam congue, rutrum non sapien. Pellentesque ac diam gravida, consectetur felis at, ornare neque. + +Nullam interdum mattis sapien quis porttitor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus aliquet rutrum ipsum id euismod. Maecenas consectetur massa et mi porta viverra. Nunc quam nibh, dignissim vitae maximus et, ullamcorper nec lorem. Nunc vitae justo dapibus, luctus lacus vitae, pretium elit. Maecenas et efficitur leo. Curabitur mauris lectus, placerat quis vehicula vitae, auctor ut urna. Quisque rhoncus pharetra luctus. In hac habitasse platea dictumst. Integer sit amet metus nec eros malesuada aliquam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi hendrerit mi ac leo aliquam, sit amet ultricies libero commodo. Mauris dapibus purus metus, sit amet viverra nibh imperdiet et. Nullam porta nulla tellus, quis vehicula diam imperdiet non. Vivamus enim massa, bibendum in fermentum in, ultrices at ex. + +Suspendisse fermentum id nibh eget accumsan. Duis dapibus bibendum erat ut sollicitudin. Aliquam nec felis risus. Pellentesque rhoncus ligula id sem maximus mollis sed nec massa. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ipsum ipsum, sodales sed enim id, convallis faucibus eros. Donec ultricies dictum tincidunt. Cras vitae nibh arcu. Pellentesque cursus, sapien nec consequat fermentum, ipsum ante suscipit dui, imperdiet hendrerit est nisl eu massa. Quisque vitae sem ligula. Aenean iaculis metus ut mauris interdum laoreet. Vivamus sed gravida dolor. + +Morbi nulla metus, porttitor sed eros sit amet, efficitur efficitur est. In vel nisl urna. Ut aliquet tellus at congue convallis. Phasellus imperdiet lobortis sollicitudin. Integer sodales, sem eu ultricies pharetra, erat erat porttitor odio, eget dapibus libero ipsum eget velit. Phasellus gravida nulla nisl, eu pharetra mi auctor vel. Sed blandit pharetra velit, ut egestas libero placerat non. Aliquam a interdum quam. Proin at tortor nec dui sollicitudin tempus sed vestibulum elit. Nunc non sollicitudin velit. + +Aenean consequat diam velit, sed rutrum tortor faucibus dictum. Quisque at semper augue. Duis ut est eget mi ornare bibendum id et ligula. Phasellus consequat tortor non leo pulvinar posuere. Proin vestibulum eleifend felis, in hendrerit tortor sollicitudin eu. Phasellus hendrerit, lacus vel laoreet interdum, dui tortor consequat justo, commodo ultricies arcu felis vitae enim. Vivamus eu sapien at leo suscipit rutrum eu at justo. Aenean et dolor a libero ullamcorper posuere. Integer laoreet placerat nisi in vulputate. Mauris laoreet eget risus sed cursus. Donec scelerisque neque a libero eleifend hendrerit. Nulla varius condimentum nunc sit amet fermentum. Aliquam lorem ex, varius nec mollis ut, ultrices in neque. Morbi sit amet porta leo. Integer iaculis fermentum lacus in vestibulum. + +Ut gravida, tellus ut maximus ultrices, erat est venenatis nisl, vitae pretium massa ex ac magna. Sed non purus eget ligula aliquet volutpat non quis arcu. Nam aliquam tincidunt risus, sit amet fringilla sapien vulputate ut. Mauris luctus suscipit pellentesque. Nunc porttitor dapibus ex quis tempus. Ut ullamcorper metus a eros vulputate, vitae viverra lectus convallis. Mauris semper imperdiet augue quis tincidunt. Integer porta pretium magna, sed cursus sem scelerisque sollicitudin. Nam efficitur, nibh pretium eleifend vestibulum, purus diam posuere sem, in egestas mauris augue sit amet urna. + +Vestibulum tincidunt euismod massa in congue. Duis interdum metus non laoreet fringilla. Donec at ligula congue, tincidunt nunc non, scelerisque nunc. Donec bibendum magna non est scelerisque feugiat at nec neque. Ut orci tortor, tempus eget massa non, dignissim faucibus dolor. Nam odio risus, accumsan pretium neque eget, accumsan dignissim dui. In ut neque auctor, scelerisque tellus sed, ullamcorper nisi. Suspendisse varius cursus quam at hendrerit. Vivamus elit libero, sagittis vitae sem ac, vulputate iaculis ligula. + +Sed lobortis laoreet purus sit amet rutrum. Pellentesque feugiat non leo vel lacinia. Quisque feugiat nisl a orci bibendum vestibulum. In et sollicitudin urna. Morbi a arcu ac metus faucibus tempus. Nam eu imperdiet sapien, suscipit mattis tortor. Aenean blandit ipsum nisi, a eleifend ligula euismod at. Integer tincidunt pharetra felis, mollis placerat mauris hendrerit at. Curabitur convallis, est sit amet luctus volutpat, massa lacus cursus augue, sed eleifend magna quam et risus. Aliquam lobortis tincidunt metus vitae porttitor. Suspendisse potenti. Aenean ullamcorper, neque id commodo luctus, nulla nunc lobortis quam, id dapibus neque dui nec mauris. Etiam quis lorem quis elit commodo ornare. Ut pharetra purus ultricies enim ultrices efficitur. Proin vehicula tincidunt molestie. Mauris et placerat sem. + +Aliquam erat volutpat. Suspendisse velit turpis, posuere ac lacus eu, lacinia laoreet velit. Sed interdum felis neque, id blandit sem malesuada sit amet. Ut sagittis justo erat, efficitur semper orci tempor sed. Donec enim massa, posuere varius lectus egestas, pellentesque posuere mi. Cras tincidunt ut libero sed mattis. Suspendisse quis magna et tellus posuere interdum vel at purus. Pellentesque fringilla tristique neque, id aliquet tellus ultricies non. Duis ut tellus vel odio lobortis vulputate. + +Integer at magna ac erat convallis vestibulum. Sed lobortis porttitor mauris. Fusce varius lorem et volutpat pulvinar. Aenean ac vulputate lectus, vitae consequat velit. Suspendisse ex dui, varius ut risus ut, dictum scelerisque sem. Vivamus urna orci, volutpat ut convallis ac, venenatis vitae urna. In hac habitasse platea dictumst. Etiam eu purus arcu. Aenean vulputate leo urna, vel tristique dui sagittis euismod. Suspendisse non tellus efficitur ante rhoncus volutpat at et sapien. + +Sed dapibus accumsan porttitor. Phasellus facilisis lectus finibus ligula dignissim, id pulvinar lectus feugiat. Nullam egestas commodo nisi posuere aliquet. Morbi sit amet tortor sagittis, rutrum dui nec, dapibus sapien. Sed posuere tortor tortor, interdum auctor magna varius vitae. Vestibulum id sagittis augue. Curabitur fermentum arcu sem, eu condimentum quam rutrum non. Phasellus rutrum nibh quis lectus rhoncus pretium. Curabitur dictum interdum elit. Vestibulum maximus sodales imperdiet. Mauris auctor nec purus sed venenatis. In in urna purus. + +Duis placerat molestie suscipit. Morbi a elit id purus efficitur consequat. Nunc ac commodo turpis. Etiam sit amet lacus a ipsum tempus venenatis sed vel nibh. Duis elementum aliquam mi sed tristique. Morbi ligula tortor, semper ac est vel, lobortis maximus erat. Curabitur ipsum felis, laoreet vel condimentum eget, ullamcorper sit amet mauris. Nulla facilisi. Nam at purus sed mi egestas placerat vitae vel magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse at dignissim diam. Phasellus consectetur eget neque vel viverra. Donec sollicitudin mattis dolor vel malesuada. Vivamus vehicula leo neque, vitae fermentum leo posuere et. Praesent dui est, finibus sit amet tristique quis, pharetra vel nibh. + +Duis nulla leo, accumsan eu odio eget, sagittis semper orci. Quisque ullamcorper ligula quam, commodo porttitor mauris ullamcorper eu. Cras varius sagittis felis in aliquam. Duis sodales risus ac justo vehicula, nec mattis diam lacinia. Cras eget lectus ipsum. Ut commodo, enim vitae malesuada hendrerit, ex dolor egestas lectus, sit amet hendrerit metus diam nec est. Vestibulum tortor metus, lobortis sit amet ante eget, tempor molestie lacus. In molestie et urna et semper. Mauris mollis, sem non hendrerit condimentum, sapien nisi cursus est, non suscipit quam justo non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam enim est, porta ac feugiat vitae, rutrum in lorem. Duis vehicula tortor ut posuere maximus. + +Nullam vestibulum non tellus sed commodo. Quisque mattis elit sit amet sapien sollicitudin, ut condimentum nisl congue. Aenean sagittis massa vel elit faucibus fermentum. Donec tincidunt nisi nec nisl sodales pellentesque. Mauris congue congue ligula ut suscipit. Vivamus velit tortor, tempor et gravida eget, fermentum sit amet ante. Nullam fringilla, lorem at ultrices cursus, urna neque ornare dolor, eu lacinia orci enim sed nibh. Ut a ullamcorper lectus, id mattis purus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean maximus sollicitudin posuere. Nunc at augue lacus. Aenean efficitur leo sit amet lacinia efficitur. + +Quisque venenatis quam mi, in pharetra odio vulputate eu. In vel nisl pulvinar, pulvinar ligula ut, sodales risus. Sed efficitur lectus at vestibulum tincidunt. Vestibulum eu ullamcorper elit. Fusce vestibulum magna enim, et tempor lacus posuere vitae. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer leo elit, luctus nec mattis sit amet, sollicitudin in turpis. + +Proin convallis venenatis leo, vitae tristique erat iaculis nec. Nulla facilisi. Duis porttitor, sapien et bibendum vulputate, sem libero sodales lacus, non malesuada felis erat ut libero. Nam non felis semper, finibus est a, mattis mauris. Praesent nec eros quam. Nulla hendrerit, augue consectetur eleifend ultricies, purus mi condimentum nulla, eget dapibus est nunc sed libero. Nullam elementum dui erat, vitae luctus libero sollicitudin et. Nulla odio magna, placerat in augue eu, dapibus imperdiet odio. Suspendisse imperdiet metus sit amet rhoncus dapibus. Cras at enim et urna vehicula cursus eu a mauris. Integer magna ante, eleifend ac placerat vitae, porta at nisi. Cras eget malesuada orci. Curabitur nunc est, vulputate id viverra et, dignissim sed odio. Curabitur non mattis sem. Sed bibendum, turpis vitae vehicula faucibus, nunc quam ultricies lectus, vitae viverra felis turpis at libero. + +Nullam ut egestas ligula. Proin hendrerit justo a lectus commodo venenatis. Nulla facilisi. Ut cursus lorem quis est bibendum condimentum. Aenean in tristique odio. Fusce tempor hendrerit ipsum. Curabitur mollis felis justo, quis dapibus erat auctor vel. Sed augue lectus, finibus ut urna quis, ullamcorper vestibulum dui. Etiam molestie aliquam tempor. Integer mattis sollicitudin erat, et tristique elit varius vel. Mauris a ex justo. + +Nam eros est, imperdiet non volutpat rutrum, pellentesque accumsan ligula. Duis sit amet turpis metus. Aenean in rhoncus metus, ac fringilla ex. Suspendisse condimentum egestas purus, ut pharetra odio vulputate vel. Duis tincidunt massa a placerat ultrices. Mauris ultricies nibh sit amet condimentum malesuada. Duis tincidunt id ipsum sed congue. + +Praesent eu ex augue. Nullam in porta ligula. In tincidunt accumsan arcu, in pellentesque magna tristique in. Mauris eleifend libero ac nisl viverra faucibus. Nam sollicitudin dolor in commodo hendrerit. Cras at orci metus. Ut quis laoreet orci. Vivamus ultrices leo pellentesque tempor aliquet. Maecenas ut eros vitae purus placerat vestibulum. Etiam vitae gravida dolor, quis rhoncus diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. + +Suspendisse fringilla lacinia sagittis. Integer tincidunt consectetur tristique. Morbi non orci convallis, congue sapien quis, vulputate nunc. Donec a libero vel magna elementum facilisis non quis mi. Mauris posuere tellus non ipsum ultrices elementum. Vivamus massa velit, facilisis quis placerat aliquet, aliquet nec leo. Praesent a maximus sem. Sed neque elit, feugiat vel quam non, molestie sagittis nunc. Etiam luctus nunc ac mauris scelerisque, nec rhoncus lacus convallis. Nunc pharetra, nunc ac pulvinar aliquam, ex ipsum euismod augue, nec porttitor lacus turpis vitae neque. Fusce bibendum odio id tortor faucibus pellentesque. Sed ac porta nibh, eu gravida erat. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam quis ullamcorper felis. Nulla mattis sagittis ante ac tincidunt. Integer ac felis efficitur, viverra libero et, facilisis ligula. Suspendisse a metus a massa rhoncus posuere. Phasellus suscipit ligula ut lacus facilisis, ac pellentesque ex tempor. Quisque consectetur massa mi, ac molestie libero dictum quis. Proin porttitor ligula quis erat tincidunt venenatis. Proin congue nunc sed elit gravida, nec consectetur lectus sodales. Etiam tincidunt convallis ipsum at vestibulum. Quisque maximus enim et mauris porttitor, et molestie magna tristique. Morbi vitae metus elit. Maecenas sed volutpat turpis. Aliquam vitae dolor vestibulum, elementum purus eget, dapibus nibh. Nullam egestas dui ac rutrum semper. + +Etiam hendrerit est metus, et condimentum metus aliquam ac. Pellentesque id neque id ipsum rhoncus vulputate. Aliquam erat nisl, posuere sit amet ligula ac, fermentum blandit felis. Vivamus fermentum mi risus, non lacinia purus viverra id. Aenean ac sapien consequat, finibus mauris nec, porta sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed quis consectetur ex, dignissim bibendum nulla. Phasellus ac libero at quam vehicula euismod non eu leo. Phasellus a sapien augue. + +Maecenas ligula dui, bibendum vitae mauris et, auctor laoreet felis. Duis non libero a mi semper mattis. Quisque consequat luctus massa, quis tristique eros auctor feugiat. Maecenas sodales euismod neque vitae facilisis. Nullam laoreet imperdiet velit at pellentesque. Etiam massa odio, facilisis a consequat vitae, placerat vel magna. Nunc sagittis eros nec urna fringilla, pulvinar vestibulum nibh scelerisque. Sed magna metus, cursus eu consequat et, pharetra a est. Suspendisse elementum neque a dui malesuada lacinia. Donec sed ipsum volutpat, cursus urna id, ullamcorper arcu. Maecenas laoreet nisl eget velit egestas sollicitudin. Etiam nisl turpis, mollis id dignissim vitae, tristique vehicula ante. Maecenas eget placerat est, at rutrum augue. Vivamus faucibus lacinia ullamcorper. Sed pulvinar urna sodales ante sodales, at gravida leo dictum. + +Morbi maximus, quam a lobortis bibendum, enim felis varius elit, ac vehicula elit nisl ut lacus. Quisque ut arcu augue. Praesent id turpis quam. Sed sed arcu eros. Maecenas at cursus lorem, ac eleifend nisi. Fusce mattis felis at commodo pharetra. Praesent ac commodo ipsum. Quisque finibus et eros vitae tincidunt. In hac habitasse platea dictumst. Praesent purus ipsum, luctus lobortis ornare quis, auctor eget justo. Nam vel enim sollicitudin, faucibus tortor eu, sagittis eros. Ut nec consectetur erat. Donec ultricies malesuada ligula, a hendrerit sapien volutpat in. Maecenas sed enim vitae sapien pulvinar faucibus. + +Proin semper nunc nibh, non consequat neque ullamcorper vel. Maecenas lobortis sagittis blandit. Aenean et arcu ultricies turpis malesuada malesuada. Ut quam ex, laoreet ut blandit cursus, feugiat vitae dolor. Etiam ex lacus, scelerisque vel erat vel, efficitur tincidunt magna. Morbi tristique lacinia dolor, in egestas magna ultrices vitae. Integer ultrices leo ac tempus venenatis. Praesent ac porta tortor. Vivamus ornare blandit tristique. Nulla rutrum finibus pellentesque. In non dui elementum, fermentum ipsum vel, varius magna. Pellentesque euismod tortor risus, ac pellentesque nisl faucibus eget. + +Vivamus eu enim purus. Cras ultrices rutrum egestas. Sed mollis erat nibh, at posuere nisl luctus nec. Nunc vulputate, sapien id auctor molestie, nisi diam tristique ante, non convallis tellus nibh at orci. Morbi a posuere purus, in ullamcorper ligula. Etiam elementum sit amet dui imperdiet iaculis. Proin vitae tincidunt ipsum, sit amet placerat lectus. Curabitur commodo sapien quam, et accumsan lectus fringilla non. Nullam eget accumsan enim, ac pharetra mauris. Sed quis tristique velit, vitae commodo nisi. Duis turpis dui, maximus ut risus at, finibus consequat nunc. Maecenas sed est accumsan, aliquet diam in, facilisis risus. Curabitur vehicula rutrum auctor. Nam iaculis risus pulvinar maximus viverra. Nulla vel augue et ex sagittis blandit. + +Ut sem nulla, porta ac ante ac, posuere laoreet eros. Donec sodales posuere justo a auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras mollis at orci hendrerit porta. Nullam sodales tortor tortor, non lacinia diam finibus id. Duis libero orci, suscipit ac odio et, dictum consequat ipsum. Pellentesque eu ligula sagittis, volutpat eros at, lacinia lorem. Cras euismod tellus in iaculis tempor. Quisque accumsan, magna a congue venenatis, ante ipsum aliquam lectus, at egestas enim nunc at justo. Quisque sem purus, viverra ut tristique ut, maximus id enim. Etiam quis placerat sem. In sollicitudin, lacus eu rutrum mollis, nulla eros luctus elit, vel dapibus urna purus nec urna. Phasellus egestas massa quam, ac molestie erat hendrerit a. Praesent ultrices neque ut turpis molestie auctor. Etiam molestie placerat purus, et euismod erat aliquam in. Morbi id suscipit justo. + +Proin est ante, consequat at varius a, mattis quis felis. Sed accumsan nibh sit amet ipsum elementum posuere. Vestibulum bibendum id diam sit amet gravida. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi nec dolor vel ipsum dignissim hendrerit vel non ipsum. Praesent facilisis orci quis elit auctor lobortis. Phasellus cursus risus lectus, vel lobortis libero dapibus in. Quisque tristique tempus leo a pulvinar. Pellentesque a magna tincidunt, pellentesque massa nec, laoreet orci. Morbi congue ornare dolor quis commodo. Phasellus massa nisi, tincidunt at eros dictum, hendrerit lobortis urna. Maecenas porta, magna id mattis molestie, nibh tellus lobortis sem, eget tincidunt ipsum quam eu turpis. + +Ut gravida orci risus, vel rutrum mauris vehicula id. Etiam bibendum, neque a placerat condimentum, ex orci imperdiet lectus, quis dapibus arcu lacus eget lectus. Sed consequat non mi sit amet venenatis. Fusce vestibulum erat libero, eget hendrerit risus vulputate sollicitudin. Integer sed eleifend felis. Donec commodo, sem eu mattis placerat, urna odio aliquam tellus, et laoreet justo tellus eget erat. Fusce sed suscipit tortor. Nam hendrerit nibh ac nunc auctor lacinia. Pellentesque placerat condimentum ipsum, eget semper tortor hendrerit vel. Nullam non urna eu lacus pellentesque congue ut id eros. + +Nunc finibus leo in rhoncus tristique. Sed eu ipsum nec nisl egestas faucibus eget a felis. Pellentesque vitae nisi in nulla accumsan fermentum. Sed venenatis feugiat eleifend. Fusce porttitor varius placerat. Aliquam aliquet lacus sit amet mattis mollis. Sed vel nulla quis dolor suscipit vehicula ac viverra lorem. Duis viverra ipsum eget nulla ullamcorper fermentum. Mauris tincidunt arcu quis quam fringilla ornare. Donec et iaculis tortor. Nam ultricies libero vel ipsum aliquet efficitur. Morbi eget dolor aliquam, tempus sapien eget, viverra ante. Donec varius mollis ex, sed efficitur purus euismod interdum. Quisque vel sapien non neque tincidunt semper. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Suspendisse sit amet purus leo. Fusce lectus lorem, aliquam ac nulla eget, imperdiet ornare eros. Nullam sem augue, varius in nisi non, sollicitudin pellentesque ante. Etiam eu odio condimentum, tempor libero et, egestas arcu. Cras pellentesque eleifend aliquet. Pellentesque non blandit ligula. Ut congue viverra rhoncus. Phasellus mattis mi ac eros placerat, eu feugiat tellus ultrices. Aenean mollis laoreet libero eu imperdiet. Cras sed pulvinar mi, ac vehicula ligula. Vestibulum sit amet ex massa. In a egestas eros. + +Mauris pretium ipsum risus, venenatis cursus ante imperdiet id. Praesent eu turpis nec risus feugiat maximus ullamcorper ac lectus. Integer placerat at mi vel dapibus. Vestibulum fermentum turpis sit amet turpis viverra, id aliquet diam suscipit. Nam nec ex sed ante ullamcorper pharetra quis sit amet risus. Sed ac faucibus velit, id feugiat nibh. Nullam eget ipsum ex. Vivamus tincidunt non nunc non faucibus. Quisque bibendum viverra facilisis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at nisi hendrerit quam suscipit egestas. Curabitur laoreet maximus ultricies. Duis ut tellus ac augue molestie dictum. + +Suspendisse rhoncus iaculis erat, ut ullamcorper est tristique eget. Donec auctor nec risus at gravida. Vivamus volutpat vulputate tellus, vel ultricies eros suscipit eget. Ut pulvinar id mi eu tempus. Morbi malesuada augue in dui varius, nec blandit neque vehicula. Donec ornare nec nisl in mollis. Morbi enim nisi, rhoncus nec est id, dapibus tempus urna. Ut id elit a felis vestibulum consectetur. Duis lectus quam, pharetra sit amet diam sed, posuere vestibulum erat. Fusce vitae maximus massa. Nullam id metus tempus, iaculis risus eu, lobortis urna. Quisque in congue urna. Pellentesque placerat neque in augue dapibus, non varius ex malesuada. Curabitur ut eleifend libero. Fusce vitae ligula luctus, fermentum enim vitae, ultrices erat. + +Sed viverra augue turpis, scelerisque egestas sapien mattis eu. Duis laoreet magna at ex pharetra dapibus. Praesent eget odio vel quam venenatis dictum. Nulla in sollicitudin dolor. Mauris lobortis nec eros vel rhoncus. Vestibulum porta viverra venenatis. Curabitur vel scelerisque quam, a egestas velit. Praesent volutpat tincidunt magna at laoreet. + +Cras nec lorem odio. Pellentesque quis dui urna. Praesent at tellus ac lectus scelerisque placerat nec eu risus. Vestibulum sit amet mattis ligula. Vivamus sed nisi at leo elementum accumsan at sit amet arcu. Aenean mattis tellus nec leo gravida, eget hendrerit nisl faucibus. Mauris pellentesque luctus condimentum. Maecenas pretium sapien nunc, eget commodo dolor maximus id. Mauris vestibulum accumsan massa a dictum. Phasellus interdum quam ligula, ut maximus diam blandit aliquam. Nunc vitae ex eu erat condimentum consectetur. Maecenas interdum condimentum volutpat. + +Donec et enim a libero rutrum laoreet. Praesent a condimentum sem, at tincidunt quam. In vel molestie risus. Sed urna dui, molestie vitae mollis laoreet, tempor quis lectus. Praesent vitae auctor est, et aliquet nunc. Curabitur vulputate blandit nulla, at gravida metus. Maecenas gravida dui eu iaculis tristique. Pellentesque posuere turpis nec auctor eleifend. Suspendisse bibendum diam eu tellus lobortis, et laoreet quam congue. In hac habitasse platea dictumst. Morbi dictum neque velit, eget rutrum eros ultrices sit amet. + +Phasellus fermentum risus pharetra consectetur bibendum. Donec magna tortor, lacinia vitae nibh quis, aliquet pretium lorem. Donec turpis nisi, pretium eu enim volutpat, mattis malesuada augue. Nullam vel tellus iaculis, sollicitudin elit eget, tincidunt lacus. Fusce elementum elementum felis et iaculis. Suspendisse porta eros nec neque malesuada, in malesuada ante sollicitudin. Vivamus bibendum viverra molestie. + +Integer feugiat, erat nec convallis aliquam, velit felis congue erat, molestie eleifend tellus erat in tellus. Nunc et justo purus. Donec egestas fermentum dui non feugiat. Quisque in sapien sagittis, gravida quam id, iaculis lectus. Cras sagittis rhoncus bibendum. Fusce quis metus in velit scelerisque tincidunt at non ipsum. Vivamus efficitur ante eu odio vulputate, vitae ultricies risus vehicula. Proin eget odio eu sem tincidunt feugiat vel id lorem. + +Vestibulum sit amet nulla dignissim, euismod mi in, fermentum tortor. Donec ut aliquet libero, lacinia accumsan velit. Donec et nulla quam. Nullam laoreet odio nec nunc imperdiet, a congue eros venenatis. Quisque nec tellus sit amet neque interdum posuere. Duis quis mi gravida, tincidunt diam convallis, ultricies augue. Mauris consequat risus non porttitor congue. Ut in ligula consequat, viverra nunc a, eleifend enim. Duis ligula urna, imperdiet nec facilisis et, ornare eu ex. Proin lobortis lectus a lobortis porttitor. Nulla leo metus, egestas eu libero sed, pretium faucibus felis. Vestibulum non sem tortor. Nam cursus est leo. Vivamus luctus enim odio, non interdum sem dapibus a. Aenean accumsan consequat lectus in imperdiet. + +Donec vehicula laoreet ipsum in posuere. Quisque vel quam imperdiet, sollicitudin nisi quis, suscipit velit. Morbi id sodales mauris. Curabitur tellus arcu, feugiat sed dui sit amet, sodales sagittis libero. Aenean vel suscipit metus, non placerat leo. Vestibulum quis nulla elit. Proin scelerisque non ante ut commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. + +Sed non urna dolor. Suspendisse convallis mi porta pulvinar ultrices. Suspendisse quam ipsum, hendrerit non scelerisque molestie, interdum dictum nunc. Morbi condimentum condimentum turpis eu luctus. Pellentesque sagittis sollicitudin odio, sed ultricies felis ornare sit amet. Sed ultrices ex leo, a tincidunt nisl gravida sed. Nullam ornare accumsan porta. Praesent consectetur id est nec sollicitudin. + +In hac habitasse platea dictumst. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed sed ultrices nibh. Duis accumsan suscipit eros, a dictum odio tempus sit amet. Aenean imperdiet erat ac lacus finibus, scelerisque cursus massa imperdiet. Mauris molestie risus ut lacinia posuere. Nulla et sodales purus. Maecenas orci erat, placerat in tristique quis, placerat in mi. + +Donec sollicitudin pellentesque odio in feugiat. Morbi eu dolor ut mauris congue sollicitudin. Aliquam erat volutpat. Nulla id varius dui. Curabitur finibus urna ante, consectetur interdum nisi volutpat a. Quisque quis mi tristique, consequat tellus eget, rutrum sapien. Vivamus vitae tellus vulputate, rutrum ex eu, vulputate sem. Suspendisse viverra lorem tellus, vel interdum orci gravida quis. Ut laoreet arcu at mi ullamcorper finibus. Duis porta sagittis vestibulum. Sed commodo nisl vitae urna sollicitudin, nec lacinia est sodales. Curabitur imperdiet sodales dui sed iaculis. Sed ac tellus maximus, eleifend quam sit amet, feugiat elit. Aenean viverra, dui at mattis varius, est odio vestibulum sapien, sit amet mollis libero massa nec velit. Etiam quis sodales justo. + +Ut ultricies, sem eget sodales feugiat, nunc arcu congue elit, ac tempor justo massa nec purus. Maecenas enim nunc, pharetra eget dictum sit amet, tempus pellentesque velit. Suspendisse venenatis ligula in nulla mattis, et imperdiet ex tincidunt. Etiam vulputate, tellus et ultrices suscipit, enim velit laoreet massa, vitae congue odio enim ac urna. Morbi quam lorem, iaculis ac varius sagittis, euismod quis dolor. In ut dui eu purus feugiat consectetur. Vestibulum cursus velit quis lacus pellentesque iaculis. Cras in risus sed mauris porta rutrum. Nulla facilisi. Nullam eu bibendum est, non pellentesque lectus. Sed imperdiet feugiat lorem, quis convallis ante auctor in. Maecenas justo magna, scelerisque sit amet tellus eget, varius elementum risus. Duis placerat et quam sed varius. + +Duis nec nibh vitae nibh dignissim mollis quis sed felis. Curabitur vitae quam placerat, venenatis purus ut, euismod nisl. Curabitur porttitor nibh eu pulvinar ullamcorper. Suspendisse posuere nec ipsum ac dapibus. Cras convallis consectetur urna. Phasellus a nibh in dolor lacinia posuere id eget augue. In eu pharetra lorem, vitae cursus lacus. Aliquam tincidunt nibh lectus. Aenean facilisis ultricies posuere. Sed ut placerat orci. Curabitur scelerisque gravida blandit. Maecenas placerat ligula eget suscipit fringilla. Mauris a tortor justo. Aliquam hendrerit semper mollis. Phasellus et tincidunt libero. Etiam vel quam libero. + +Quisque aliquet tempor ex. Ut ante sem, vehicula at enim vel, gravida porta elit. Etiam vitae lacus a neque lobortis consectetur. Mauris sed interdum odio. Mauris elementum ex blandit tempor cursus. Integer in enim in leo viverra elementum. Fusce consectetur metus et sem rutrum, mattis euismod diam semper. Nunc sed ipsum vel urna consequat vehicula. Donec cursus pretium lorem, vestibulum pretium felis commodo sit amet. Nam blandit felis enim, eget gravida ex faucibus a. In nec neque massa. Etiam laoreet posuere ipsum. Praesent volutpat nunc dolor, ac vulputate magna facilisis non. Aenean congue turpis vel lectus sollicitudin tristique. Sed nec consequat purus, non vehicula quam. Etiam ultricies, est ac dictum tincidunt, turpis turpis pretium massa, a vulputate libero justo at nibh. + +Aliquam erat volutpat. Cras ultrices augue ac sollicitudin lobortis. Curabitur et aliquet purus. Duis feugiat semper facilisis. Phasellus lobortis cursus velit, a sollicitudin tortor. Nam feugiat sapien non dapibus condimentum. Morbi at mi bibendum, commodo quam at, laoreet enim. Integer eu ultrices enim. Sed vestibulum eu urna ut dictum. Curabitur at mattis leo, sed cursus massa. Aliquam porttitor, felis quis fermentum porttitor, justo velit feugiat nulla, eget condimentum sem dui ut sapien. + +In fringilla elit eu orci aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut eget fringilla tellus. Curabitur fermentum, mi et condimentum suscipit, elit neque bibendum dui, et hendrerit nunc metus id ipsum. Morbi placerat mi in hendrerit congue. Ut feugiat mauris eget scelerisque viverra. Vivamus sit amet erat dictum, sagittis lectus nec, pulvinar lorem. Sed non enim ac dui sollicitudin aliquet. Quisque ut lacus dolor. Fusce hendrerit malesuada euismod. Nulla faucibus vel mauris eu mollis. Mauris est diam, fringilla ac arcu feugiat, efficitur volutpat turpis. Aliquam venenatis cursus massa sed porttitor. Ut ac finibus enim, in tincidunt sapien. + +Nunc faucibus semper turpis a lacinia. Phasellus gravida, libero vel pulvinar ornare, ex sem tincidunt lectus, sit amet convallis augue risus at tortor. Quisque sit amet ipsum id nulla posuere vestibulum. Pellentesque scelerisque mauris vel leo viverra sodales. Nulla viverra aliquam ex, ut rutrum enim fermentum venenatis. Aenean eget dapibus ex, eget faucibus metus. Vestibulum volutpat leo in diam semper, eget porta magna suscipit. Sed sit amet nulla blandit, aliquam dolor ac, gravida velit. Sed vel velit viverra, maximus est id, convallis justo. + +Curabitur nulla ante, vulputate at libero vel, ullamcorper rutrum nibh. Pellentesque porttitor eu mauris id mattis. Duis vulputate augue elit, eget interdum justo pretium vel. Maecenas eu vulputate arcu, eget posuere purus. Suspendisse viverra a velit dictum eleifend. Suspendisse vitae dapibus diam. Donec vehicula justo in ante interdum, eu luctus diam placerat. Vivamus convallis ipsum eu orci suscipit, sed fermentum enim euismod. Maecenas faucibus elit vitae ex ornare tristique. Donec vestibulum nec elit sit amet porttitor. Aenean tempor lectus eget tortor hendrerit luctus. Nullam interdum vitae lectus vel feugiat. Cras in risus non magna consectetur lobortis. Sed faucibus enim quis gravida convallis. + +Phasellus eget massa sit amet libero ultrices suscipit. Vivamus at risus sapien. Nam mollis nunc eget velit dictum maximus. Sed pellentesque, nunc ac fringilla lacinia, quam enim mattis ex, sed euismod tortor metus eu neque. Ut mattis nisl ut lectus rhoncus, sodales bibendum eros porta. Nulla porttitor enim nec diam sagittis, eget porta velit efficitur. Vestibulum ultricies eros neque. Phasellus rutrum suscipit enim, in interdum ante gravida vitae. Sed in sagittis diam, non commodo velit. + +Morbi hendrerit odio orci, nec tincidunt odio rhoncus nec. Mauris neque velit, vehicula a lorem at, suscipit tristique dui. Sed finibus, nisl in mattis convallis, turpis neque sodales lacus, eu porta enim magna non diam. Nam commodo sodales risus consectetur malesuada. In eget elementum justo. Phasellus sit amet massa imperdiet, dapibus nunc sit amet, suscipit orci. Fusce condimentum laoreet feugiat. Ut ut viverra ante. Praesent bibendum interdum commodo. Nulla mollis nisi a est ornare volutpat. Sed at ligula eu nisi dapibus tempus. Proin cursus vestibulum justo, nec efficitur justo dignissim vel. Nunc quis maximus eros. + +Cras viverra, diam a tristique mattis, libero felis vulputate tellus, a ornare felis leo a dui. Nulla ante nulla, finibus ut tellus ut, blandit pharetra nibh. Proin eleifend fermentum ex, eget auctor libero vulputate in. Nullam ultricies, mauris placerat pretium placerat, leo urna lobortis leo, vel placerat arcu libero sed mauris. Aliquam mauris ligula, ornare at urna at, eleifend gravida ligula. Vestibulum consectetur ut nulla non scelerisque. Donec ornare, sem nec elementum aliquam, urna nulla bibendum metus, eu euismod dui ligula ac est. Fusce laoreet erat eu ex lobortis, quis bibendum ligula interdum. Sed vel mi erat. Vivamus id lacus ac enim mattis tempor. Nunc ultricies pellentesque enim sed euismod. Fusce tincidunt convallis elit quis aliquam. Mauris nulla ipsum, sollicitudin quis diam ac, feugiat volutpat tellus. In nibh nibh, vulputate quis tincidunt quis, pulvinar eget magna. Pellentesque quis finibus dolor. Suspendisse viverra vitae lectus non eleifend. + +Nunc ut orci et sapien maximus semper. Nulla dignissim sem urna, ac varius lectus ultricies id. Quisque aliquet pulvinar pretium. In ultricies molestie tellus vehicula porta. Nam enim lorem, aliquam eget ex et, hendrerit volutpat quam. Maecenas diam lacus, pellentesque eget tempus ac, pharetra eu elit. Donec vel eros a sem facilisis vulputate. Nullam ac nisi vulputate, laoreet nisl ac, eleifend sem. Nullam mi massa, rhoncus sed pharetra interdum, tincidunt eget nunc. Aliquam viverra mattis posuere. Mauris et dui sed nisl sollicitudin fermentum quis ut arcu. Nam placerat eget orci at tincidunt. Curabitur vel turpis metus. Phasellus nibh nulla, fermentum scelerisque sem vel, gravida tincidunt velit. Pellentesque vel quam tempor, finibus massa pellentesque, condimentum dui. + +Donec at mattis neque. Etiam velit diam, consequat auctor mauris id, hendrerit faucibus metus. Maecenas ullamcorper eros a est sodales, ac consectetur odio scelerisque. Donec leo metus, imperdiet at pellentesque vel, feugiat id erat. Suspendisse at magna enim. Vestibulum placerat sodales lorem id sollicitudin. Aenean at euismod ligula, eget mollis diam. Phasellus pulvinar, orci nec pretium condimentum, est erat facilisis purus, quis feugiat augue elit aliquam nulla. Aenean vitae tortor id risus congue tincidunt. Sed dolor enim, mattis a ullamcorper id, volutpat ac leo. + +Proin vehicula feugiat augue, id feugiat quam sodales quis. Donec et ultricies massa, a lacinia nulla. Duis aliquam augue ornare euismod viverra. Ut lectus risus, rutrum sit amet efficitur a, luctus nec nisl. Cras volutpat ullamcorper congue. Sed vitae odio metus. Phasellus aliquet euismod varius. + +Nullam sem ex, malesuada ut magna ut, pretium mollis arcu. Nam porttitor eros cursus mi lacinia faucibus. Suspendisse aliquet eleifend iaculis. Maecenas sit amet viverra tortor. Nunc a mollis risus. Etiam tempus dolor in tortor malesuada mattis. Ut tincidunt venenatis est sit amet dignissim. Vestibulum massa enim, tristique sed scelerisque eu, fringilla ac velit. Donec efficitur quis urna sit amet malesuada. Vestibulum consequat ac ligula in dapibus. Maecenas massa massa, molestie non posuere nec, elementum ut magna. In nisi erat, mollis non venenatis eu, faucibus in justo. Morbi gravida non ex non egestas. Pellentesque finibus laoreet diam, eu commodo augue congue vitae. + +Aenean sem mi, ullamcorper dapibus lobortis vitae, interdum tincidunt tortor. Vivamus eget vulputate libero. Ut bibendum posuere lectus, vel tincidunt tortor aliquet at. Phasellus malesuada orci et bibendum accumsan. Aliquam quis libero vel leo mollis porta. Sed sagittis leo ac lacus dictum, ac malesuada elit finibus. Suspendisse pharetra luctus commodo. Vivamus ultricies a odio non interdum. Vivamus scelerisque tincidunt turpis quis tempor. Pellentesque tortor ligula, varius non nunc eu, blandit sollicitudin neque. Nunc imperdiet, diam et tristique luctus, ipsum ex condimentum nunc, sit amet aliquam justo velit sed libero. Duis vel suscipit ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed tincidunt neque vel massa ultricies, id dictum leo consequat. Curabitur lobortis ultricies tellus, eget mattis nisl aliquam sit amet. + +Proin at suscipit justo. Vivamus ut vestibulum nisl. Pellentesque enim odio, pharetra non magna sed, efficitur auctor magna. Praesent tincidunt ante quis ante hendrerit viverra. Pellentesque vel ipsum id magna vulputate efficitur. Sed nec neque accumsan, pulvinar sapien quis, euismod mauris. Donec condimentum laoreet sapien quis gravida. Quisque sed mattis purus. Vestibulum placerat vel neque maximus scelerisque. + +Vestibulum mattis quam quis efficitur elementum. Duis dictum dolor ac scelerisque commodo. Fusce sollicitudin nisi sit amet dictum placerat. Suspendisse euismod pharetra eleifend. In eros nisl, porttitor sed mauris at, consectetur aliquet mauris. Donec euismod viverra neque sed fermentum. Phasellus libero magna, accumsan ut ultricies vitae, dignissim eget metus. Donec tellus turpis, interdum eget maximus nec, hendrerit eget massa. Curabitur auctor ligula in iaculis auctor. In ultrices quam suscipit cursus finibus. Aenean id mi at dolor interdum iaculis vitae ut lorem. Nullam sed nibh fringilla, lacinia odio nec, placerat erat. In dui libero, viverra ac viverra ac, pellentesque sit amet turpis. + +Nulla in enim ex. Sed feugiat est et consectetur venenatis. Cras varius facilisis dui vel convallis. Vestibulum et elit eget tellus feugiat pellentesque. In ut ante eu purus aliquet posuere. Nulla nec ornare sem, sed luctus lorem. Nam varius iaculis odio, eget faucibus nisl ullamcorper in. Sed eget cursus felis, nec efficitur nisi. + +Vivamus commodo et sem quis pulvinar. Pellentesque libero ante, venenatis vitae ligula sit amet, ornare sollicitudin nulla. Mauris eget tellus hendrerit, pulvinar metus quis, tempor nisi. Proin magna ex, laoreet sed tortor quis, varius fermentum enim. Integer eu dolor dictum, vulputate tortor et, aliquet ligula. Vestibulum vitae justo id mauris luctus sollicitudin. Suspendisse eget auctor neque, sodales egestas lorem. Vestibulum lacinia egestas metus vitae euismod. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus ex tellus, volutpat nec pulvinar sit amet, condimentum vitae dui. Curabitur vel felis sodales, lacinia nunc iaculis, ullamcorper augue. Pellentesque consequat dolor quis eros efficitur malesuada. Nulla ut malesuada lectus. + +Morbi et tristique ante. Aliquam erat volutpat. Vivamus vitae dui nec turpis pellentesque fermentum. Quisque eget velit massa. Pellentesque tristique aliquam nisl, eu sollicitudin justo venenatis sed. Duis eleifend sem eros, ut aliquam libero porttitor id. Sed non nunc consequat, rhoncus diam eu, commodo erat. Praesent fermentum in lectus id blandit. Donec quis ipsum at justo volutpat finibus. Nulla blandit justo nulla, at mollis lacus consequat eget. Aenean sollicitudin quis eros ut ullamcorper. + +Pellentesque venenatis nulla ut mi aliquet feugiat. Cras semper vel magna nec pharetra. Integer mattis felis et sapien commodo imperdiet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis quis luctus felis. Vestibulum justo nibh, aliquam non lectus vitae, molestie placerat justo. Donec lorem nibh, gravida sit amet hendrerit ac, maximus id ipsum. Nunc ac libero sodales risus eleifend sagittis. Phasellus est massa, lobortis elementum ex sed, scelerisque consectetur neque. Nunc faucibus neque id lorem malesuada, eget convallis ex mattis. + +Sed turpis tortor, fermentum non turpis id, posuere varius nibh. Donec iaculis lorem dui. Etiam eros ante, sodales eget venenatis at, consectetur eget risus. Curabitur non aliquam ante, a pretium justo. Maecenas tempor nisl tortor, vitae dictum nisi ultrices eu. Duis eget dui ultrices, porttitor lacus sed, lobortis purus. Quisque mattis elit nec neque sagittis, sed commodo leo blandit. Mauris sodales interdum eleifend. Vestibulum condimentum consectetur augue, id luctus diam convallis et. + +Nunc suscipit risus in justo accumsan, a placerat magna tincidunt. Proin a nisl ipsum. Sed libero dui, tristique in augue quis, auctor tristique risus. Sed porttitor ex augue, eu porta augue molestie a. Duis rhoncus purus libero, eu tempus turpis condimentum at. Sed mollis nisi id lectus placerat tincidunt. Maecenas non scelerisque elit, quis rutrum orci. Donec in tellus pharetra urna ornare lobortis. Phasellus id risus at nisi varius rutrum eu ut turpis. + +Duis dictum justo quis nisl porta, eget tincidunt magna suscipit. Sed velit massa, ullamcorper eu sodales ac, pretium a massa. Duis et rutrum tortor. Nulla accumsan hendrerit sapien, cursus volutpat eros egestas eget. Donec sollicitudin at ante quis sollicitudin. Aenean blandit feugiat diam, id feugiat eros faucibus eget. Donec viverra dolor vel justo scelerisque dignissim. Nulla semper sem nunc, rhoncus semper tellus ultricies sed. Duis in ornare diam. Donec vehicula feugiat varius. Maecenas ut suscipit est. Vivamus sem sem, finibus at dolor sit amet, euismod dapibus ligula. Vestibulum fringilla odio dapibus, congue massa eget, congue sem. Donec feugiat magna eget tortor lacinia scelerisque non et ipsum. + +Suspendisse potenti. Nunc convallis sollicitudin ex eget venenatis. Sed iaculis nibh ex, vel ornare ligula congue dignissim. Quisque sollicitudin dolor ac dui vestibulum, sit amet molestie nisi aliquet. Donec at risus felis. Aenean sollicitudin metus a feugiat porta. Aenean a tortor ut dolor cursus sagittis. Vivamus consectetur porttitor nunc in facilisis. Proin sit amet mi vel lectus consectetur ultrices. + +Sed cursus lectus vitae nunc tristique, nec commodo turpis dapibus. Pellentesque luctus ex id facilisis ornare. Morbi quis placerat dolor. Donec in lectus in arcu mattis porttitor ac sit amet metus. Cras congue mauris non risus sodales, vitae feugiat ipsum bibendum. Nulla venenatis urna sed libero elementum, a cursus lorem commodo. Mauris faucibus lobortis eros nec commodo. + +Nullam suscipit ligula ullamcorper lorem commodo blandit. Nulla porta nibh quis pulvinar placerat. Vivamus eu arcu justo. Vestibulum imperdiet est ut fermentum porttitor. Pellentesque consectetur libero in sapien efficitur scelerisque. Curabitur ac erat sit amet odio aliquet dignissim. Pellentesque mi sem, rhoncus et luctus at, porttitor rutrum lectus. Vestibulum sollicitudin sollicitudin suscipit. Aenean efficitur dolor non ultrices imperdiet. Donec vel sem ex. + +Sed convallis mauris aliquam rutrum cursus. Ut tempor porttitor sodales. Etiam eu risus ac augue gravida egestas et eu dolor. Proin id magna ex. Suspendisse quis lectus quis lorem ultricies tempus. Donec porttitor velit vitae tincidunt faucibus. Aliquam vitae semper nisi. Morbi ultrices, leo non pretium dapibus, dui libero pellentesque ex, vel placerat enim ante vitae dui. Nunc varius, sem sit amet sagittis lobortis, lectus odio scelerisque mauris, ut vestibulum orci magna quis neque. Sed id congue justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris congue nisi est, malesuada mollis elit tincidunt sed. Curabitur sed ex sit amet felis tristique elementum vitae vel nibh. + +Etiam mollis pretium lobortis. Mauris augue lacus, efficitur at lacus sed, mollis tincidunt lectus. Aliquam erat volutpat. Donec at euismod elit, et mattis felis. Sed id lobortis urna. Morbi imperdiet vestibulum leo, sed maximus leo blandit eu. Aliquam semper lorem neque, nec euismod turpis mattis mollis. Quisque lobortis urna ultrices odio pretium, ac venenatis orci faucibus. Suspendisse bibendum odio ligula, sed lobortis massa pharetra nec. Donec turpis justo, iaculis at dictum ac, finibus eu libero. Maecenas quis porttitor mi, sit amet aliquet neque. + +Vivamus auctor vulputate ante, at egestas lorem. Donec eu risus in nulla mollis ultricies at et urna. Duis accumsan porta egestas. Ut vel euismod augue. Fusce convallis nulla ante, nec fringilla velit aliquet at. Nam malesuada dapibus ligula, a aliquam nibh scelerisque ac. Praesent malesuada neque et pellentesque interdum. Curabitur volutpat at turpis vitae tristique. Vivamus porttitor semper congue. Quisque suscipit lacus mi, rhoncus ultrices tortor auctor quis. Maecenas neque neque, molestie ac facilisis eget, luctus ac lorem. In ut odio ut lacus suscipit pulvinar vitae sed elit. Nulla imperdiet, sem quis euismod sagittis, dui erat luctus dolor, faucibus faucibus erat sem eget nunc. Nam accumsan placerat malesuada. Maecenas convallis finibus pulvinar. + +Cras at placerat tortor. Morbi facilisis auctor felis sit amet molestie. Donec sodales sed lorem vitae suscipit. Etiam fermentum pharetra ipsum, nec luctus orci gravida eu. Pellentesque gravida, est non condimentum tempus, mauris ligula molestie est, in congue dolor nisl vel sapien. Duis congue tempor augue, id rutrum eros porta dapibus. Etiam rutrum eget est eget vestibulum. Aenean mollis arcu vel consequat varius. Praesent at condimentum felis. Duis nec interdum nisl. Donec commodo lorem sed sapien scelerisque malesuada non eu urna. In blandit non ipsum at porta. Nam lobortis leo vitae dui auctor, non feugiat quam bibendum. Donec auctor lectus sagittis laoreet maximus. Maecenas rhoncus laoreet porttitor. Vestibulum porttitor augue ut lectus hendrerit, eget posuere mi gravida. + +Sed mattis ex in erat pulvinar, eu imperdiet magna dapibus. Etiam nisi nibh, tempus non tellus sit amet, mattis tempor odio. Quisque nec lorem feugiat, lobortis odio et, commodo nunc. Maecenas semper purus nisi, nec vehicula nibh eleifend vitae. Nulla fermentum a lectus at maximus. Phasellus finibus metus non euismod ultrices. Etiam a pulvinar ante. Quisque convallis nec metus sit amet facilisis. Praesent laoreet massa et sollicitudin laoreet. Vestibulum in mauris aliquet, convallis mi ut, elementum purus. Nulla purus nulla, sodales at hendrerit quis, tempus sed lectus. + +Nam ut laoreet neque, ut maximus nibh. Maecenas quis justo pellentesque, sollicitudin elit at, venenatis velit. Aenean nunc velit, vehicula scelerisque odio at, consectetur laoreet purus. Duis dui purus, malesuada quis ipsum sit amet, tempor interdum libero. Curabitur porta scelerisque sapien, vitae cursus diam condimentum eu. Phasellus sed orci quam. Nullam vitae dui quis purus tincidunt vestibulum. Curabitur quis nulla porta, cursus arcu non, auctor enim. Etiam sollicitudin ex id sem vehicula mollis. Morbi viverra laoreet tincidunt. Praesent ut semper dui. Nam sit amet pretium neque. Mauris vitae luctus diam, in lacinia purus. Maecenas ut placerat justo, ut porta felis. Integer eu mauris ante. + +Aenean porttitor tellus diam, tempor consequat metus efficitur id. Suspendisse ut felis at erat tempor dictum at nec sapien. Sed vestibulum interdum felis, ac mattis mauris porta in. Nunc et condimentum massa. Sed cursus dictum justo et luctus. Integer convallis enim nisl, a rutrum lectus ultricies in. Donec dapibus lacus at nulla dapibus, id sollicitudin velit hendrerit. Fusce a magna at orci mollis rutrum ac a dolor. Aliquam erat volutpat. Morbi varius porta nunc, sit amet sodales ex hendrerit commodo. Donec tincidunt tortor sapien, vitae egestas sapien vehicula eget. + +Suspendisse potenti. Donec pulvinar felis nec leo malesuada interdum. Integer posuere placerat maximus. Donec nibh ipsum, tincidunt vitae luctus vitae, bibendum at leo. Sed cursus nisl ut ex faucibus aliquet sed nec eros. Curabitur molestie posuere felis. Integer faucibus velit eget consequat iaculis. Mauris sed vulputate odio. Phasellus maximus, elit a pharetra egestas, lorem magna semper tellus, vestibulum semper diam felis at sapien. Suspendisse facilisis, nisl sit amet euismod vehicula, libero nulla vehicula dolor, quis fermentum nibh elit sit amet diam. + +Morbi lorem enim, euismod eu varius ut, scelerisque quis odio. Nam tempus vitae eros id molestie. Nunc pretium in nulla eget accumsan. Quisque mattis est ut semper aliquet. Maecenas eget diam elementum, fermentum ipsum a, euismod sapien. Duis quam ligula, cursus et velit nec, ullamcorper tincidunt magna. Donec vulputate nisl est, et ullamcorper urna tempor sit amet. + +Proin lacinia dui non turpis congue pretium. Morbi posuere metus vel purus imperdiet interdum. Morbi venenatis vel eros non ultricies. Nulla vel semper elit. Ut quis purus tincidunt, auctor justo ut, faucibus turpis. Proin quis mattis erat, at faucibus ligula. Mauris in mauris enim. Donec facilisis enim at est feugiat hendrerit. Nam vel nisi lorem. Fusce ultricies convallis diam, in feugiat tortor luctus quis. Donec tempor, leo vitae volutpat aliquam, magna elit feugiat leo, quis placerat sapien felis eget arcu. Donec ornare fermentum eleifend. Integer a est orci. + +Proin rhoncus egestas leo. Nulla ultricies porta elit quis ornare. Nunc fermentum interdum vehicula. In in ligula lorem. Donec nec arcu sit amet orci lobortis iaculis. Mauris at mollis erat, sit amet mollis tortor. Mauris laoreet justo ullamcorper porttitor auctor. Aenean sit amet aliquam lectus, id fermentum eros. Praesent urna sem, vehicula ac fermentum id, dapibus ut purus. Vestibulum vitae tempus nunc. Donec at nunc ornare metus volutpat porta at eget magna. Donec varius aliquet metus, eu lobortis risus aliquam sed. Ut dapibus fermentum velit, ac tincidunt libero faucibus at. + +In in purus auctor, feugiat massa quis, facilisis nisi. Donec dolor purus, gravida eget dolor ac, porttitor imperdiet urna. Donec faucibus placerat erat, a sagittis ante finibus ac. Sed venenatis dignissim elit, in iaculis felis posuere faucibus. Praesent sed viverra dolor. Mauris sed nulla consectetur nunc laoreet molestie in ut metus. Proin ac ex sit amet magna vulputate hendrerit ac condimentum urna. Proin ligula metus, gravida et sollicitudin facilisis, iaculis ut odio. Cras tincidunt urna et augue varius, ut facilisis urna consequat. Aenean vehicula finibus quam. Ut iaculis eu diam ac mollis. Nam mi lorem, tristique eget varius at, sodales at urna. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin vitae dictum erat, et auctor ipsum. Nullam nunc nunc, sollicitudin quis magna a, vestibulum fermentum mauris. Praesent at erat dolor. Proin laoreet tristique nulla vel efficitur. Nam sed ultrices nibh, id rutrum nunc. Curabitur eleifend a erat sit amet sollicitudin. Nullam metus quam, laoreet vitae dapibus id, placerat sed leo. Aliquam erat volutpat. Donec turpis nisl, cursus eu ex sit amet, lacinia pellentesque nisl. Sed id ipsum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec interdum scelerisque lorem eu mattis. + +Vivamus ac tristique massa, nec facilisis nisl. Nam ipsum neque, tincidunt vel urna in, cursus imperdiet enim. Nam pellentesque egestas tempus. Morbi facilisis imperdiet libero vitae fringilla. Nam lacinia ligula at sapien facilisis malesuada. Nullam accumsan pulvinar sem, et cursus libero porta sit amet. Curabitur vulputate erat elit, ut pulvinar erat maximus vel. + +Cras aliquet metus ut purus sagittis, vel venenatis ante consectetur. Pellentesque nulla lacus, viverra viverra mattis non, placerat vitae nibh. Donec enim turpis, accumsan sit amet tincidunt eu, imperdiet non metus. Morbi ipsum eros, tincidunt vel est ac, tristique porttitor nibh. Praesent ut ullamcorper mauris. Sed laoreet sit amet diam congue venenatis. Integer porta purus nec orci sagittis posuere. + +Donec vehicula mauris eget lacus mollis venenatis et sed nibh. Nam sodales ligula ipsum, scelerisque lacinia ligula sagittis in. Nam sit amet ipsum at erat malesuada congue. Aenean ut sollicitudin sapien. Etiam at tempor odio. Mauris vitae purus ut magna suscipit consequat. Vivamus quis sapien neque. Nulla vulputate sem sit amet massa pellentesque, eleifend tristique ligula egestas. Suspendisse tincidunt gravida mi, in pulvinar lectus egestas non. Aenean imperdiet ex sit amet nunc sollicitudin porta. Integer justo odio, ultricies at interdum in, rhoncus vitae sem. Sed porttitor arcu quis purus aliquet hendrerit. Praesent tempor tortor at dolor dictum pulvinar. Nulla aliquet nunc non ligula scelerisque accumsan. Donec nulla justo, congue vitae massa in, faucibus hendrerit magna. Donec non egestas purus. + +Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibu + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vulputate, ipsum quis interdum fermentum, lorem sem fermentum eros, vitae auctor neque lacus in nisi. Suspendisse potenti. Maecenas et scelerisque elit, in tincidunt quam. Sed eu tincidunt quam. Nullam justo ex, imperdiet a imperdiet et, fermentum sit amet eros. Aenean quis tempus sem. Pellentesque accumsan magna mi, ut mollis velit sagittis id. Etiam quis ipsum orci. Fusce purus ante, accumsan a lobortis at, venenatis eu nisl. Praesent ornare sed ante placerat accumsan. Suspendisse tempus dignissim fermentum. Nunc a leo ac lacus sodales iaculis eu vitae mi. In feugiat ante at massa finibus cursus. Suspendisse posuere fringilla ornare. Mauris elementum ac quam id convallis. Vestibulum non elit quis urna volutpat aliquam a eu lacus. + +Aliquam vestibulum imperdiet neque, suscipit aliquam elit ultrices bibendum. Suspendisse ultrices pulvinar cursus. Morbi risus nisi, cursus consequat rutrum vitae, molestie sed dui. Fusce posuere, augue quis dignissim aliquam, nisi ipsum porttitor ante, quis fringilla nisl turpis ac nisi. Nulla varius enim eget lorem vehicula gravida. Donec finibus malesuada leo nec semper. Proin ac enim eros. Vivamus non tincidunt nisi, vel tristique lorem. + +Nunc consequat ex id eros dignissim, id rutrum risus laoreet. Sed euismod non erat eu ultricies. Etiam vehicula gravida lacus ut porta. Vestibulum eu eros quis nunc aliquet luctus. Cras quis semper ligula. Nullam gravida vehicula quam sed porta. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In porta cursus vulputate. Quisque porta a nisi eget cursus. Aliquam risus leo, luctus ac magna in, efficitur cursus magna. In condimentum non mi id semper. Donec interdum ante eget commodo maximus. + +Vivamus sit amet vestibulum lectus. Fusce tincidunt mi sapien, dictum sollicitudin diam vulputate in. Integer fringilla consequat mollis. Cras aliquet consequat felis eget feugiat. Nunc tempor cursus arcu, vitae ornare nunc varius et. Vestibulum et tortor vel ante viverra porttitor. Nam at tortor ullamcorper, facilisis augue quis, tristique erat. Aenean ut euismod nibh. Quisque eu tincidunt est, nec euismod eros. + +Proin vehicula nibh non viverra egestas. Phasellus sem dolor, ultricies ac sagittis tristique, lacinia a purus. Vestibulum in ante eros. Pellentesque lacus nulla, tristique vitae interdum vel, malesuada ac diam. Aenean bibendum posuere turpis in accumsan. Ut est nulla, ullamcorper quis turpis at, viverra sagittis mauris. Sed in interdum purus. Praesent scelerisque nibh eget sem euismod, ut imperdiet mi venenatis. Vivamus pulvinar orci sed dapibus auctor. Nulla facilisi. Vestibulum tincidunt erat nec porttitor egestas. Mauris quis risus ante. Nulla facilisi. + +Aliquam ullamcorper ornare lobortis. Phasellus quis sem et ipsum mollis malesuada sed in ex. Ut aliquam ex eget metus finibus maximus. Proin suscipit mauris eu nibh lacinia, quis feugiat dui dapibus. Nam sed libero est. Aenean vulputate orci sit amet diam faucibus, eu sagittis sapien volutpat. Nam imperdiet felis turpis, at pretium odio pulvinar in. Sed vestibulum id eros nec ultricies. Sed quis aliquam tortor, vitae ullamcorper tellus. Donec egestas laoreet eros, id suscipit est rutrum nec. Sed auctor nulla eget metus aliquam, ut condimentum enim elementum. + +Aliquam suscipit non turpis sit amet bibendum. Fusce velit ligula, euismod et maximus at, luctus sed neque. Quisque pretium, nisl at ullamcorper finibus, lectus leo mattis sapien, vel euismod mauris diam ullamcorper ex. Nulla ut risus finibus, lacinia ligula at, auctor erat. Mauris consectetur sagittis ligula vel dapibus. Nullam libero libero, lobortis aliquam libero vel, venenatis ultricies leo. Duis porttitor, nibh congue fermentum posuere, erat libero pulvinar tortor, a pellentesque nunc ipsum vel sem. Nullam volutpat, eros sit amet facilisis consectetur, ipsum est vehicula massa, non vestibulum neque elit in mauris. Nunc hendrerit ipsum non enim bibendum, vitae rhoncus mi egestas. Etiam ullamcorper massa vel nisl sagittis, nec bibendum arcu malesuada. Aenean aliquet turpis justo, a consectetur arcu mollis convallis. Etiam tellus ipsum, ultricies vitae lorem et, ornare facilisis orci. Praesent fringilla justo urna, vel mollis neque pulvinar vestibulum. + +Donec non iaculis erat. Aliquam et mi sed nunc pulvinar ultricies in ut ipsum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Praesent feugiat lacus ac dignissim semper. Phasellus vitae quam nisi. Morbi vel diam ultricies risus lobortis ornare. Fusce maximus et ligula quis iaculis. Sed congue ex eget felis convallis, sit amet hendrerit elit tempor. Donec vehicula blandit ante eget commodo. Vestibulum eleifend diam at feugiat euismod. Etiam magna tellus, dignissim eget fermentum vel, vestibulum vitae mauris. Nam accumsan et erat id sagittis. Donec lacinia, odio ut ornare ultricies, dolor velit accumsan tortor, non finibus erat tellus quis ligula. Nunc quis metus in leo volutpat ornare vulputate eu nisl. + +Donec quis viverra ex. Nullam id feugiat mauris, eu fringilla nulla. Vestibulum id maximus elit. Cras elementum elit sed felis lobortis, eget sagittis nisi hendrerit. Vivamus vitae elit neque. Donec vulputate lacus ut libero ultrices accumsan. Vivamus accumsan nulla orci, in dignissim est laoreet sagittis. Proin at commodo velit. Curabitur in velit felis. Aliquam erat volutpat. Sed consequat, nulla et cursus sodales, nisi lacus mattis risus, quis eleifend erat ex nec turpis. Sed suscipit ultrices lorem in hendrerit. + +Morbi vitae lacus nec libero ornare tempus eu et diam. Suspendisse magna ipsum, fermentum vel odio quis, molestie aliquam urna. Fusce mollis turpis a eros accumsan porttitor. Pellentesque rhoncus dolor sit amet magna rutrum, et dapibus justo tempor. Sed purus nisi, maximus vitae fringilla eu, molestie nec urna. Fusce malesuada finibus pretium. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec sed aliquet eros. Pellentesque luctus diam ante, eget euismod nisl aliquet eu. Sed accumsan elit purus, tempor varius ligula tempus nec. Curabitur ornare leo suscipit suscipit fermentum. Morbi eget nulla est. Maecenas faucibus interdum tristique. + +Etiam ut elit eros. Nulla pharetra suscipit molestie. Nulla facilisis bibendum nisl non molestie. Curabitur turpis lectus, facilisis vel diam non, vulputate ultrices mauris. Aenean placerat aliquam convallis. Suspendisse sed scelerisque tellus. Vivamus lacinia neque eget risus cursus suscipit. Proin consequat dolor vel neque tempor, eu aliquam sem scelerisque. Duis non eros a purus malesuada pharetra non et nulla. Suspendisse potenti. Mauris libero eros, finibus vel nulla id, sagittis dapibus ante. Proin iaculis sed nunc et cursus. + +Quisque accumsan lorem sit amet lorem aliquet euismod. Curabitur fermentum rutrum posuere. Etiam ultricies, sem id pellentesque suscipit, urna magna lacinia eros, quis efficitur risus nisl at lacus. Nulla quis lacus tortor. Mauris placerat ex in dolor tincidunt, vel aliquet nisi pretium. Cras iaculis risus vitae pellentesque aliquet. Quisque a enim imperdiet, ullamcorper arcu vitae, rutrum risus. Nullam consectetur libero at felis fringilla, nec congue nibh dignissim. Nam et lobortis felis, eu pellentesque ligula. Aenean facilisis, ligula non imperdiet maximus, massa orci gravida sapien, at sagittis lacus nisl in lacus. Nulla quis mauris luctus, scelerisque felis consequat, tempus risus. Fusce auctor nisl non nulla luctus molestie. Maecenas sapien nisl, auctor non dolor et, iaculis scelerisque lorem. Suspendisse egestas enim aliquet, accumsan mauris nec, posuere quam. Nulla iaculis dui dui, sit amet vestibulum erat ultricies ac. + +Cras eget dolor erat. Proin at nisl ut leo consectetur ultricies vel ut arcu. Nulla in felis malesuada, ullamcorper tortor et, convallis massa. Nunc urna justo, ornare in nibh vitae, hendrerit condimentum libero. Etiam vitae libero in purus venenatis fringilla. Nullam velit nulla, consequat ut turpis non, egestas hendrerit nibh. Duis tortor turpis, interdum non ante ac, cursus accumsan lectus. Cras pharetra bibendum augue quis dictum. Sed euismod vestibulum justo. Proin porta lobortis purus. Duis venenatis diam tortor, sit amet condimentum eros rhoncus a. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc at magna nec diam lobortis efficitur sit amet ut lacus. Nulla quis orci tortor. Pellentesque tempus velit a odio finibus porta. + +Proin feugiat mauris a tellus scelerisque convallis. Maecenas libero magna, blandit nec ultrices id, congue vel mi. Aliquam lacinia, quam vel condimentum convallis, tortor turpis aliquam odio, sed blandit libero lacus et eros. In eleifend iaculis magna ac finibus. Praesent auctor facilisis tellus in congue. Sed molestie lobortis dictum. Nam quis dignissim augue, vel euismod lorem. Curabitur posuere dapibus luctus. Donec ultricies dictum lectus, quis blandit arcu commodo ac. Aenean tincidunt ligula in nunc imperdiet dignissim. Curabitur egestas sollicitudin sapien ut semper. Aenean nec dignissim lacus. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec aliquam dictum vehicula. Donec tortor est, volutpat non nisi nec, varius gravida ex. Nunc vel tristique nunc, vitae mattis nisi. Nunc nec luctus ex, vitae tincidunt lectus. In hac habitasse platea dictumst. Curabitur lobortis ex eget tincidunt tempor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut a vehicula mi. + +Fusce eu libero finibus, interdum nulla a, placerat neque. Cras bibendum tempor libero nec feugiat. Cras ut sodales eros. Proin viverra, massa sit amet viverra egestas, neque nisl porta ex, sit amet hendrerit libero ligula vel urna. Mauris suscipit lacus id justo rhoncus suscipit. Etiam vel libero tellus. Maecenas non diam molestie, condimentum tellus a, bibendum enim. Mauris aliquet imperdiet tellus, eget sagittis dolor. Sed blandit in neque et luctus. Cras elementum sagittis nunc, vel mollis lorem euismod et. Donec posuere at lacus eget suscipit. + +Nulla nunc mi, pretium non massa vel, tempor semper magna. Nunc a leo pulvinar, tincidunt nunc at, dignissim mi. Aliquam erat volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut viverra nulla a nisl finibus, at hendrerit ligula ullamcorper. Donec a lorem semper, tempor magna et, lobortis libero. Mauris id sapien leo. Donec dignissim, quam vitae porttitor dignissim, quam justo mattis dui, vel consequat odio elit quis orci. Etiam nec pretium neque, sit amet pretium orci. Duis ac tortor venenatis, feugiat purus non, feugiat nunc. Proin scelerisque nisl in turpis aliquam vulputate. + +Praesent sed est semper, fringilla lorem vitae, tincidunt nibh. Cras eros metus, auctor at mauris sit amet, sodales semper orci. Nunc a ornare ex. Curabitur bibendum arcu congue urna vulputate egestas. Vestibulum finibus id risus et accumsan. Aenean ut volutpat tellus. Aenean tincidunt malesuada urna sit amet vestibulum. Mauris vel tellus dictum, varius lacus quis, dictum arcu. + +Aenean quis metus eu erat feugiat cursus vel at ligula. Proin dapibus sodales urna, id euismod lectus tempus id. Pellentesque ex ligula, convallis et erat vel, vulputate condimentum nisl. Pellentesque pharetra nulla quis massa eleifend hendrerit. Praesent sed massa ipsum. Maecenas vehicula dolor massa, id sodales urna faucibus et. Mauris ac quam non massa tincidunt feugiat et at lacus. Fusce libero massa, vulputate vel scelerisque non, mollis in leo. Ut sit amet ultricies odio. Suspendisse in sapien viverra, facilisis purus ut, pretium libero. + +Vivamus tristique pharetra molestie. Nam a volutpat purus. Praesent consequat gravida nisi, ac blandit nisi suscipit ut. Quisque posuere, ligula a ultrices laoreet, ligula nunc vulputate libero, ut rutrum erat odio tincidunt justo. Sed vitae leo at leo fringilla bibendum. Vestibulum ut augue nec dolor auctor accumsan. Praesent laoreet id eros pulvinar commodo. Suspendisse potenti. Ut pharetra, mauris vitae blandit fringilla, odio ante tincidunt lorem, sit amet tempor metus diam ut turpis. + +Praesent quis egestas arcu. Nullam at porta arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi vulputate ligula malesuada ligula luctus, vulputate tempus erat bibendum. Nunc ullamcorper non lectus at euismod. Etiam nibh felis, tincidunt a metus vel, pellentesque rhoncus neque. Etiam at diam in erat luctus interdum. Nunc vel ipsum pulvinar, sollicitudin lacus ac, tempus urna. Etiam vel lacinia sapien. Pellentesque sagittis velit vel mi efficitur iaculis. Integer euismod sit amet urna in sagittis. Cras eleifend ut nibh in facilisis. Donec et lacus vitae nunc placerat sodales. Nulla sed hendrerit ligula, at dapibus sapien. + +Praesent at iaculis ex. Curabitur est purus, cursus a faucibus quis, dictum id velit. Donec dignissim fringilla viverra. Nunc mauris felis, laoreet sit amet sagittis at, vestibulum in libero. Maecenas quis orci turpis. Quisque ut nibh vitae magna mollis consequat id at mauris. Aliquam eu odio eget nulla bibendum sodales. Quisque vel orci eleifend nisi pretium lacinia. Suspendisse eget risus eget mi volutpat molestie eget quis lacus. Duis nisi libero, tincidunt nec nulla id, faucibus cursus felis. + +Donec tempor eget risus pellentesque molestie. Phasellus porta neque vel arcu egestas, nec blandit velit fringilla. Nullam porta faucibus justo vitae laoreet. Pellentesque viverra id nunc eu varius. Nulla pulvinar lobortis iaculis. Etiam vestibulum odio nec velit tristique, a tristique nisi mattis. In sed fringilla orci, vitae efficitur odio. Quisque dui odio, ornare eget velit at, lacinia consequat libero. Quisque lectus nulla, aliquet eu leo in, porta rutrum diam. Donec nec mattis neque. Nam rutrum, odio ac eleifend bibendum, dolor arcu rutrum neque, eget porta elit tellus a lacus. Sed massa metus, sollicitudin et sapien eu, finibus tempus orci. Proin et sapien sit amet erat molestie interdum. In quis rutrum velit, faucibus ultrices tellus. + +Sed sagittis sed justo eget tincidunt. Maecenas ut leo sagittis, feugiat magna et, viverra velit. Maecenas ex arcu, feugiat at consequat vitae, auctor eu massa. Integer egestas, enim vitae maximus convallis, est lectus pretium mauris, ac posuere lectus nisl quis quam. Aliquam tempus laoreet mi, vitae dapibus dolor varius dapibus. Suspendisse potenti. Donec sit amet purus nec libero dapibus tristique. Pellentesque viverra bibendum ligula. Donec sed felis et ex lobortis laoreet. Phasellus a fringilla libero, vitae malesuada nulla. Pellentesque blandit mattis lacus, et blandit tortor laoreet consequat. Suspendisse libero nunc, viverra sed fermentum in, accumsan egestas arcu. Proin in placerat elit. Sed interdum imperdiet malesuada. Suspendisse aliquet quis mauris eget sollicitudin. + +Vivamus accumsan tellus non erat volutpat, quis dictum dolor feugiat. Praesent rutrum nunc ac est mollis cursus. Fusce semper volutpat dui ut egestas. Curabitur sit amet posuere massa. Cras tincidunt nulla et mi mollis imperdiet. Suspendisse scelerisque ex id sodales vulputate. In nunc augue, pharetra in placerat eu, mattis id tellus. Vivamus cursus efficitur vehicula. Nulla aliquet vehicula aliquet. + +Sed cursus tellus sed porta pulvinar. Sed vitae nisi neque. Nullam aliquet, lorem et efficitur scelerisque, arcu diam aliquam felis, sed pulvinar lorem odio et turpis. Praesent convallis pulvinar turpis eu iaculis. Aliquam nec gravida mi. Curabitur eu nibh tempor, blandit justo in, ultrices felis. Fusce placerat metus non mi sagittis rutrum. Morbi sed dui fringilla, sagittis mauris eget, imperdiet nunc. Phasellus hendrerit sem elit, id hendrerit libero auctor sit amet. Integer sodales elit sit amet consequat cursus. + +Nam semper est eget nunc mollis, in pellentesque lectus fringilla. In finibus vel diam id semper. Nunc mattis quis erat eu consectetur. In hac habitasse platea dictumst. Nullam et ipsum vestibulum ex pulvinar ultricies sit amet id velit. Aenean suscipit mi tortor, a lobortis magna viverra non. Nulla condimentum aliquet ante et ullamcorper. Pellentesque porttitor arcu a posuere tempus. Aenean lacus quam, imperdiet eu justo vitae, pretium efficitur ex. Duis id purus id magna rhoncus ultrices id eu risus. Nunc dignissim et libero id dictum. + +Quisque a tincidunt neque. Phasellus commodo mi sit amet tempor fringilla. Ut rhoncus, neque non porttitor elementum, libero nulla egestas augue, sed fringilla sapien felis ac velit. Phasellus viverra rhoncus mollis. Nam ullamcorper leo vel erat laoreet luctus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus semper a metus a cursus. Nulla sed orci egestas, efficitur purus ac, malesuada tellus. Aenean rutrum velit at tellus fermentum mollis. Aliquam eleifend euismod metus. + +In hac habitasse platea dictumst. Vestibulum volutpat neque vitae porttitor laoreet. Nam at tellus consequat, sodales quam in, pulvinar arcu. Maecenas varius convallis diam, ac lobortis tellus pellentesque quis. Maecenas eget augue massa. Nullam volutpat nibh ac justo rhoncus, ut iaculis tellus rutrum. Fusce efficitur efficitur libero quis condimentum. Curabitur congue neque non tincidunt tristique. Fusce eget tempor ex, at pellentesque odio. Praesent luctus dictum vestibulum. Etiam non orci nunc. Vivamus vitae laoreet purus, a lobortis velit. Curabitur tincidunt purus ac lectus elementum pellentesque. Quisque sed tincidunt est. + +Sed vel ultrices massa, vitae ultricies justo. Cras finibus mauris nec lacus tempus dignissim. Cras faucibus maximus velit, eget faucibus orci luctus vehicula. Nulla massa nunc, porta ac consequat eget, rhoncus non tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce sed maximus metus, vel imperdiet ipsum. Ut scelerisque lectus at blandit porttitor. Ut vulputate nunc pharetra, aliquet sapien ac, sollicitudin sapien. Aenean eget ante lorem. Nam accumsan venenatis tellus id dignissim. + +Curabitur fringilla, magna non maximus dapibus, nulla sapien vestibulum lectus, sit amet semper dolor neque vitae nisl. Nunc ultrices vehicula augue sed iaculis. Maecenas nec diam mollis, suscipit orci et, vestibulum ante. Pellentesque eu nisl tortor. Nunc eleifend, lacus quis volutpat volutpat, nisi mi molestie sem, quis mollis ipsum libero a tellus. Ut viverra dolor mattis convallis interdum. Sed tempus nisl at nunc scelerisque aliquet. Quisque tempor tempor lorem id feugiat. Nullam blandit lectus velit, vitae porta lacus tincidunt a. Vivamus sit amet arcu ultrices, tincidunt mi quis, viverra quam. Aenean fringilla libero elementum lorem semper, quis pulvinar eros gravida. Nullam sodales blandit mauris, sed fermentum velit fermentum sit amet. Donec malesuada mauris in augue sodales vulputate. Vestibulum gravida turpis id elit rhoncus dignissim. Integer non congue lorem, eu viverra orci. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at dolor magna. Aliquam consectetur erat augue, id iaculis velit pharetra ac. Integer rutrum venenatis dignissim. Integer non sodales elit. Curabitur ut magna ut nibh feugiat aliquam ac ut risus. Morbi nibh quam, aliquam id placerat nec, vestibulum eget velit. Suspendisse at dignissim quam. Vivamus aliquet sem sed nisl volutpat, ut cursus orci ultrices. Aliquam ultrices lacinia enim, vitae aliquet neque. + +Quisque scelerisque finibus diam in mattis. Cras cursus auctor velit. Aliquam sem leo, fermentum et maximus et, molestie a libero. Aenean justo elit, rutrum a ornare id, egestas eget enim. Aenean auctor tristique erat. Curabitur condimentum libero lacus, nec consequat orci vestibulum sed. Fusce elit ligula, blandit vitae sapien vitae, dictum ultrices risus. Nam laoreet suscipit sapien, at interdum velit faucibus sit amet. Duis quis metus egestas lectus elementum posuere non nec libero. Aliquam a dolor bibendum, facilisis nunc a, maximus diam. Vestibulum suscipit tristique magna, non dignissim turpis sodales sed. Nunc ornare, velit ac facilisis fringilla, dolor mi consectetur lorem, vitae finibus erat justo suscipit urna. Maecenas sit amet eros erat. Nunc non arcu ornare, suscipit lorem eget, sodales mauris. Aliquam tincidunt, quam nec mollis lacinia, nisi orci fermentum libero, consequat eleifend lectus quam et sapien. Vestibulum a quam urna. + +Cras arcu leo, euismod ac ullamcorper at, faucibus sed massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus porttitor velit in enim interdum, non commodo metus ornare. Morbi vel lorem quis nisl luctus tristique quis vitae nisl. Suspendisse condimentum tortor enim, nec eleifend ipsum euismod et. Sed gravida quam ut tristique lacinia. Mauris eu interdum ipsum, ac ultrices odio. Nullam auctor tellus a risus porttitor vehicula. Nulla blandit euismod dictum. In pharetra, enim iaculis pulvinar interdum, dui nunc placerat nunc, sit amet pretium lectus nulla vitae quam. Phasellus quis enim sollicitudin, varius nulla id, ornare purus. Donec quam lacus, vestibulum quis nunc ac, mollis dictum nisi. Cras ut mollis elit. Maecenas ultrices ligula at risus faucibus scelerisque. Etiam vitae porttitor purus. Curabitur blandit lectus urna, ut hendrerit tortor feugiat ut. + +Phasellus fringilla, sapien pellentesque commodo pharetra, ante libero aliquam tellus, ut consectetur augue libero a sapien. Maecenas blandit luctus nisl eget aliquet. Maecenas vitae porta dolor, faucibus laoreet sapien. Suspendisse lobortis, ipsum sed vehicula aliquam, elit purus scelerisque dui, rutrum consectetur diam odio et lorem. In nec lacinia metus. Donec viverra libero est, vel bibendum erat condimentum quis. Donec feugiat purus leo. In laoreet vitae felis a porttitor. Mauris ullamcorper, lacus id condimentum suscipit, neque magna pellentesque arcu, eget cursus neque tellus id metus. Curabitur volutpat ac orci vel ultricies. + +Sed ut finibus erat. Sed diam purus, varius non tincidunt quis, ultrices sit amet ipsum. Donec et egestas nulla. Suspendisse placerat nisi at dui laoreet iaculis. Aliquam aliquet leo at augue faucibus molestie. Nullam lacus augue, hendrerit sed nisi eu, faucibus porta est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam ut leo aliquet sem fermentum rutrum quis ac justo. Integer placerat aliquam nisl ut sagittis. Proin erat orci, lobortis et sem eget, eleifend fringilla augue. Mauris varius laoreet arcu, sed tincidunt felis. Pellentesque venenatis lorem odio, id pulvinar velit molestie feugiat. Donec mattis lacus sed eleifend pulvinar. + +Sed condimentum ex in tincidunt hendrerit. Etiam eget risus lacinia, euismod nibh eu, pellentesque quam. Proin elit eros, convallis id mauris ac, bibendum ultrices lectus. Morbi venenatis, purus id fermentum consequat, nunc libero tincidunt ligula, non dictum ligula orci nec quam. Nulla nec ultrices lorem. Aenean maximus augue vel dictum pharetra. Etiam turpis urna, pellentesque quis malesuada eu, molestie faucibus felis. + +Vestibulum pharetra augue ut quam blandit congue in nec risus. Proin eu nibh eu dui eleifend porta vitae id lectus. Proin lacus nibh, lobortis sed ligula vitae, interdum lobortis erat. Suspendisse potenti. In sollicitudin quis sapien ut aliquet. Mauris ac nulla arcu. Fusce tristique justo quis lectus mollis, eu volutpat lectus finibus. Vivamus venenatis facilisis ex ut vestibulum. + +Etiam varius lobortis purus, in hendrerit elit tristique at. In tempus, augue vestibulum fermentum gravida, ligula tellus vulputate arcu, eu molestie ex sapien at purus. Vestibulum nec egestas metus. Duis pulvinar quam nec consequat interdum. Aenean non dapibus lacus. Aliquam sit amet aliquet nulla. Sed venenatis volutpat purus nec convallis. Phasellus aliquet semper sodales. Cras risus sapien, condimentum auctor urna a, pulvinar ornare nisl. Sed tincidunt felis elit, ut elementum est bibendum ac. Morbi interdum justo vel dui faucibus condimentum. + +Sed convallis eu sem at tincidunt. Nullam at auctor est, et ullamcorper ipsum. Pellentesque eget ante ante. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer euismod, sapien sed dapibus ornare, nibh enim maximus lacus, lacinia placerat urna quam quis felis. Morbi accumsan id nisl ut condimentum. Donec bibendum nisi est, sed volutpat lorem rhoncus in. Vestibulum ac lacinia nunc, eget volutpat magna. Integer aliquam pharetra ipsum, id placerat nunc volutpat quis. Etiam urna diam, rhoncus sit amet varius vel, euismod vel sem. Nullam vel molestie urna. Vivamus ornare erat at venenatis euismod. Suspendisse potenti. Fusce diam justo, tincidunt vel sem at, commodo faucibus nisl. Duis gravida efficitur diam, vel sagittis erat pulvinar ut. + +Quisque vel pharetra felis. Duis efficitur tortor dolor, vitae porttitor erat fermentum sed. Sed eu mi purus. Etiam dignissim tortor eu tempus molestie. Aenean pretium erat enim, in hendrerit ante hendrerit at. Sed ut risus vel nunc venenatis ultricies quis in lacus. Pellentesque vitae purus euismod, placerat risus non, ullamcorper augue. Quisque varius quam ligula, nec aliquet ex faucibus vitae. Quisque rhoncus sit amet leo tincidunt mattis. Cras id mauris eget purus pretium gravida sit amet eu augue. Aliquam dapibus odio augue, id lacinia velit pulvinar eu. + +Mauris fringilla, tellus nec pharetra iaculis, neque nisi ultrices massa, et tincidunt sem dui sed mi. Curabitur erat lorem, venenatis quis tempus lacinia, tempus sit amet nunc. Aliquam at neque ac metus commodo dictum quis vitae justo. Phasellus eget lacus tempus, blandit lorem vel, rutrum est. Aenean pharetra sem ut augue lobortis dignissim. Sed rhoncus at nulla id ultrices. Cras id condimentum felis. In suscipit luctus vulputate. Donec tincidunt lacus nec enim tincidunt sollicitudin ut quis enim. Nam at libero urna. Praesent sit amet massa vitae massa ullamcorper vehicula. + +Nullam bibendum augue ut turpis condimentum bibendum. Proin sit amet urna hendrerit, sodales tortor a, lobortis lectus. Integer sagittis velit turpis, et tincidunt nisi commodo eget. Duis tincidunt elit finibus accumsan cursus. Aenean dignissim scelerisque felis vel lacinia. Nunc lacinia maximus luctus. In hac habitasse platea dictumst. Vestibulum eget urna et enim tempor tempor. Nam feugiat, felis vel vestibulum tempus, orci justo viverra diam, id dapibus lorem justo in ligula. + +Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In ac pellentesque sem. Vestibulum lacinia magna dui, eu lacinia augue placerat et. Maecenas pulvinar congue est. Pellentesque commodo dui non pulvinar scelerisque. Etiam interdum est posuere sem bibendum, ac commodo magna dictum. Cras ipsum turpis, rhoncus nec posuere vitae, laoreet a arcu. Integer ac massa sit amet enim placerat lacinia sed ultrices arcu. Suspendisse sem nibh, luctus sit amet volutpat in, pellentesque eu metus. Ut gravida neque eget mi accumsan tempus. Nam sit amet aliquet nibh. + +Pellentesque a purus cursus nulla hendrerit congue quis et odio. Aenean hendrerit, leo ullamcorper sagittis hendrerit, erat dui molestie quam, sed condimentum lacus risus sed tellus. Morbi a dapibus lectus, ut feugiat ex. Phasellus pretium quam et sapien mollis, vel iaculis dui dignissim. Sed ullamcorper est turpis, a viverra lorem consectetur in. Aenean aliquet nibh non cursus rutrum. Suspendisse at tristique urna, id lobortis urna. In hac habitasse platea dictumst. Phasellus libero velit, rutrum sed tellus nec, dapibus tincidunt ligula. Quisque vel dui venenatis, consequat nisl ut, lacinia ipsum. Phasellus vitae magna pellentesque, lobortis est id, faucibus quam. Nam eleifend faucibus dui vel pellentesque. + +Etiam ut est non lacus tincidunt interdum. Maecenas sed massa urna. Quisque ut nibh tortor. Pellentesque felis ipsum, tempor finibus ipsum et, euismod pretium metus. Donec sit amet est ipsum. Quisque rhoncus justo non finibus elementum. Nulla nec lectus ac tortor placerat fringilla. Phasellus ac ultrices nunc, eu efficitur nisl. Nulla rhoncus nunc vitae ante dictum tincidunt. Nunc ultrices, massa sit amet malesuada dignissim, lectus lacus consequat sapien, non eleifend metus sem in eros. Phasellus mauris ante, dictum sit amet suscipit ac, rhoncus eget nisi. Phasellus at orci mollis, imperdiet neque eget, faucibus nulla. In at purus massa. Pellentesque quis rutrum lectus. + +Integer eu faucibus turpis, sit amet mollis massa. Vestibulum id nulla commodo, rutrum ipsum sed, semper ante. Phasellus condimentum orci nec nibh convallis, ac maximus orci ullamcorper. Maecenas vitae sollicitudin mi. Integer et finibus lectus, et condimentum ligula. Donec elementum tristique quam vitae dapibus. Morbi euismod ipsum in tristique ullamcorper. + +Duis fermentum non enim eu auctor. Quisque lacinia nibh vehicula nibh posuere, eu volutpat turpis facilisis. Ut ac faucibus nulla. Sed eleifend quis ex et pellentesque. Vestibulum sollicitudin in libero id fringilla. Phasellus dignissim purus consequat, condimentum dui sit amet, condimentum ante. Pellentesque ac consectetur massa, quis sagittis est. Nulla maximus tristique risus accumsan convallis. Curabitur imperdiet ac lacus a ultrices. Nulla facilisi. Sed quis quam quis lectus placerat lobortis vel sed turpis. In mollis dui id neque iaculis, ut aliquet tellus malesuada. Proin at luctus odio, vel blandit sapien. Praesent dignissim tortor vehicula libero fringilla, nec ultrices erat suscipit. Maecenas scelerisque purus in dapibus fermentum. + +Curabitur magna odio, mattis in tortor ut, porttitor congue est. Vestibulum mollis lacinia elementum. Fusce maximus erat vitae nunc rutrum lobortis. Integer ligula eros, auctor vel elit non, posuere luctus lacus. Maecenas quis auctor massa. Ut ipsum lacus, efficitur posuere euismod et, hendrerit efficitur est. Phasellus fringilla, quam id tincidunt pretium, nunc dui sollicitudin orci, eu dignissim nisi metus ut magna. Integer lobortis interdum dolor, non bibendum purus posuere et. Donec non lectus aliquet, pretium dolor eu, cursus massa. Sed ut dui sapien. In sed vestibulum massa. Pellentesque blandit, dui non sodales vehicula, orci metus mollis nunc, non pharetra ex tellus ac est. Mauris sagittis metus et fermentum pretium. Nulla facilisi. Quisque quis ante ut nulla placerat mattis ut quis nisi. + +Sed quis nulla ligula. Quisque dignissim ligula urna, sed aliquam purus semper at. Suspendisse potenti. Nunc massa lectus, pharetra vehicula arcu bibendum, imperdiet sodales ipsum. Nam ac sapien diam. Mauris iaculis fringilla mattis. Pellentesque tempus eros sit amet justo volutpat mollis. Phasellus ac turpis ipsum. Morbi vel ante elit. Aenean posuere quam consequat velit varius suscipit. Donec tempor quam ut nibh cursus efficitur. + +Morbi molestie dolor nec sem egestas suscipit. Etiam placerat pharetra lectus, et ullamcorper risus tristique in. Sed faucibus ullamcorper lectus eget fringilla. Maecenas malesuada hendrerit congue. Sed eget neque a erat placerat tincidunt. Aliquam vitae dignissim turpis. Fusce at placerat magna, a laoreet lectus. Maecenas a purus nec diam gravida fringilla. Nam malesuada euismod ante non vehicula. In faucibus bibendum leo, faucibus posuere nisl pretium quis. Fusce finibus bibendum finibus. Vestibulum eu justo maximus, hendrerit diam nec, dignissim sapien. Aenean dolor lacus, malesuada quis vestibulum ac, venenatis ac ipsum. Cras a est id nunc finibus facilisis. Cras lacinia neque et interdum vehicula. Suspendisse vulputate tellus elit, eget tempor dui finibus vel. + +Cras sed pretium odio. Proin hendrerit elementum felis in tincidunt. Nam sed turpis vel justo molestie accumsan condimentum eu nunc. Praesent lobortis euismod rhoncus. Nulla vitae euismod nibh, quis mattis mi. Fusce ultrices placerat porttitor. Duis sem ipsum, pellentesque sit amet odio a, molestie vulputate mauris. + +Duis blandit mollis ligula, sit amet mattis ligula finibus sit amet. Nunc a leo molestie, placerat diam et, vestibulum leo. Suspendisse facilisis neque purus, nec pellentesque ligula fermentum nec. Aenean malesuada mauris lorem, eu blandit arcu pulvinar quis. Duis laoreet urna lacus, non maximus arcu rutrum ultricies. Nulla augue dolor, suscipit eu mollis eu, aliquam condimentum diam. Ut semper orci luctus, pharetra turpis at, euismod mi. Nulla leo diam, finibus sit amet purus sed, maximus dictum lorem. Integer eu mi id turpis laoreet rhoncus. + +Integer a mauris tincidunt, finibus orci ut, pretium mauris. Nulla molestie nunc mi, id finibus lorem elementum sed. Proin quis laoreet ante. Integer nulla augue, commodo id molestie quis, rutrum ut turpis. Suspendisse et tortor turpis. Sed ut pharetra massa. Pellentesque elementum blandit sem, ut elementum tellus egestas a. Fusce eu purus nibh. + +Cras dignissim ligula scelerisque magna faucibus ullamcorper. Proin at condimentum risus, auctor malesuada quam. Nullam interdum interdum egestas. Nulla aliquam nisi vitae felis mollis dictum. Suspendisse dapibus consectetur tortor. Ut ut nisi non sem bibendum tincidunt. Vivamus suscipit leo quis gravida dignissim. + +Aliquam interdum, leo id vehicula mollis, eros eros rhoncus diam, non mollis ligula mi eu mauris. Sed ultrices vel velit sollicitudin tincidunt. Nunc auctor metus at ligula gravida elementum. Praesent interdum eu elit et mollis. Duis egestas quam sit amet velit dignissim consequat. Aliquam ac turpis nec nunc convallis sagittis. Fusce blandit, erat ac fringilla consectetur, dolor eros sodales leo, vel aliquet risus nisl et diam. Aliquam luctus felis vitae est eleifend euismod facilisis et lacus. Sed leo tellus, auctor eu arcu in, volutpat sagittis nisl. Pellentesque nisl ligula, placerat vel ullamcorper at, vulputate ac odio. Morbi ac faucibus orci, et tempus nulla. Proin rhoncus rutrum dolor, in venenatis mauris. Suspendisse a fermentum augue, non semper mi. Nunc eget pretium neque. Phasellus augue erat, feugiat ac aliquam congue, rutrum non sapien. Pellentesque ac diam gravida, consectetur felis at, ornare neque. + +Nullam interdum mattis sapien quis porttitor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus aliquet rutrum ipsum id euismod. Maecenas consectetur massa et mi porta viverra. Nunc quam nibh, dignissim vitae maximus et, ullamcorper nec lorem. Nunc vitae justo dapibus, luctus lacus vitae, pretium elit. Maecenas et efficitur leo. Curabitur mauris lectus, placerat quis vehicula vitae, auctor ut urna. Quisque rhoncus pharetra luctus. In hac habitasse platea dictumst. Integer sit amet metus nec eros malesuada aliquam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi hendrerit mi ac leo aliquam, sit amet ultricies libero commodo. Mauris dapibus purus metus, sit amet viverra nibh imperdiet et. Nullam porta nulla tellus, quis vehicula diam imperdiet non. Vivamus enim massa, bibendum in fermentum in, ultrices at ex. + +Suspendisse fermentum id nibh eget accumsan. Duis dapibus bibendum erat ut sollicitudin. Aliquam nec felis risus. Pellentesque rhoncus ligula id sem maximus mollis sed nec massa. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ipsum ipsum, sodales sed enim id, convallis faucibus eros. Donec ultricies dictum tincidunt. Cras vitae nibh arcu. Pellentesque cursus, sapien nec consequat fermentum, ipsum ante suscipit dui, imperdiet hendrerit est nisl eu massa. Quisque vitae sem ligula. Aenean iaculis metus ut mauris interdum laoreet. Vivamus sed gravida dolor. + +Morbi nulla metus, porttitor sed eros sit amet, efficitur efficitur est. In vel nisl urna. Ut aliquet tellus at congue convallis. Phasellus imperdiet lobortis sollicitudin. Integer sodales, sem eu ultricies pharetra, erat erat porttitor odio, eget dapibus libero ipsum eget velit. Phasellus gravida nulla nisl, eu pharetra mi auctor vel. Sed blandit pharetra velit, ut egestas libero placerat non. Aliquam a interdum quam. Proin at tortor nec dui sollicitudin tempus sed vestibulum elit. Nunc non sollicitudin velit. + +Aenean consequat diam velit, sed rutrum tortor faucibus dictum. Quisque at semper augue. Duis ut est eget mi ornare bibendum id et ligula. Phasellus consequat tortor non leo pulvinar posuere. Proin vestibulum eleifend felis, in hendrerit tortor sollicitudin eu. Phasellus hendrerit, lacus vel laoreet interdum, dui tortor consequat justo, commodo ultricies arcu felis vitae enim. Vivamus eu sapien at leo suscipit rutrum eu at justo. Aenean et dolor a libero ullamcorper posuere. Integer laoreet placerat nisi in vulputate. Mauris laoreet eget risus sed cursus. Donec scelerisque neque a libero eleifend hendrerit. Nulla varius condimentum nunc sit amet fermentum. Aliquam lorem ex, varius nec mollis ut, ultrices in neque. Morbi sit amet porta leo. Integer iaculis fermentum lacus in vestibulum. + +Ut gravida, tellus ut maximus ultrices, erat est venenatis nisl, vitae pretium massa ex ac magna. Sed non purus eget ligula aliquet volutpat non quis arcu. Nam aliquam tincidunt risus, sit amet fringilla sapien vulputate ut. Mauris luctus suscipit pellentesque. Nunc porttitor dapibus ex quis tempus. Ut ullamcorper metus a eros vulputate, vitae viverra lectus convallis. Mauris semper imperdiet augue quis tincidunt. Integer porta pretium magna, sed cursus sem scelerisque sollicitudin. Nam efficitur, nibh pretium eleifend vestibulum, purus diam posuere sem, in egestas mauris augue sit amet urna. + +Vestibulum tincidunt euismod massa in congue. Duis interdum metus non laoreet fringilla. Donec at ligula congue, tincidunt nunc non, scelerisque nunc. Donec bibendum magna non est scelerisque feugiat at nec neque. Ut orci tortor, tempus eget massa non, dignissim faucibus dolor. Nam odio risus, accumsan pretium neque eget, accumsan dignissim dui. In ut neque auctor, scelerisque tellus sed, ullamcorper nisi. Suspendisse varius cursus quam at hendrerit. Vivamus elit libero, sagittis vitae sem ac, vulputate iaculis ligula. + +Sed lobortis laoreet purus sit amet rutrum. Pellentesque feugiat non leo vel lacinia. Quisque feugiat nisl a orci bibendum vestibulum. In et sollicitudin urna. Morbi a arcu ac metus faucibus tempus. Nam eu imperdiet sapien, suscipit mattis tortor. Aenean blandit ipsum nisi, a eleifend ligula euismod at. Integer tincidunt pharetra felis, mollis placerat mauris hendrerit at. Curabitur convallis, est sit amet luctus volutpat, massa lacus cursus augue, sed eleifend magna quam et risus. Aliquam lobortis tincidunt metus vitae porttitor. Suspendisse potenti. Aenean ullamcorper, neque id commodo luctus, nulla nunc lobortis quam, id dapibus neque dui nec mauris. Etiam quis lorem quis elit commodo ornare. Ut pharetra purus ultricies enim ultrices efficitur. Proin vehicula tincidunt molestie. Mauris et placerat sem. + +Aliquam erat volutpat. Suspendisse velit turpis, posuere ac lacus eu, lacinia laoreet velit. Sed interdum felis neque, id blandit sem malesuada sit amet. Ut sagittis justo erat, efficitur semper orci tempor sed. Donec enim massa, posuere varius lectus egestas, pellentesque posuere mi. Cras tincidunt ut libero sed mattis. Suspendisse quis magna et tellus posuere interdum vel at purus. Pellentesque fringilla tristique neque, id aliquet tellus ultricies non. Duis ut tellus vel odio lobortis vulputate. + +Integer at magna ac erat convallis vestibulum. Sed lobortis porttitor mauris. Fusce varius lorem et volutpat pulvinar. Aenean ac vulputate lectus, vitae consequat velit. Suspendisse ex dui, varius ut risus ut, dictum scelerisque sem. Vivamus urna orci, volutpat ut convallis ac, venenatis vitae urna. In hac habitasse platea dictumst. Etiam eu purus arcu. Aenean vulputate leo urna, vel tristique dui sagittis euismod. Suspendisse non tellus efficitur ante rhoncus volutpat at et sapien. + +Sed dapibus accumsan porttitor. Phasellus facilisis lectus finibus ligula dignissim, id pulvinar lectus feugiat. Nullam egestas commodo nisi posuere aliquet. Morbi sit amet tortor sagittis, rutrum dui nec, dapibus sapien. Sed posuere tortor tortor, interdum auctor magna varius vitae. Vestibulum id sagittis augue. Curabitur fermentum arcu sem, eu condimentum quam rutrum non. Phasellus rutrum nibh quis lectus rhoncus pretium. Curabitur dictum interdum elit. Vestibulum maximus sodales imperdiet. Mauris auctor nec purus sed venenatis. In in urna purus. + +Duis placerat molestie suscipit. Morbi a elit id purus efficitur consequat. Nunc ac commodo turpis. Etiam sit amet lacus a ipsum tempus venenatis sed vel nibh. Duis elementum aliquam mi sed tristique. Morbi ligula tortor, semper ac est vel, lobortis maximus erat. Curabitur ipsum felis, laoreet vel condimentum eget, ullamcorper sit amet mauris. Nulla facilisi. Nam at purus sed mi egestas placerat vitae vel magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse at dignissim diam. Phasellus consectetur eget neque vel viverra. Donec sollicitudin mattis dolor vel malesuada. Vivamus vehicula leo neque, vitae fermentum leo posuere et. Praesent dui est, finibus sit amet tristique quis, pharetra vel nibh. + +Duis nulla leo, accumsan eu odio eget, sagittis semper orci. Quisque ullamcorper ligula quam, commodo porttitor mauris ullamcorper eu. Cras varius sagittis felis in aliquam. Duis sodales risus ac justo vehicula, nec mattis diam lacinia. Cras eget lectus ipsum. Ut commodo, enim vitae malesuada hendrerit, ex dolor egestas lectus, sit amet hendrerit metus diam nec est. Vestibulum tortor metus, lobortis sit amet ante eget, tempor molestie lacus. In molestie et urna et semper. Mauris mollis, sem non hendrerit condimentum, sapien nisi cursus est, non suscipit quam justo non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam enim est, porta ac feugiat vitae, rutrum in lorem. Duis vehicula tortor ut posuere maximus. + +Nullam vestibulum non tellus sed commodo. Quisque mattis elit sit amet sapien sollicitudin, ut condimentum nisl congue. Aenean sagittis massa vel elit faucibus fermentum. Donec tincidunt nisi nec nisl sodales pellentesque. Mauris congue congue ligula ut suscipit. Vivamus velit tortor, tempor et gravida eget, fermentum sit amet ante. Nullam fringilla, lorem at ultrices cursus, urna neque ornare dolor, eu lacinia orci enim sed nibh. Ut a ullamcorper lectus, id mattis purus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean maximus sollicitudin posuere. Nunc at augue lacus. Aenean efficitur leo sit amet lacinia efficitur. + +Quisque venenatis quam mi, in pharetra odio vulputate eu. In vel nisl pulvinar, pulvinar ligula ut, sodales risus. Sed efficitur lectus at vestibulum tincidunt. Vestibulum eu ullamcorper elit. Fusce vestibulum magna enim, et tempor lacus posuere vitae. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer leo elit, luctus nec mattis sit amet, sollicitudin in turpis. + +Proin convallis venenatis leo, vitae tristique erat iaculis nec. Nulla facilisi. Duis porttitor, sapien et bibendum vulputate, sem libero sodales lacus, non malesuada felis erat ut libero. Nam non felis semper, finibus est a, mattis mauris. Praesent nec eros quam. Nulla hendrerit, augue consectetur eleifend ultricies, purus mi condimentum nulla, eget dapibus est nunc sed libero. Nullam elementum dui erat, vitae luctus libero sollicitudin et. Nulla odio magna, placerat in augue eu, dapibus imperdiet odio. Suspendisse imperdiet metus sit amet rhoncus dapibus. Cras at enim et urna vehicula cursus eu a mauris. Integer magna ante, eleifend ac placerat vitae, porta at nisi. Cras eget malesuada orci. Curabitur nunc est, vulputate id viverra et, dignissim sed odio. Curabitur non mattis sem. Sed bibendum, turpis vitae vehicula faucibus, nunc quam ultricies lectus, vitae viverra felis turpis at libero. + +Nullam ut egestas ligula. Proin hendrerit justo a lectus commodo venenatis. Nulla facilisi. Ut cursus lorem quis est bibendum condimentum. Aenean in tristique odio. Fusce tempor hendrerit ipsum. Curabitur mollis felis justo, quis dapibus erat auctor vel. Sed augue lectus, finibus ut urna quis, ullamcorper vestibulum dui. Etiam molestie aliquam tempor. Integer mattis sollicitudin erat, et tristique elit varius vel. Mauris a ex justo. + +Nam eros est, imperdiet non volutpat rutrum, pellentesque accumsan ligula. Duis sit amet turpis metus. Aenean in rhoncus metus, ac fringilla ex. Suspendisse condimentum egestas purus, ut pharetra odio vulputate vel. Duis tincidunt massa a placerat ultrices. Mauris ultricies nibh sit amet condimentum malesuada. Duis tincidunt id ipsum sed congue. + +Praesent eu ex augue. Nullam in porta ligula. In tincidunt accumsan arcu, in pellentesque magna tristique in. Mauris eleifend libero ac nisl viverra faucibus. Nam sollicitudin dolor in commodo hendrerit. Cras at orci metus. Ut quis laoreet orci. Vivamus ultrices leo pellentesque tempor aliquet. Maecenas ut eros vitae purus placerat vestibulum. Etiam vitae gravida dolor, quis rhoncus diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. + +Suspendisse fringilla lacinia sagittis. Integer tincidunt consectetur tristique. Morbi non orci convallis, congue sapien quis, vulputate nunc. Donec a libero vel magna elementum facilisis non quis mi. Mauris posuere tellus non ipsum ultrices elementum. Vivamus massa velit, facilisis quis placerat aliquet, aliquet nec leo. Praesent a maximus sem. Sed neque elit, feugiat vel quam non, molestie sagittis nunc. Etiam luctus nunc ac mauris scelerisque, nec rhoncus lacus convallis. Nunc pharetra, nunc ac pulvinar aliquam, ex ipsum euismod augue, nec porttitor lacus turpis vitae neque. Fusce bibendum odio id tortor faucibus pellentesque. Sed ac porta nibh, eu gravida erat. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam quis ullamcorper felis. Nulla mattis sagittis ante ac tincidunt. Integer ac felis efficitur, viverra libero et, facilisis ligula. Suspendisse a metus a massa rhoncus posuere. Phasellus suscipit ligula ut lacus facilisis, ac pellentesque ex tempor. Quisque consectetur massa mi, ac molestie libero dictum quis. Proin porttitor ligula quis erat tincidunt venenatis. Proin congue nunc sed elit gravida, nec consectetur lectus sodales. Etiam tincidunt convallis ipsum at vestibulum. Quisque maximus enim et mauris porttitor, et molestie magna tristique. Morbi vitae metus elit. Maecenas sed volutpat turpis. Aliquam vitae dolor vestibulum, elementum purus eget, dapibus nibh. Nullam egestas dui ac rutrum semper. + +Etiam hendrerit est metus, et condimentum metus aliquam ac. Pellentesque id neque id ipsum rhoncus vulputate. Aliquam erat nisl, posuere sit amet ligula ac, fermentum blandit felis. Vivamus fermentum mi risus, non lacinia purus viverra id. Aenean ac sapien consequat, finibus mauris nec, porta sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed quis consectetur ex, dignissim bibendum nulla. Phasellus ac libero at quam vehicula euismod non eu leo. Phasellus a sapien augue. + +Maecenas ligula dui, bibendum vitae mauris et, auctor laoreet felis. Duis non libero a mi semper mattis. Quisque consequat luctus massa, quis tristique eros auctor feugiat. Maecenas sodales euismod neque vitae facilisis. Nullam laoreet imperdiet velit at pellentesque. Etiam massa odio, facilisis a consequat vitae, placerat vel magna. Nunc sagittis eros nec urna fringilla, pulvinar vestibulum nibh scelerisque. Sed magna metus, cursus eu consequat et, pharetra a est. Suspendisse elementum neque a dui malesuada lacinia. Donec sed ipsum volutpat, cursus urna id, ullamcorper arcu. Maecenas laoreet nisl eget velit egestas sollicitudin. Etiam nisl turpis, mollis id dignissim vitae, tristique vehicula ante. Maecenas eget placerat est, at rutrum augue. Vivamus faucibus lacinia ullamcorper. Sed pulvinar urna sodales ante sodales, at gravida leo dictum. + +Morbi maximus, quam a lobortis bibendum, enim felis varius elit, ac vehicula elit nisl ut lacus. Quisque ut arcu augue. Praesent id turpis quam. Sed sed arcu eros. Maecenas at cursus lorem, ac eleifend nisi. Fusce mattis felis at commodo pharetra. Praesent ac commodo ipsum. Quisque finibus et eros vitae tincidunt. In hac habitasse platea dictumst. Praesent purus ipsum, luctus lobortis ornare quis, auctor eget justo. Nam vel enim sollicitudin, faucibus tortor eu, sagittis eros. Ut nec consectetur erat. Donec ultricies malesuada ligula, a hendrerit sapien volutpat in. Maecenas sed enim vitae sapien pulvinar faucibus. + +Proin semper nunc nibh, non consequat neque ullamcorper vel. Maecenas lobortis sagittis blandit. Aenean et arcu ultricies turpis malesuada malesuada. Ut quam ex, laoreet ut blandit cursus, feugiat vitae dolor. Etiam ex lacus, scelerisque vel erat vel, efficitur tincidunt magna. Morbi tristique lacinia dolor, in egestas magna ultrices vitae. Integer ultrices leo ac tempus venenatis. Praesent ac porta tortor. Vivamus ornare blandit tristique. Nulla rutrum finibus pellentesque. In non dui elementum, fermentum ipsum vel, varius magna. Pellentesque euismod tortor risus, ac pellentesque nisl faucibus eget. + +Vivamus eu enim purus. Cras ultrices rutrum egestas. Sed mollis erat nibh, at posuere nisl luctus nec. Nunc vulputate, sapien id auctor molestie, nisi diam tristique ante, non convallis tellus nibh at orci. Morbi a posuere purus, in ullamcorper ligula. Etiam elementum sit amet dui imperdiet iaculis. Proin vitae tincidunt ipsum, sit amet placerat lectus. Curabitur commodo sapien quam, et accumsan lectus fringilla non. Nullam eget accumsan enim, ac pharetra mauris. Sed quis tristique velit, vitae commodo nisi. Duis turpis dui, maximus ut risus at, finibus consequat nunc. Maecenas sed est accumsan, aliquet diam in, facilisis risus. Curabitur vehicula rutrum auctor. Nam iaculis risus pulvinar maximus viverra. Nulla vel augue et ex sagittis blandit. + +Ut sem nulla, porta ac ante ac, posuere laoreet eros. Donec sodales posuere justo a auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras mollis at orci hendrerit porta. Nullam sodales tortor tortor, non lacinia diam finibus id. Duis libero orci, suscipit ac odio et, dictum consequat ipsum. Pellentesque eu ligula sagittis, volutpat eros at, lacinia lorem. Cras euismod tellus in iaculis tempor. Quisque accumsan, magna a congue venenatis, ante ipsum aliquam lectus, at egestas enim nunc at justo. Quisque sem purus, viverra ut tristique ut, maximus id enim. Etiam quis placerat sem. In sollicitudin, lacus eu rutrum mollis, nulla eros luctus elit, vel dapibus urna purus nec urna. Phasellus egestas massa quam, ac molestie erat hendrerit a. Praesent ultrices neque ut turpis molestie auctor. Etiam molestie placerat purus, et euismod erat aliquam in. Morbi id suscipit justo. + +Proin est ante, consequat at varius a, mattis quis felis. Sed accumsan nibh sit amet ipsum elementum posuere. Vestibulum bibendum id diam sit amet gravida. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi nec dolor vel ipsum dignissim hendrerit vel non ipsum. Praesent facilisis orci quis elit auctor lobortis. Phasellus cursus risus lectus, vel lobortis libero dapibus in. Quisque tristique tempus leo a pulvinar. Pellentesque a magna tincidunt, pellentesque massa nec, laoreet orci. Morbi congue ornare dolor quis commodo. Phasellus massa nisi, tincidunt at eros dictum, hendrerit lobortis urna. Maecenas porta, magna id mattis molestie, nibh tellus lobortis sem, eget tincidunt ipsum quam eu turpis. + +Ut gravida orci risus, vel rutrum mauris vehicula id. Etiam bibendum, neque a placerat condimentum, ex orci imperdiet lectus, quis dapibus arcu lacus eget lectus. Sed consequat non mi sit amet venenatis. Fusce vestibulum erat libero, eget hendrerit risus vulputate sollicitudin. Integer sed eleifend felis. Donec commodo, sem eu mattis placerat, urna odio aliquam tellus, et laoreet justo tellus eget erat. Fusce sed suscipit tortor. Nam hendrerit nibh ac nunc auctor lacinia. Pellentesque placerat condimentum ipsum, eget semper tortor hendrerit vel. Nullam non urna eu lacus pellentesque congue ut id eros. + +Nunc finibus leo in rhoncus tristique. Sed eu ipsum nec nisl egestas faucibus eget a felis. Pellentesque vitae nisi in nulla accumsan fermentum. Sed venenatis feugiat eleifend. Fusce porttitor varius placerat. Aliquam aliquet lacus sit amet mattis mollis. Sed vel nulla quis dolor suscipit vehicula ac viverra lorem. Duis viverra ipsum eget nulla ullamcorper fermentum. Mauris tincidunt arcu quis quam fringilla ornare. Donec et iaculis tortor. Nam ultricies libero vel ipsum aliquet efficitur. Morbi eget dolor aliquam, tempus sapien eget, viverra ante. Donec varius mollis ex, sed efficitur purus euismod interdum. Quisque vel sapien non neque tincidunt semper. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Suspendisse sit amet purus leo. Fusce lectus lorem, aliquam ac nulla eget, imperdiet ornare eros. Nullam sem augue, varius in nisi non, sollicitudin pellentesque ante. Etiam eu odio condimentum, tempor libero et, egestas arcu. Cras pellentesque eleifend aliquet. Pellentesque non blandit ligula. Ut congue viverra rhoncus. Phasellus mattis mi ac eros placerat, eu feugiat tellus ultrices. Aenean mollis laoreet libero eu imperdiet. Cras sed pulvinar mi, ac vehicula ligula. Vestibulum sit amet ex massa. In a egestas eros. + +Mauris pretium ipsum risus, venenatis cursus ante imperdiet id. Praesent eu turpis nec risus feugiat maximus ullamcorper ac lectus. Integer placerat at mi vel dapibus. Vestibulum fermentum turpis sit amet turpis viverra, id aliquet diam suscipit. Nam nec ex sed ante ullamcorper pharetra quis sit amet risus. Sed ac faucibus velit, id feugiat nibh. Nullam eget ipsum ex. Vivamus tincidunt non nunc non faucibus. Quisque bibendum viverra facilisis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at nisi hendrerit quam suscipit egestas. Curabitur laoreet maximus ultricies. Duis ut tellus ac augue molestie dictum. + +Suspendisse rhoncus iaculis erat, ut ullamcorper est tristique eget. Donec auctor nec risus at gravida. Vivamus volutpat vulputate tellus, vel ultricies eros suscipit eget. Ut pulvinar id mi eu tempus. Morbi malesuada augue in dui varius, nec blandit neque vehicula. Donec ornare nec nisl in mollis. Morbi enim nisi, rhoncus nec est id, dapibus tempus urna. Ut id elit a felis vestibulum consectetur. Duis lectus quam, pharetra sit amet diam sed, posuere vestibulum erat. Fusce vitae maximus massa. Nullam id metus tempus, iaculis risus eu, lobortis urna. Quisque in congue urna. Pellentesque placerat neque in augue dapibus, non varius ex malesuada. Curabitur ut eleifend libero. Fusce vitae ligula luctus, fermentum enim vitae, ultrices erat. + +Sed viverra augue turpis, scelerisque egestas sapien mattis eu. Duis laoreet magna at ex pharetra dapibus. Praesent eget odio vel quam venenatis dictum. Nulla in sollicitudin dolor. Mauris lobortis nec eros vel rhoncus. Vestibulum porta viverra venenatis. Curabitur vel scelerisque quam, a egestas velit. Praesent volutpat tincidunt magna at laoreet. + +Cras nec lorem odio. Pellentesque quis dui urna. Praesent at tellus ac lectus scelerisque placerat nec eu risus. Vestibulum sit amet mattis ligula. Vivamus sed nisi at leo elementum accumsan at sit amet arcu. Aenean mattis tellus nec leo gravida, eget hendrerit nisl faucibus. Mauris pellentesque luctus condimentum. Maecenas pretium sapien nunc, eget commodo dolor maximus id. Mauris vestibulum accumsan massa a dictum. Phasellus interdum quam ligula, ut maximus diam blandit aliquam. Nunc vitae ex eu erat condimentum consectetur. Maecenas interdum condimentum volutpat. + +Donec et enim a libero rutrum laoreet. Praesent a condimentum sem, at tincidunt quam. In vel molestie risus. Sed urna dui, molestie vitae mollis laoreet, tempor quis lectus. Praesent vitae auctor est, et aliquet nunc. Curabitur vulputate blandit nulla, at gravida metus. Maecenas gravida dui eu iaculis tristique. Pellentesque posuere turpis nec auctor eleifend. Suspendisse bibendum diam eu tellus lobortis, et laoreet quam congue. In hac habitasse platea dictumst. Morbi dictum neque velit, eget rutrum eros ultrices sit amet. + +Phasellus fermentum risus pharetra consectetur bibendum. Donec magna tortor, lacinia vitae nibh quis, aliquet pretium lorem. Donec turpis nisi, pretium eu enim volutpat, mattis malesuada augue. Nullam vel tellus iaculis, sollicitudin elit eget, tincidunt lacus. Fusce elementum elementum felis et iaculis. Suspendisse porta eros nec neque malesuada, in malesuada ante sollicitudin. Vivamus bibendum viverra molestie. + +Integer feugiat, erat nec convallis aliquam, velit felis congue erat, molestie eleifend tellus erat in tellus. Nunc et justo purus. Donec egestas fermentum dui non feugiat. Quisque in sapien sagittis, gravida quam id, iaculis lectus. Cras sagittis rhoncus bibendum. Fusce quis metus in velit scelerisque tincidunt at non ipsum. Vivamus efficitur ante eu odio vulputate, vitae ultricies risus vehicula. Proin eget odio eu sem tincidunt feugiat vel id lorem. + +Vestibulum sit amet nulla dignissim, euismod mi in, fermentum tortor. Donec ut aliquet libero, lacinia accumsan velit. Donec et nulla quam. Nullam laoreet odio nec nunc imperdiet, a congue eros venenatis. Quisque nec tellus sit amet neque interdum posuere. Duis quis mi gravida, tincidunt diam convallis, ultricies augue. Mauris consequat risus non porttitor congue. Ut in ligula consequat, viverra nunc a, eleifend enim. Duis ligula urna, imperdiet nec facilisis et, ornare eu ex. Proin lobortis lectus a lobortis porttitor. Nulla leo metus, egestas eu libero sed, pretium faucibus felis. Vestibulum non sem tortor. Nam cursus est leo. Vivamus luctus enim odio, non interdum sem dapibus a. Aenean accumsan consequat lectus in imperdiet. + +Donec vehicula laoreet ipsum in posuere. Quisque vel quam imperdiet, sollicitudin nisi quis, suscipit velit. Morbi id sodales mauris. Curabitur tellus arcu, feugiat sed dui sit amet, sodales sagittis libero. Aenean vel suscipit metus, non placerat leo. Vestibulum quis nulla elit. Proin scelerisque non ante ut commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. + +Sed non urna dolor. Suspendisse convallis mi porta pulvinar ultrices. Suspendisse quam ipsum, hendrerit non scelerisque molestie, interdum dictum nunc. Morbi condimentum condimentum turpis eu luctus. Pellentesque sagittis sollicitudin odio, sed ultricies felis ornare sit amet. Sed ultrices ex leo, a tincidunt nisl gravida sed. Nullam ornare accumsan porta. Praesent consectetur id est nec sollicitudin. + +In hac habitasse platea dictumst. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed sed ultrices nibh. Duis accumsan suscipit eros, a dictum odio tempus sit amet. Aenean imperdiet erat ac lacus finibus, scelerisque cursus massa imperdiet. Mauris molestie risus ut lacinia posuere. Nulla et sodales purus. Maecenas orci erat, placerat in tristique quis, placerat in mi. + +Donec sollicitudin pellentesque odio in feugiat. Morbi eu dolor ut mauris congue sollicitudin. Aliquam erat volutpat. Nulla id varius dui. Curabitur finibus urna ante, consectetur interdum nisi volutpat a. Quisque quis mi tristique, consequat tellus eget, rutrum sapien. Vivamus vitae tellus vulputate, rutrum ex eu, vulputate sem. Suspendisse viverra lorem tellus, vel interdum orci gravida quis. Ut laoreet arcu at mi ullamcorper finibus. Duis porta sagittis vestibulum. Sed commodo nisl vitae urna sollicitudin, nec lacinia est sodales. Curabitur imperdiet sodales dui sed iaculis. Sed ac tellus maximus, eleifend quam sit amet, feugiat elit. Aenean viverra, dui at mattis varius, est odio vestibulum sapien, sit amet mollis libero massa nec velit. Etiam quis sodales justo. + +Ut ultricies, sem eget sodales feugiat, nunc arcu congue elit, ac tempor justo massa nec purus. Maecenas enim nunc, pharetra eget dictum sit amet, tempus pellentesque velit. Suspendisse venenatis ligula in nulla mattis, et imperdiet ex tincidunt. Etiam vulputate, tellus et ultrices suscipit, enim velit laoreet massa, vitae congue odio enim ac urna. Morbi quam lorem, iaculis ac varius sagittis, euismod quis dolor. In ut dui eu purus feugiat consectetur. Vestibulum cursus velit quis lacus pellentesque iaculis. Cras in risus sed mauris porta rutrum. Nulla facilisi. Nullam eu bibendum est, non pellentesque lectus. Sed imperdiet feugiat lorem, quis convallis ante auctor in. Maecenas justo magna, scelerisque sit amet tellus eget, varius elementum risus. Duis placerat et quam sed varius. + +Duis nec nibh vitae nibh dignissim mollis quis sed felis. Curabitur vitae quam placerat, venenatis purus ut, euismod nisl. Curabitur porttitor nibh eu pulvinar ullamcorper. Suspendisse posuere nec ipsum ac dapibus. Cras convallis consectetur urna. Phasellus a nibh in dolor lacinia posuere id eget augue. In eu pharetra lorem, vitae cursus lacus. Aliquam tincidunt nibh lectus. Aenean facilisis ultricies posuere. Sed ut placerat orci. Curabitur scelerisque gravida blandit. Maecenas placerat ligula eget suscipit fringilla. Mauris a tortor justo. Aliquam hendrerit semper mollis. Phasellus et tincidunt libero. Etiam vel quam libero. + +Quisque aliquet tempor ex. Ut ante sem, vehicula at enim vel, gravida porta elit. Etiam vitae lacus a neque lobortis consectetur. Mauris sed interdum odio. Mauris elementum ex blandit tempor cursus. Integer in enim in leo viverra elementum. Fusce consectetur metus et sem rutrum, mattis euismod diam semper. Nunc sed ipsum vel urna consequat vehicula. Donec cursus pretium lorem, vestibulum pretium felis commodo sit amet. Nam blandit felis enim, eget gravida ex faucibus a. In nec neque massa. Etiam laoreet posuere ipsum. Praesent volutpat nunc dolor, ac vulputate magna facilisis non. Aenean congue turpis vel lectus sollicitudin tristique. Sed nec consequat purus, non vehicula quam. Etiam ultricies, est ac dictum tincidunt, turpis turpis pretium massa, a vulputate libero justo at nibh. + +Aliquam erat volutpat. Cras ultrices augue ac sollicitudin lobortis. Curabitur et aliquet purus. Duis feugiat semper facilisis. Phasellus lobortis cursus velit, a sollicitudin tortor. Nam feugiat sapien non dapibus condimentum. Morbi at mi bibendum, commodo quam at, laoreet enim. Integer eu ultrices enim. Sed vestibulum eu urna ut dictum. Curabitur at mattis leo, sed cursus massa. Aliquam porttitor, felis quis fermentum porttitor, justo velit feugiat nulla, eget condimentum sem dui ut sapien. + +In fringilla elit eu orci aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut eget fringilla tellus. Curabitur fermentum, mi et condimentum suscipit, elit neque bibendum dui, et hendrerit nunc metus id ipsum. Morbi placerat mi in hendrerit congue. Ut feugiat mauris eget scelerisque viverra. Vivamus sit amet erat dictum, sagittis lectus nec, pulvinar lorem. Sed non enim ac dui sollicitudin aliquet. Quisque ut lacus dolor. Fusce hendrerit malesuada euismod. Nulla faucibus vel mauris eu mollis. Mauris est diam, fringilla ac arcu feugiat, efficitur volutpat turpis. Aliquam venenatis cursus massa sed porttitor. Ut ac finibus enim, in tincidunt sapien. + +Nunc faucibus semper turpis a lacinia. Phasellus gravida, libero vel pulvinar ornare, ex sem tincidunt lectus, sit amet convallis augue risus at tortor. Quisque sit amet ipsum id nulla posuere vestibulum. Pellentesque scelerisque mauris vel leo viverra sodales. Nulla viverra aliquam ex, ut rutrum enim fermentum venenatis. Aenean eget dapibus ex, eget faucibus metus. Vestibulum volutpat leo in diam semper, eget porta magna suscipit. Sed sit amet nulla blandit, aliquam dolor ac, gravida velit. Sed vel velit viverra, maximus est id, convallis justo. + +Curabitur nulla ante, vulputate at libero vel, ullamcorper rutrum nibh. Pellentesque porttitor eu mauris id mattis. Duis vulputate augue elit, eget interdum justo pretium vel. Maecenas eu vulputate arcu, eget posuere purus. Suspendisse viverra a velit dictum eleifend. Suspendisse vitae dapibus diam. Donec vehicula justo in ante interdum, eu luctus diam placerat. Vivamus convallis ipsum eu orci suscipit, sed fermentum enim euismod. Maecenas faucibus elit vitae ex ornare tristique. Donec vestibulum nec elit sit amet porttitor. Aenean tempor lectus eget tortor hendrerit luctus. Nullam interdum vitae lectus vel feugiat. Cras in risus non magna consectetur lobortis. Sed faucibus enim quis gravida convallis. + +Phasellus eget massa sit amet libero ultrices suscipit. Vivamus at risus sapien. Nam mollis nunc eget velit dictum maximus. Sed pellentesque, nunc ac fringilla lacinia, quam enim mattis ex, sed euismod tortor metus eu neque. Ut mattis nisl ut lectus rhoncus, sodales bibendum eros porta. Nulla porttitor enim nec diam sagittis, eget porta velit efficitur. Vestibulum ultricies eros neque. Phasellus rutrum suscipit enim, in interdum ante gravida vitae. Sed in sagittis diam, non commodo velit. + +Morbi hendrerit odio orci, nec tincidunt odio rhoncus nec. Mauris neque velit, vehicula a lorem at, suscipit tristique dui. Sed finibus, nisl in mattis convallis, turpis neque sodales lacus, eu porta enim magna non diam. Nam commodo sodales risus consectetur malesuada. In eget elementum justo. Phasellus sit amet massa imperdiet, dapibus nunc sit amet, suscipit orci. Fusce condimentum laoreet feugiat. Ut ut viverra ante. Praesent bibendum interdum commodo. Nulla mollis nisi a est ornare volutpat. Sed at ligula eu nisi dapibus tempus. Proin cursus vestibulum justo, nec efficitur justo dignissim vel. Nunc quis maximus eros. + +Cras viverra, diam a tristique mattis, libero felis vulputate tellus, a ornare felis leo a dui. Nulla ante nulla, finibus ut tellus ut, blandit pharetra nibh. Proin eleifend fermentum ex, eget auctor libero vulputate in. Nullam ultricies, mauris placerat pretium placerat, leo urna lobortis leo, vel placerat arcu libero sed mauris. Aliquam mauris ligula, ornare at urna at, eleifend gravida ligula. Vestibulum consectetur ut nulla non scelerisque. Donec ornare, sem nec elementum aliquam, urna nulla bibendum metus, eu euismod dui ligula ac est. Fusce laoreet erat eu ex lobortis, quis bibendum ligula interdum. Sed vel mi erat. Vivamus id lacus ac enim mattis tempor. Nunc ultricies pellentesque enim sed euismod. Fusce tincidunt convallis elit quis aliquam. Mauris nulla ipsum, sollicitudin quis diam ac, feugiat volutpat tellus. In nibh nibh, vulputate quis tincidunt quis, pulvinar eget magna. Pellentesque quis finibus dolor. Suspendisse viverra vitae lectus non eleifend. + +Nunc ut orci et sapien maximus semper. Nulla dignissim sem urna, ac varius lectus ultricies id. Quisque aliquet pulvinar pretium. In ultricies molestie tellus vehicula porta. Nam enim lorem, aliquam eget ex et, hendrerit volutpat quam. Maecenas diam lacus, pellentesque eget tempus ac, pharetra eu elit. Donec vel eros a sem facilisis vulputate. Nullam ac nisi vulputate, laoreet nisl ac, eleifend sem. Nullam mi massa, rhoncus sed pharetra interdum, tincidunt eget nunc. Aliquam viverra mattis posuere. Mauris et dui sed nisl sollicitudin fermentum quis ut arcu. Nam placerat eget orci at tincidunt. Curabitur vel turpis metus. Phasellus nibh nulla, fermentum scelerisque sem vel, gravida tincidunt velit. Pellentesque vel quam tempor, finibus massa pellentesque, condimentum dui. + +Donec at mattis neque. Etiam velit diam, consequat auctor mauris id, hendrerit faucibus metus. Maecenas ullamcorper eros a est sodales, ac consectetur odio scelerisque. Donec leo metus, imperdiet at pellentesque vel, feugiat id erat. Suspendisse at magna enim. Vestibulum placerat sodales lorem id sollicitudin. Aenean at euismod ligula, eget mollis diam. Phasellus pulvinar, orci nec pretium condimentum, est erat facilisis purus, quis feugiat augue elit aliquam nulla. Aenean vitae tortor id risus congue tincidunt. Sed dolor enim, mattis a ullamcorper id, volutpat ac leo. + +Proin vehicula feugiat augue, id feugiat quam sodales quis. Donec et ultricies massa, a lacinia nulla. Duis aliquam augue ornare euismod viverra. Ut lectus risus, rutrum sit amet efficitur a, luctus nec nisl. Cras volutpat ullamcorper congue. Sed vitae odio metus. Phasellus aliquet euismod varius. + +Nullam sem ex, malesuada ut magna ut, pretium mollis arcu. Nam porttitor eros cursus mi lacinia faucibus. Suspendisse aliquet eleifend iaculis. Maecenas sit amet viverra tortor. Nunc a mollis risus. Etiam tempus dolor in tortor malesuada mattis. Ut tincidunt venenatis est sit amet dignissim. Vestibulum massa enim, tristique sed scelerisque eu, fringilla ac velit. Donec efficitur quis urna sit amet malesuada. Vestibulum consequat ac ligula in dapibus. Maecenas massa massa, molestie non posuere nec, elementum ut magna. In nisi erat, mollis non venenatis eu, faucibus in justo. Morbi gravida non ex non egestas. Pellentesque finibus laoreet diam, eu commodo augue congue vitae. + +Aenean sem mi, ullamcorper dapibus lobortis vitae, interdum tincidunt tortor. Vivamus eget vulputate libero. Ut bibendum posuere lectus, vel tincidunt tortor aliquet at. Phasellus malesuada orci et bibendum accumsan. Aliquam quis libero vel leo mollis porta. Sed sagittis leo ac lacus dictum, ac malesuada elit finibus. Suspendisse pharetra luctus commodo. Vivamus ultricies a odio non interdum. Vivamus scelerisque tincidunt turpis quis tempor. Pellentesque tortor ligula, varius non nunc eu, blandit sollicitudin neque. Nunc imperdiet, diam et tristique luctus, ipsum ex condimentum nunc, sit amet aliquam justo velit sed libero. Duis vel suscipit ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed tincidunt neque vel massa ultricies, id dictum leo consequat. Curabitur lobortis ultricies tellus, eget mattis nisl aliquam sit amet. + +Proin at suscipit justo. Vivamus ut vestibulum nisl. Pellentesque enim odio, pharetra non magna sed, efficitur auctor magna. Praesent tincidunt ante quis ante hendrerit viverra. Pellentesque vel ipsum id magna vulputate efficitur. Sed nec neque accumsan, pulvinar sapien quis, euismod mauris. Donec condimentum laoreet sapien quis gravida. Quisque sed mattis purus. Vestibulum placerat vel neque maximus scelerisque. + +Vestibulum mattis quam quis efficitur elementum. Duis dictum dolor ac scelerisque commodo. Fusce sollicitudin nisi sit amet dictum placerat. Suspendisse euismod pharetra eleifend. In eros nisl, porttitor sed mauris at, consectetur aliquet mauris. Donec euismod viverra neque sed fermentum. Phasellus libero magna, accumsan ut ultricies vitae, dignissim eget metus. Donec tellus turpis, interdum eget maximus nec, hendrerit eget massa. Curabitur auctor ligula in iaculis auctor. In ultrices quam suscipit cursus finibus. Aenean id mi at dolor interdum iaculis vitae ut lorem. Nullam sed nibh fringilla, lacinia odio nec, placerat erat. In dui libero, viverra ac viverra ac, pellentesque sit amet turpis. + +Nulla in enim ex. Sed feugiat est et consectetur venenatis. Cras varius facilisis dui vel convallis. Vestibulum et elit eget tellus feugiat pellentesque. In ut ante eu purus aliquet posuere. Nulla nec ornare sem, sed luctus lorem. Nam varius iaculis odio, eget faucibus nisl ullamcorper in. Sed eget cursus felis, nec efficitur nisi. + +Vivamus commodo et sem quis pulvinar. Pellentesque libero ante, venenatis vitae ligula sit amet, ornare sollicitudin nulla. Mauris eget tellus hendrerit, pulvinar metus quis, tempor nisi. Proin magna ex, laoreet sed tortor quis, varius fermentum enim. Integer eu dolor dictum, vulputate tortor et, aliquet ligula. Vestibulum vitae justo id mauris luctus sollicitudin. Suspendisse eget auctor neque, sodales egestas lorem. Vestibulum lacinia egestas metus vitae euismod. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus ex tellus, volutpat nec pulvinar sit amet, condimentum vitae dui. Curabitur vel felis sodales, lacinia nunc iaculis, ullamcorper augue. Pellentesque consequat dolor quis eros efficitur malesuada. Nulla ut malesuada lectus. + +Morbi et tristique ante. Aliquam erat volutpat. Vivamus vitae dui nec turpis pellentesque fermentum. Quisque eget velit massa. Pellentesque tristique aliquam nisl, eu sollicitudin justo venenatis sed. Duis eleifend sem eros, ut aliquam libero porttitor id. Sed non nunc consequat, rhoncus diam eu, commodo erat. Praesent fermentum in lectus id blandit. Donec quis ipsum at justo volutpat finibus. Nulla blandit justo nulla, at mollis lacus consequat eget. Aenean sollicitudin quis eros ut ullamcorper. + +Pellentesque venenatis nulla ut mi aliquet feugiat. Cras semper vel magna nec pharetra. Integer mattis felis et sapien commodo imperdiet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis quis luctus felis. Vestibulum justo nibh, aliquam non lectus vitae, molestie placerat justo. Donec lorem nibh, gravida sit amet hendrerit ac, maximus id ipsum. Nunc ac libero sodales risus eleifend sagittis. Phasellus est massa, lobortis elementum ex sed, scelerisque consectetur neque. Nunc faucibus neque id lorem malesuada, eget convallis ex mattis. + +Sed turpis tortor, fermentum non turpis id, posuere varius nibh. Donec iaculis lorem dui. Etiam eros ante, sodales eget venenatis at, consectetur eget risus. Curabitur non aliquam ante, a pretium justo. Maecenas tempor nisl tortor, vitae dictum nisi ultrices eu. Duis eget dui ultrices, porttitor lacus sed, lobortis purus. Quisque mattis elit nec neque sagittis, sed commodo leo blandit. Mauris sodales interdum eleifend. Vestibulum condimentum consectetur augue, id luctus diam convallis et. + +Nunc suscipit risus in justo accumsan, a placerat magna tincidunt. Proin a nisl ipsum. Sed libero dui, tristique in augue quis, auctor tristique risus. Sed porttitor ex augue, eu porta augue molestie a. Duis rhoncus purus libero, eu tempus turpis condimentum at. Sed mollis nisi id lectus placerat tincidunt. Maecenas non scelerisque elit, quis rutrum orci. Donec in tellus pharetra urna ornare lobortis. Phasellus id risus at nisi varius rutrum eu ut turpis. + +Duis dictum justo quis nisl porta, eget tincidunt magna suscipit. Sed velit massa, ullamcorper eu sodales ac, pretium a massa. Duis et rutrum tortor. Nulla accumsan hendrerit sapien, cursus volutpat eros egestas eget. Donec sollicitudin at ante quis sollicitudin. Aenean blandit feugiat diam, id feugiat eros faucibus eget. Donec viverra dolor vel justo scelerisque dignissim. Nulla semper sem nunc, rhoncus semper tellus ultricies sed. Duis in ornare diam. Donec vehicula feugiat varius. Maecenas ut suscipit est. Vivamus sem sem, finibus at dolor sit amet, euismod dapibus ligula. Vestibulum fringilla odio dapibus, congue massa eget, congue sem. Donec feugiat magna eget tortor lacinia scelerisque non et ipsum. + +Suspendisse potenti. Nunc convallis sollicitudin ex eget venenatis. Sed iaculis nibh ex, vel ornare ligula congue dignissim. Quisque sollicitudin dolor ac dui vestibulum, sit amet molestie nisi aliquet. Donec at risus felis. Aenean sollicitudin metus a feugiat porta. Aenean a tortor ut dolor cursus sagittis. Vivamus consectetur porttitor nunc in facilisis. Proin sit amet mi vel lectus consectetur ultrices. + +Sed cursus lectus vitae nunc tristique, nec commodo turpis dapibus. Pellentesque luctus ex id facilisis ornare. Morbi quis placerat dolor. Donec in lectus in arcu mattis porttitor ac sit amet metus. Cras congue mauris non risus sodales, vitae feugiat ipsum bibendum. Nulla venenatis urna sed libero elementum, a cursus lorem commodo. Mauris faucibus lobortis eros nec commodo. + +Nullam suscipit ligula ullamcorper lorem commodo blandit. Nulla porta nibh quis pulvinar placerat. Vivamus eu arcu justo. Vestibulum imperdiet est ut fermentum porttitor. Pellentesque consectetur libero in sapien efficitur scelerisque. Curabitur ac erat sit amet odio aliquet dignissim. Pellentesque mi sem, rhoncus et luctus at, porttitor rutrum lectus. Vestibulum sollicitudin sollicitudin suscipit. Aenean efficitur dolor non ultrices imperdiet. Donec vel sem ex. + +Sed convallis mauris aliquam rutrum cursus. Ut tempor porttitor sodales. Etiam eu risus ac augue gravida egestas et eu dolor. Proin id magna ex. Suspendisse quis lectus quis lorem ultricies tempus. Donec porttitor velit vitae tincidunt faucibus. Aliquam vitae semper nisi. Morbi ultrices, leo non pretium dapibus, dui libero pellentesque ex, vel placerat enim ante vitae dui. Nunc varius, sem sit amet sagittis lobortis, lectus odio scelerisque mauris, ut vestibulum orci magna quis neque. Sed id congue justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris congue nisi est, malesuada mollis elit tincidunt sed. Curabitur sed ex sit amet felis tristique elementum vitae vel nibh. + +Etiam mollis pretium lobortis. Mauris augue lacus, efficitur at lacus sed, mollis tincidunt lectus. Aliquam erat volutpat. Donec at euismod elit, et mattis felis. Sed id lobortis urna. Morbi imperdiet vestibulum leo, sed maximus leo blandit eu. Aliquam semper lorem neque, nec euismod turpis mattis mollis. Quisque lobortis urna ultrices odio pretium, ac venenatis orci faucibus. Suspendisse bibendum odio ligula, sed lobortis massa pharetra nec. Donec turpis justo, iaculis at dictum ac, finibus eu libero. Maecenas quis porttitor mi, sit amet aliquet neque. + +Vivamus auctor vulputate ante, at egestas lorem. Donec eu risus in nulla mollis ultricies at et urna. Duis accumsan porta egestas. Ut vel euismod augue. Fusce convallis nulla ante, nec fringilla velit aliquet at. Nam malesuada dapibus ligula, a aliquam nibh scelerisque ac. Praesent malesuada neque et pellentesque interdum. Curabitur volutpat at turpis vitae tristique. Vivamus porttitor semper congue. Quisque suscipit lacus mi, rhoncus ultrices tortor auctor quis. Maecenas neque neque, molestie ac facilisis eget, luctus ac lorem. In ut odio ut lacus suscipit pulvinar vitae sed elit. Nulla imperdiet, sem quis euismod sagittis, dui erat luctus dolor, faucibus faucibus erat sem eget nunc. Nam accumsan placerat malesuada. Maecenas convallis finibus pulvinar. + +Cras at placerat tortor. Morbi facilisis auctor felis sit amet molestie. Donec sodales sed lorem vitae suscipit. Etiam fermentum pharetra ipsum, nec luctus orci gravida eu. Pellentesque gravida, est non condimentum tempus, mauris ligula molestie est, in congue dolor nisl vel sapien. Duis congue tempor augue, id rutrum eros porta dapibus. Etiam rutrum eget est eget vestibulum. Aenean mollis arcu vel consequat varius. Praesent at condimentum felis. Duis nec interdum nisl. Donec commodo lorem sed sapien scelerisque malesuada non eu urna. In blandit non ipsum at porta. Nam lobortis leo vitae dui auctor, non feugiat quam bibendum. Donec auctor lectus sagittis laoreet maximus. Maecenas rhoncus laoreet porttitor. Vestibulum porttitor augue ut lectus hendrerit, eget posuere mi gravida. + +Sed mattis ex in erat pulvinar, eu imperdiet magna dapibus. Etiam nisi nibh, tempus non tellus sit amet, mattis tempor odio. Quisque nec lorem feugiat, lobortis odio et, commodo nunc. Maecenas semper purus nisi, nec vehicula nibh eleifend vitae. Nulla fermentum a lectus at maximus. Phasellus finibus metus non euismod ultrices. Etiam a pulvinar ante. Quisque convallis nec metus sit amet facilisis. Praesent laoreet massa et sollicitudin laoreet. Vestibulum in mauris aliquet, convallis mi ut, elementum purus. Nulla purus nulla, sodales at hendrerit quis, tempus sed lectus. + +Nam ut laoreet neque, ut maximus nibh. Maecenas quis justo pellentesque, sollicitudin elit at, venenatis velit. Aenean nunc velit, vehicula scelerisque odio at, consectetur laoreet purus. Duis dui purus, malesuada quis ipsum sit amet, tempor interdum libero. Curabitur porta scelerisque sapien, vitae cursus diam condimentum eu. Phasellus sed orci quam. Nullam vitae dui quis purus tincidunt vestibulum. Curabitur quis nulla porta, cursus arcu non, auctor enim. Etiam sollicitudin ex id sem vehicula mollis. Morbi viverra laoreet tincidunt. Praesent ut semper dui. Nam sit amet pretium neque. Mauris vitae luctus diam, in lacinia purus. Maecenas ut placerat justo, ut porta felis. Integer eu mauris ante. + +Aenean porttitor tellus diam, tempor consequat metus efficitur id. Suspendisse ut felis at erat tempor dictum at nec sapien. Sed vestibulum interdum felis, ac mattis mauris porta in. Nunc et condimentum massa. Sed cursus dictum justo et luctus. Integer convallis enim nisl, a rutrum lectus ultricies in. Donec dapibus lacus at nulla dapibus, id sollicitudin velit hendrerit. Fusce a magna at orci mollis rutrum ac a dolor. Aliquam erat volutpat. Morbi varius porta nunc, sit amet sodales ex hendrerit commodo. Donec tincidunt tortor sapien, vitae egestas sapien vehicula eget. + +Suspendisse potenti. Donec pulvinar felis nec leo malesuada interdum. Integer posuere placerat maximus. Donec nibh ipsum, tincidunt vitae luctus vitae, bibendum at leo. Sed cursus nisl ut ex faucibus aliquet sed nec eros. Curabitur molestie posuere felis. Integer faucibus velit eget consequat iaculis. Mauris sed vulputate odio. Phasellus maximus, elit a pharetra egestas, lorem magna semper tellus, vestibulum semper diam felis at sapien. Suspendisse facilisis, nisl sit amet euismod vehicula, libero nulla vehicula dolor, quis fermentum nibh elit sit amet diam. + +Morbi lorem enim, euismod eu varius ut, scelerisque quis odio. Nam tempus vitae eros id molestie. Nunc pretium in nulla eget accumsan. Quisque mattis est ut semper aliquet. Maecenas eget diam elementum, fermentum ipsum a, euismod sapien. Duis quam ligula, cursus et velit nec, ullamcorper tincidunt magna. Donec vulputate nisl est, et ullamcorper urna tempor sit amet. + +Proin lacinia dui non turpis congue pretium. Morbi posuere metus vel purus imperdiet interdum. Morbi venenatis vel eros non ultricies. Nulla vel semper elit. Ut quis purus tincidunt, auctor justo ut, faucibus turpis. Proin quis mattis erat, at faucibus ligula. Mauris in mauris enim. Donec facilisis enim at est feugiat hendrerit. Nam vel nisi lorem. Fusce ultricies convallis diam, in feugiat tortor luctus quis. Donec tempor, leo vitae volutpat aliquam, magna elit feugiat leo, quis placerat sapien felis eget arcu. Donec ornare fermentum eleifend. Integer a est orci. + +Proin rhoncus egestas leo. Nulla ultricies porta elit quis ornare. Nunc fermentum interdum vehicula. In in ligula lorem. Donec nec arcu sit amet orci lobortis iaculis. Mauris at mollis erat, sit amet mollis tortor. Mauris laoreet justo ullamcorper porttitor auctor. Aenean sit amet aliquam lectus, id fermentum eros. Praesent urna sem, vehicula ac fermentum id, dapibus ut purus. Vestibulum vitae tempus nunc. Donec at nunc ornare metus volutpat porta at eget magna. Donec varius aliquet metus, eu lobortis risus aliquam sed. Ut dapibus fermentum velit, ac tincidunt libero faucibus at. + +In in purus auctor, feugiat massa quis, facilisis nisi. Donec dolor purus, gravida eget dolor ac, porttitor imperdiet urna. Donec faucibus placerat erat, a sagittis ante finibus ac. Sed venenatis dignissim elit, in iaculis felis posuere faucibus. Praesent sed viverra dolor. Mauris sed nulla consectetur nunc laoreet molestie in ut metus. Proin ac ex sit amet magna vulputate hendrerit ac condimentum urna. Proin ligula metus, gravida et sollicitudin facilisis, iaculis ut odio. Cras tincidunt urna et augue varius, ut facilisis urna consequat. Aenean vehicula finibus quam. Ut iaculis eu diam ac mollis. Nam mi lorem, tristique eget varius at, sodales at urna. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin vitae dictum erat, et auctor ipsum. Nullam nunc nunc, sollicitudin quis magna a, vestibulum fermentum mauris. Praesent at erat dolor. Proin laoreet tristique nulla vel efficitur. Nam sed ultrices nibh, id rutrum nunc. Curabitur eleifend a erat sit amet sollicitudin. Nullam metus quam, laoreet vitae dapibus id, placerat sed leo. Aliquam erat volutpat. Donec turpis nisl, cursus eu ex sit amet, lacinia pellentesque nisl. Sed id ipsum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec interdum scelerisque lorem eu mattis. + +Vivamus ac tristique massa, nec facilisis nisl. Nam ipsum neque, tincidunt vel urna in, cursus imperdiet enim. Nam pellentesque egestas tempus. Morbi facilisis imperdiet libero vitae fringilla. Nam lacinia ligula at sapien facilisis malesuada. Nullam accumsan pulvinar sem, et cursus libero porta sit amet. Curabitur vulputate erat elit, ut pulvinar erat maximus vel. + +Cras aliquet metus ut purus sagittis, vel venenatis ante consectetur. Pellentesque nulla lacus, viverra viverra mattis non, placerat vitae nibh. Donec enim turpis, accumsan sit amet tincidunt eu, imperdiet non metus. Morbi ipsum eros, tincidunt vel est ac, tristique porttitor nibh. Praesent ut ullamcorper mauris. Sed laoreet sit amet diam congue venenatis. Integer porta purus nec orci sagittis posuere. + +Donec vehicula mauris eget lacus mollis venenatis et sed nibh. Nam sodales ligula ipsum, scelerisque lacinia ligula sagittis in. Nam sit amet ipsum at erat malesuada congue. Aenean ut sollicitudin sapien. Etiam at tempor odio. Mauris vitae purus ut magna suscipit consequat. Vivamus quis sapien neque. Nulla vulputate sem sit amet massa pellentesque, eleifend tristique ligula egestas. Suspendisse tincidunt gravida mi, in pulvinar lectus egestas non. Aenean imperdiet ex sit amet nunc sollicitudin porta. Integer justo odio, ultricies at interdum in, rhoncus vitae sem. Sed porttitor arcu quis purus aliquet hendrerit. Praesent tempor tortor at dolor dictum pulvinar. Nulla aliquet nunc non ligula scelerisque accumsan. Donec nulla justo, congue vitae massa in, faucibus hendrerit magna. Donec non egestas purus. + +Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibus mattis neque dictum sed. Sed convallis fermentum molestie. Nulla facilisi turpis duis. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vulputate, ipsum quis interdum fermentum, lorem sem fermentum eros, vitae auctor neque lacus in nisi. Suspendisse potenti. Maecenas et scelerisque elit, in tincidunt quam. Sed eu tincidunt quam. Nullam justo ex, imperdiet a imperdiet et, fermentum sit amet eros. Aenean quis tempus sem. Pellentesque accumsan magna mi, ut mollis velit sagittis id. Etiam quis ipsum orci. Fusce purus ante, accumsan a lobortis at, venenatis eu nisl. Praesent ornare sed ante placerat accumsan. Suspendisse tempus dignissim fermentum. Nunc a leo ac lacus sodales iaculis eu vitae mi. In feugiat ante at massa finibus cursus. Suspendisse posuere fringilla ornare. Mauris elementum ac quam id convallis. Vestibulum non elit quis urna volutpat aliquam a eu lacus. + +Aliquam vestibulum imperdiet neque, suscipit aliquam elit ultrices bibendum. Suspendisse ultrices pulvinar cursus. Morbi risus nisi, cursus consequat rutrum vitae, molestie sed dui. Fusce posuere, augue quis dignissim aliquam, nisi ipsum porttitor ante, quis fringilla nisl turpis ac nisi. Nulla varius enim eget lorem vehicula gravida. Donec finibus malesuada leo nec semper. Proin ac enim eros. Vivamus non tincidunt nisi, vel tristique lorem. + +Nunc consequat ex id eros dignissim, id rutrum risus laoreet. Sed euismod non erat eu ultricies. Etiam vehicula gravida lacus ut porta. Vestibulum eu eros quis nunc aliquet luctus. Cras quis semper ligula. Nullam gravida vehicula quam sed porta. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In porta cursus vulputate. Quisque porta a nisi eget cursus. Aliquam risus leo, luctus ac magna in, efficitur cursus magna. In condimentum non mi id semper. Donec interdum ante eget commodo maximus. + +Vivamus sit amet vestibulum lectus. Fusce tincidunt mi sapien, dictum sollicitudin diam vulputate in. Integer fringilla consequat mollis. Cras aliquet consequat felis eget feugiat. Nunc tempor cursus arcu, vitae ornare nunc varius et. Vestibulum et tortor vel ante viverra porttitor. Nam at tortor ullamcorper, facilisis augue quis, tristique erat. Aenean ut euismod nibh. Quisque eu tincidunt est, nec euismod eros. + +Proin vehicula nibh non viverra egestas. Phasellus sem dolor, ultricies ac sagittis tristique, lacinia a purus. Vestibulum in ante eros. Pellentesque lacus nulla, tristique vitae interdum vel, malesuada ac diam. Aenean bibendum posuere turpis in accumsan. Ut est nulla, ullamcorper quis turpis at, viverra sagittis mauris. Sed in interdum purus. Praesent scelerisque nibh eget sem euismod, ut imperdiet mi venenatis. Vivamus pulvinar orci sed dapibus auctor. Nulla facilisi. Vestibulum tincidunt erat nec porttitor egestas. Mauris quis risus ante. Nulla facilisi. + +Aliquam ullamcorper ornare lobortis. Phasellus quis sem et ipsum mollis malesuada sed in ex. Ut aliquam ex eget metus finibus maximus. Proin suscipit mauris eu nibh lacinia, quis feugiat dui dapibus. Nam sed libero est. Aenean vulputate orci sit amet diam faucibus, eu sagittis sapien volutpat. Nam imperdiet felis turpis, at pretium odio pulvinar in. Sed vestibulum id eros nec ultricies. Sed quis aliquam tortor, vitae ullamcorper tellus. Donec egestas laoreet eros, id suscipit est rutrum nec. Sed auctor nulla eget metus aliquam, ut condimentum enim elementum. + +Aliquam suscipit non turpis sit amet bibendum. Fusce velit ligula, euismod et maximus at, luctus sed neque. Quisque pretium, nisl at ullamcorper finibus, lectus leo mattis sapien, vel euismod mauris diam ullamcorper ex. Nulla ut risus finibus, lacinia ligula at, auctor erat. Mauris consectetur sagittis ligula vel dapibus. Nullam libero libero, lobortis aliquam libero vel, venenatis ultricies leo. Duis porttitor, nibh congue fermentum posuere, erat libero pulvinar tortor, a pellentesque nunc ipsum vel sem. Nullam volutpat, eros sit amet facilisis consectetur, ipsum est vehicula massa, non vestibulum neque elit in mauris. Nunc hendrerit ipsum non enim bibendum, vitae rhoncus mi egestas. Etiam ullamcorper massa vel nisl sagittis, nec bibendum arcu malesuada. Aenean aliquet turpis justo, a consectetur arcu mollis convallis. Etiam tellus ipsum, ultricies vitae lorem et, ornare facilisis orci. Praesent fringilla justo urna, vel mollis neque pulvinar vestibulum. + +Donec non iaculis erat. Aliquam et mi sed nunc pulvinar ultricies in ut ipsum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Praesent feugiat lacus ac dignissim semper. Phasellus vitae quam nisi. Morbi vel diam ultricies risus lobortis ornare. Fusce maximus et ligula quis iaculis. Sed congue ex eget felis convallis, sit amet hendrerit elit tempor. Donec vehicula blandit ante eget commodo. Vestibulum eleifend diam at feugiat euismod. Etiam magna tellus, dignissim eget fermentum vel, vestibulum vitae mauris. Nam accumsan et erat id sagittis. Donec lacinia, odio ut ornare ultricies, dolor velit accumsan tortor, non finibus erat tellus quis ligula. Nunc quis metus in leo volutpat ornare vulputate eu nisl. + +Donec quis viverra ex. Nullam id feugiat mauris, eu fringilla nulla. Vestibulum id maximus elit. Cras elementum elit sed felis lobortis, eget sagittis nisi hendrerit. Vivamus vitae elit neque. Donec vulputate lacus ut libero ultrices accumsan. Vivamus accumsan nulla orci, in dignissim est laoreet sagittis. Proin at commodo velit. Curabitur in velit felis. Aliquam erat volutpat. Sed consequat, nulla et cursus sodales, nisi lacus mattis risus, quis eleifend erat ex nec turpis. Sed suscipit ultrices lorem in hendrerit. + +Morbi vitae lacus nec libero ornare tempus eu et diam. Suspendisse magna ipsum, fermentum vel odio quis, molestie aliquam urna. Fusce mollis turpis a eros accumsan porttitor. Pellentesque rhoncus dolor sit amet magna rutrum, et dapibus justo tempor. Sed purus nisi, maximus vitae fringilla eu, molestie nec urna. Fusce malesuada finibus pretium. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec sed aliquet eros. Pellentesque luctus diam ante, eget euismod nisl aliquet eu. Sed accumsan elit purus, tempor varius ligula tempus nec. Curabitur ornare leo suscipit suscipit fermentum. Morbi eget nulla est. Maecenas faucibus interdum tristique. + +Etiam ut elit eros. Nulla pharetra suscipit molestie. Nulla facilisis bibendum nisl non molestie. Curabitur turpis lectus, facilisis vel diam non, vulputate ultrices mauris. Aenean placerat aliquam convallis. Suspendisse sed scelerisque tellus. Vivamus lacinia neque eget risus cursus suscipit. Proin consequat dolor vel neque tempor, eu aliquam sem scelerisque. Duis non eros a purus malesuada pharetra non et nulla. Suspendisse potenti. Mauris libero eros, finibus vel nulla id, sagittis dapibus ante. Proin iaculis sed nunc et cursus. + +Quisque accumsan lorem sit amet lorem aliquet euismod. Curabitur fermentum rutrum posuere. Etiam ultricies, sem id pellentesque suscipit, urna magna lacinia eros, quis efficitur risus nisl at lacus. Nulla quis lacus tortor. Mauris placerat ex in dolor tincidunt, vel aliquet nisi pretium. Cras iaculis risus vitae pellentesque aliquet. Quisque a enim imperdiet, ullamcorper arcu vitae, rutrum risus. Nullam consectetur libero at felis fringilla, nec congue nibh dignissim. Nam et lobortis felis, eu pellentesque ligula. Aenean facilisis, ligula non imperdiet maximus, massa orci gravida sapien, at sagittis lacus nisl in lacus. Nulla quis mauris luctus, scelerisque felis consequat, tempus risus. Fusce auctor nisl non nulla luctus molestie. Maecenas sapien nisl, auctor non dolor et, iaculis scelerisque lorem. Suspendisse egestas enim aliquet, accumsan mauris nec, posuere quam. Nulla iaculis dui dui, sit amet vestibulum erat ultricies ac. + +Cras eget dolor erat. Proin at nisl ut leo consectetur ultricies vel ut arcu. Nulla in felis malesuada, ullamcorper tortor et, convallis massa. Nunc urna justo, ornare in nibh vitae, hendrerit condimentum libero. Etiam vitae libero in purus venenatis fringilla. Nullam velit nulla, consequat ut turpis non, egestas hendrerit nibh. Duis tortor turpis, interdum non ante ac, cursus accumsan lectus. Cras pharetra bibendum augue quis dictum. Sed euismod vestibulum justo. Proin porta lobortis purus. Duis venenatis diam tortor, sit amet condimentum eros rhoncus a. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc at magna nec diam lobortis efficitur sit amet ut lacus. Nulla quis orci tortor. Pellentesque tempus velit a odio finibus porta. + +Proin feugiat mauris a tellus scelerisque convallis. Maecenas libero magna, blandit nec ultrices id, congue vel mi. Aliquam lacinia, quam vel condimentum convallis, tortor turpis aliquam odio, sed blandit libero lacus et eros. In eleifend iaculis magna ac finibus. Praesent auctor facilisis tellus in congue. Sed molestie lobortis dictum. Nam quis dignissim augue, vel euismod lorem. Curabitur posuere dapibus luctus. Donec ultricies dictum lectus, quis blandit arcu commodo ac. Aenean tincidunt ligula in nunc imperdiet dignissim. Curabitur egestas sollicitudin sapien ut semper. Aenean nec dignissim lacus. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec aliquam dictum vehicula. Donec tortor est, volutpat non nisi nec, varius gravida ex. Nunc vel tristique nunc, vitae mattis nisi. Nunc nec luctus ex, vitae tincidunt lectus. In hac habitasse platea dictumst. Curabitur lobortis ex eget tincidunt tempor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut a vehicula mi. + +Fusce eu libero finibus, interdum nulla a, placerat neque. Cras bibendum tempor libero nec feugiat. Cras ut sodales eros. Proin viverra, massa sit amet viverra egestas, neque nisl porta ex, sit amet hendrerit libero ligula vel urna. Mauris suscipit lacus id justo rhoncus suscipit. Etiam vel libero tellus. Maecenas non diam molestie, condimentum tellus a, bibendum enim. Mauris aliquet imperdiet tellus, eget sagittis dolor. Sed blandit in neque et luctus. Cras elementum sagittis nunc, vel mollis lorem euismod et. Donec posuere at lacus eget suscipit. + +Nulla nunc mi, pretium non massa vel, tempor semper magna. Nunc a leo pulvinar, tincidunt nunc at, dignissim mi. Aliquam erat volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut viverra nulla a nisl finibus, at hendrerit ligula ullamcorper. Donec a lorem semper, tempor magna et, lobortis libero. Mauris id sapien leo. Donec dignissim, quam vitae porttitor dignissim, quam justo mattis dui, vel consequat odio elit quis orci. Etiam nec pretium neque, sit amet pretium orci. Duis ac tortor venenatis, feugiat purus non, feugiat nunc. Proin scelerisque nisl in turpis aliquam vulputate. + +Praesent sed est semper, fringilla lorem vitae, tincidunt nibh. Cras eros metus, auctor at mauris sit amet, sodales semper orci. Nunc a ornare ex. Curabitur bibendum arcu congue urna vulputate egestas. Vestibulum finibus id risus et accumsan. Aenean ut volutpat tellus. Aenean tincidunt malesuada urna sit amet vestibulum. Mauris vel tellus dictum, varius lacus quis, dictum arcu. + +Aenean quis metus eu erat feugiat cursus vel at ligula. Proin dapibus sodales urna, id euismod lectus tempus id. Pellentesque ex ligula, convallis et erat vel, vulputate condimentum nisl. Pellentesque pharetra nulla quis massa eleifend hendrerit. Praesent sed massa ipsum. Maecenas vehicula dolor massa, id sodales urna faucibus et. Mauris ac quam non massa tincidunt feugiat et at lacus. Fusce libero massa, vulputate vel scelerisque non, mollis in leo. Ut sit amet ultricies odio. Suspendisse in sapien viverra, facilisis purus ut, pretium libero. + +Vivamus tristique pharetra molestie. Nam a volutpat purus. Praesent consequat gravida nisi, ac blandit nisi suscipit ut. Quisque posuere, ligula a ultrices laoreet, ligula nunc vulputate libero, ut rutrum erat odio tincidunt justo. Sed vitae leo at leo fringilla bibendum. Vestibulum ut augue nec dolor auctor accumsan. Praesent laoreet id eros pulvinar commodo. Suspendisse potenti. Ut pharetra, mauris vitae blandit fringilla, odio ante tincidunt lorem, sit amet tempor metus diam ut turpis. + +Praesent quis egestas arcu. Nullam at porta arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi vulputate ligula malesuada ligula luctus, vulputate tempus erat bibendum. Nunc ullamcorper non lectus at euismod. Etiam nibh felis, tincidunt a metus vel, pellentesque rhoncus neque. Etiam at diam in erat luctus interdum. Nunc vel ipsum pulvinar, sollicitudin lacus ac, tempus urna. Etiam vel lacinia sapien. Pellentesque sagittis velit vel mi efficitur iaculis. Integer euismod sit amet urna in sagittis. Cras eleifend ut nibh in facilisis. Donec et lacus vitae nunc placerat sodales. Nulla sed hendrerit ligula, at dapibus sapien. + +Praesent at iaculis ex. Curabitur est purus, cursus a faucibus quis, dictum id velit. Donec dignissim fringilla viverra. Nunc mauris felis, laoreet sit amet sagittis at, vestibulum in libero. Maecenas quis orci turpis. Quisque ut nibh vitae magna mollis consequat id at mauris. Aliquam eu odio eget nulla bibendum sodales. Quisque vel orci eleifend nisi pretium lacinia. Suspendisse eget risus eget mi volutpat molestie eget quis lacus. Duis nisi libero, tincidunt nec nulla id, faucibus cursus felis. + +Donec tempor eget risus pellentesque molestie. Phasellus porta neque vel arcu egestas, nec blandit velit fringilla. Nullam porta faucibus justo vitae laoreet. Pellentesque viverra id nunc eu varius. Nulla pulvinar lobortis iaculis. Etiam vestibulum odio nec velit tristique, a tristique nisi mattis. In sed fringilla orci, vitae efficitur odio. Quisque dui odio, ornare eget velit at, lacinia consequat libero. Quisque lectus nulla, aliquet eu leo in, porta rutrum diam. Donec nec mattis neque. Nam rutrum, odio ac eleifend bibendum, dolor arcu rutrum neque, eget porta elit tellus a lacus. Sed massa metus, sollicitudin et sapien eu, finibus tempus orci. Proin et sapien sit amet erat molestie interdum. In quis rutrum velit, faucibus ultrices tellus. + +Sed sagittis sed justo eget tincidunt. Maecenas ut leo sagittis, feugiat magna et, viverra velit. Maecenas ex arcu, feugiat at consequat vitae, auctor eu massa. Integer egestas, enim vitae maximus convallis, est lectus pretium mauris, ac posuere lectus nisl quis quam. Aliquam tempus laoreet mi, vitae dapibus dolor varius dapibus. Suspendisse potenti. Donec sit amet purus nec libero dapibus tristique. Pellentesque viverra bibendum ligula. Donec sed felis et ex lobortis laoreet. Phasellus a fringilla libero, vitae malesuada nulla. Pellentesque blandit mattis lacus, et blandit tortor laoreet consequat. Suspendisse libero nunc, viverra sed fermentum in, accumsan egestas arcu. Proin in placerat elit. Sed interdum imperdiet malesuada. Suspendisse aliquet quis mauris eget sollicitudin. + +Vivamus accumsan tellus non erat volutpat, quis dictum dolor feugiat. Praesent rutrum nunc ac est mollis cursus. Fusce semper volutpat dui ut egestas. Curabitur sit amet posuere massa. Cras tincidunt nulla et mi mollis imperdiet. Suspendisse scelerisque ex id sodales vulputate. In nunc augue, pharetra in placerat eu, mattis id tellus. Vivamus cursus efficitur vehicula. Nulla aliquet vehicula aliquet. + +Sed cursus tellus sed porta pulvinar. Sed vitae nisi neque. Nullam aliquet, lorem et efficitur scelerisque, arcu diam aliquam felis, sed pulvinar lorem odio et turpis. Praesent convallis pulvinar turpis eu iaculis. Aliquam nec gravida mi. Curabitur eu nibh tempor, blandit justo in, ultrices felis. Fusce placerat metus non mi sagittis rutrum. Morbi sed dui fringilla, sagittis mauris eget, imperdiet nunc. Phasellus hendrerit sem elit, id hendrerit libero auctor sit amet. Integer sodales elit sit amet consequat cursus. + +Nam semper est eget nunc mollis, in pellentesque lectus fringilla. In finibus vel diam id semper. Nunc mattis quis erat eu consectetur. In hac habitasse platea dictumst. Nullam et ipsum vestibulum ex pulvinar ultricies sit amet id velit. Aenean suscipit mi tortor, a lobortis magna viverra non. Nulla condimentum aliquet ante et ullamcorper. Pellentesque porttitor arcu a posuere tempus. Aenean lacus quam, imperdiet eu justo vitae, pretium efficitur ex. Duis id purus id magna rhoncus ultrices id eu risus. Nunc dignissim et libero id dictum. + +Quisque a tincidunt neque. Phasellus commodo mi sit amet tempor fringilla. Ut rhoncus, neque non porttitor elementum, libero nulla egestas augue, sed fringilla sapien felis ac velit. Phasellus viverra rhoncus mollis. Nam ullamcorper leo vel erat laoreet luctus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus semper a metus a cursus. Nulla sed orci egestas, efficitur purus ac, malesuada tellus. Aenean rutrum velit at tellus fermentum mollis. Aliquam eleifend euismod metus. + +In hac habitasse platea dictumst. Vestibulum volutpat neque vitae porttitor laoreet. Nam at tellus consequat, sodales quam in, pulvinar arcu. Maecenas varius convallis diam, ac lobortis tellus pellentesque quis. Maecenas eget augue massa. Nullam volutpat nibh ac justo rhoncus, ut iaculis tellus rutrum. Fusce efficitur efficitur libero quis condimentum. Curabitur congue neque non tincidunt tristique. Fusce eget tempor ex, at pellentesque odio. Praesent luctus dictum vestibulum. Etiam non orci nunc. Vivamus vitae laoreet purus, a lobortis velit. Curabitur tincidunt purus ac lectus elementum pellentesque. Quisque sed tincidunt est. + +Sed vel ultrices massa, vitae ultricies justo. Cras finibus mauris nec lacus tempus dignissim. Cras faucibus maximus velit, eget faucibus orci luctus vehicula. Nulla massa nunc, porta ac consequat eget, rhoncus non tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce sed maximus metus, vel imperdiet ipsum. Ut scelerisque lectus at blandit porttitor. Ut vulputate nunc pharetra, aliquet sapien ac, sollicitudin sapien. Aenean eget ante lorem. Nam accumsan venenatis tellus id dignissim. + +Curabitur fringilla, magna non maximus dapibus, nulla sapien vestibulum lectus, sit amet semper dolor neque vitae nisl. Nunc ultrices vehicula augue sed iaculis. Maecenas nec diam mollis, suscipit orci et, vestibulum ante. Pellentesque eu nisl tortor. Nunc eleifend, lacus quis volutpat volutpat, nisi mi molestie sem, quis mollis ipsum libero a tellus. Ut viverra dolor mattis convallis interdum. Sed tempus nisl at nunc scelerisque aliquet. Quisque tempor tempor lorem id feugiat. Nullam blandit lectus velit, vitae porta lacus tincidunt a. Vivamus sit amet arcu ultrices, tincidunt mi quis, viverra quam. Aenean fringilla libero elementum lorem semper, quis pulvinar eros gravida. Nullam sodales blandit mauris, sed fermentum velit fermentum sit amet. Donec malesuada mauris in augue sodales vulputate. Vestibulum gravida turpis id elit rhoncus dignissim. Integer non congue lorem, eu viverra orci. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at dolor magna. Aliquam consectetur erat augue, id iaculis velit pharetra ac. Integer rutrum venenatis dignissim. Integer non sodales elit. Curabitur ut magna ut nibh feugiat aliquam ac ut risus. Morbi nibh quam, aliquam id placerat nec, vestibulum eget velit. Suspendisse at dignissim quam. Vivamus aliquet sem sed nisl volutpat, ut cursus orci ultrices. Aliquam ultrices lacinia enim, vitae aliquet neque. + +Quisque scelerisque finibus diam in mattis. Cras cursus auctor velit. Aliquam sem leo, fermentum et maximus et, molestie a libero. Aenean justo elit, rutrum a ornare id, egestas eget enim. Aenean auctor tristique erat. Curabitur condimentum libero lacus, nec consequat orci vestibulum sed. Fusce elit ligula, blandit vitae sapien vitae, dictum ultrices risus. Nam laoreet suscipit sapien, at interdum velit faucibus sit amet. Duis quis metus egestas lectus elementum posuere non nec libero. Aliquam a dolor bibendum, facilisis nunc a, maximus diam. Vestibulum suscipit tristique magna, non dignissim turpis sodales sed. Nunc ornare, velit ac facilisis fringilla, dolor mi consectetur lorem, vitae finibus erat justo suscipit urna. Maecenas sit amet eros erat. Nunc non arcu ornare, suscipit lorem eget, sodales mauris. Aliquam tincidunt, quam nec mollis lacinia, nisi orci fermentum libero, consequat eleifend lectus quam et sapien. Vestibulum a quam urna. + +Cras arcu leo, euismod ac ullamcorper at, faucibus sed massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus porttitor velit in enim interdum, non commodo metus ornare. Morbi vel lorem quis nisl luctus tristique quis vitae nisl. Suspendisse condimentum tortor enim, nec eleifend ipsum euismod et. Sed gravida quam ut tristique lacinia. Mauris eu interdum ipsum, ac ultrices odio. Nullam auctor tellus a risus porttitor vehicula. Nulla blandit euismod dictum. In pharetra, enim iaculis pulvinar interdum, dui nunc placerat nunc, sit amet pretium lectus nulla vitae quam. Phasellus quis enim sollicitudin, varius nulla id, ornare purus. Donec quam lacus, vestibulum quis nunc ac, mollis dictum nisi. Cras ut mollis elit. Maecenas ultrices ligula at risus faucibus scelerisque. Etiam vitae porttitor purus. Curabitur blandit lectus urna, ut hendrerit tortor feugiat ut. + +Phasellus fringilla, sapien pellentesque commodo pharetra, ante libero aliquam tellus, ut consectetur augue libero a sapien. Maecenas blandit luctus nisl eget aliquet. Maecenas vitae porta dolor, faucibus laoreet sapien. Suspendisse lobortis, ipsum sed vehicula aliquam, elit purus scelerisque dui, rutrum consectetur diam odio et lorem. In nec lacinia metus. Donec viverra libero est, vel bibendum erat condimentum quis. Donec feugiat purus leo. In laoreet vitae felis a porttitor. Mauris ullamcorper, lacus id condimentum suscipit, neque magna pellentesque arcu, eget cursus neque tellus id metus. Curabitur volutpat ac orci vel ultricies. + +Sed ut finibus erat. Sed diam purus, varius non tincidunt quis, ultrices sit amet ipsum. Donec et egestas nulla. Suspendisse placerat nisi at dui laoreet iaculis. Aliquam aliquet leo at augue faucibus molestie. Nullam lacus augue, hendrerit sed nisi eu, faucibus porta est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam ut leo aliquet sem fermentum rutrum quis ac justo. Integer placerat aliquam nisl ut sagittis. Proin erat orci, lobortis et sem eget, eleifend fringilla augue. Mauris varius laoreet arcu, sed tincidunt felis. Pellentesque venenatis lorem odio, id pulvinar velit molestie feugiat. Donec mattis lacus sed eleifend pulvinar. + +Sed condimentum ex in tincidunt hendrerit. Etiam eget risus lacinia, euismod nibh eu, pellentesque quam. Proin elit eros, convallis id mauris ac, bibendum ultrices lectus. Morbi venenatis, purus id fermentum consequat, nunc libero tincidunt ligula, non dictum ligula orci nec quam. Nulla nec ultrices lorem. Aenean maximus augue vel dictum pharetra. Etiam turpis urna, pellentesque quis malesuada eu, molestie faucibus felis. + +Vestibulum pharetra augue ut quam blandit congue in nec risus. Proin eu nibh eu dui eleifend porta vitae id lectus. Proin lacus nibh, lobortis sed ligula vitae, interdum lobortis erat. Suspendisse potenti. In sollicitudin quis sapien ut aliquet. Mauris ac nulla arcu. Fusce tristique justo quis lectus mollis, eu volutpat lectus finibus. Vivamus venenatis facilisis ex ut vestibulum. + +Etiam varius lobortis purus, in hendrerit elit tristique at. In tempus, augue vestibulum fermentum gravida, ligula tellus vulputate arcu, eu molestie ex sapien at purus. Vestibulum nec egestas metus. Duis pulvinar quam nec consequat interdum. Aenean non dapibus lacus. Aliquam sit amet aliquet nulla. Sed venenatis volutpat purus nec convallis. Phasellus aliquet semper sodales. Cras risus sapien, condimentum auctor urna a, pulvinar ornare nisl. Sed tincidunt felis elit, ut elementum est bibendum ac. Morbi interdum justo vel dui faucibus condimentum. + +Sed convallis eu sem at tincidunt. Nullam at auctor est, et ullamcorper ipsum. Pellentesque eget ante ante. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer euismod, sapien sed dapibus ornare, nibh enim maximus lacus, lacinia placerat urna quam quis felis. Morbi accumsan id nisl ut condimentum. Donec bibendum nisi est, sed volutpat lorem rhoncus in. Vestibulum ac lacinia nunc, eget volutpat magna. Integer aliquam pharetra ipsum, id placerat nunc volutpat quis. Etiam urna diam, rhoncus sit amet varius vel, euismod vel sem. Nullam vel molestie urna. Vivamus ornare erat at venenatis euismod. Suspendisse potenti. Fusce diam justo, tincidunt vel sem at, commodo faucibus nisl. Duis gravida efficitur diam, vel sagittis erat pulvinar ut. + +Quisque vel pharetra felis. Duis efficitur tortor dolor, vitae porttitor erat fermentum sed. Sed eu mi purus. Etiam dignissim tortor eu tempus molestie. Aenean pretium erat enim, in hendrerit ante hendrerit at. Sed ut risus vel nunc venenatis ultricies quis in lacus. Pellentesque vitae purus euismod, placerat risus non, ullamcorper augue. Quisque varius quam ligula, nec aliquet ex faucibus vitae. Quisque rhoncus sit amet leo tincidunt mattis. Cras id mauris eget purus pretium gravida sit amet eu augue. Aliquam dapibus odio augue, id lacinia velit pulvinar eu. + +Mauris fringilla, tellus nec pharetra iaculis, neque nisi ultrices massa, et tincidunt sem dui sed mi. Curabitur erat lorem, venenatis quis tempus lacinia, tempus sit amet nunc. Aliquam at neque ac metus commodo dictum quis vitae justo. Phasellus eget lacus tempus, blandit lorem vel, rutrum est. Aenean pharetra sem ut augue lobortis dignissim. Sed rhoncus at nulla id ultrices. Cras id condimentum felis. In suscipit luctus vulputate. Donec tincidunt lacus nec enim tincidunt sollicitudin ut quis enim. Nam at libero urna. Praesent sit amet massa vitae massa ullamcorper vehicula. + +Nullam bibendum augue ut turpis condimentum bibendum. Proin sit amet urna hendrerit, sodales tortor a, lobortis lectus. Integer sagittis velit turpis, et tincidunt nisi commodo eget. Duis tincidunt elit finibus accumsan cursus. Aenean dignissim scelerisque felis vel lacinia. Nunc lacinia maximus luctus. In hac habitasse platea dictumst. Vestibulum eget urna et enim tempor tempor. Nam feugiat, felis vel vestibulum tempus, orci justo viverra diam, id dapibus lorem justo in ligula. + +Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In ac pellentesque sem. Vestibulum lacinia magna dui, eu lacinia augue placerat et. Maecenas pulvinar congue est. Pellentesque commodo dui non pulvinar scelerisque. Etiam interdum est posuere sem bibendum, ac commodo magna dictum. Cras ipsum turpis, rhoncus nec posuere vitae, laoreet a arcu. Integer ac massa sit amet enim placerat lacinia sed ultrices arcu. Suspendisse sem nibh, luctus sit amet volutpat in, pellentesque eu metus. Ut gravida neque eget mi accumsan tempus. Nam sit amet aliquet nibh. + +Pellentesque a purus cursus nulla hendrerit congue quis et odio. Aenean hendrerit, leo ullamcorper sagittis hendrerit, erat dui molestie quam, sed condimentum lacus risus sed tellus. Morbi a dapibus lectus, ut feugiat ex. Phasellus pretium quam et sapien mollis, vel iaculis dui dignissim. Sed ullamcorper est turpis, a viverra lorem consectetur in. Aenean aliquet nibh non cursus rutrum. Suspendisse at tristique urna, id lobortis urna. In hac habitasse platea dictumst. Phasellus libero velit, rutrum sed tellus nec, dapibus tincidunt ligula. Quisque vel dui venenatis, consequat nisl ut, lacinia ipsum. Phasellus vitae magna pellentesque, lobortis est id, faucibus quam. Nam eleifend faucibus dui vel pellentesque. + +Etiam ut est non lacus tincidunt interdum. Maecenas sed massa urna. Quisque ut nibh tortor. Pellentesque felis ipsum, tempor finibus ipsum et, euismod pretium metus. Donec sit amet est ipsum. Quisque rhoncus justo non finibus elementum. Nulla nec lectus ac tortor placerat fringilla. Phasellus ac ultrices nunc, eu efficitur nisl. Nulla rhoncus nunc vitae ante dictum tincidunt. Nunc ultrices, massa sit amet malesuada dignissim, lectus lacus consequat sapien, non eleifend metus sem in eros. Phasellus mauris ante, dictum sit amet suscipit ac, rhoncus eget nisi. Phasellus at orci mollis, imperdiet neque eget, faucibus nulla. In at purus massa. Pellentesque quis rutrum lectus. + +Integer eu faucibus turpis, sit amet mollis massa. Vestibulum id nulla commodo, rutrum ipsum sed, semper ante. Phasellus condimentum orci nec nibh convallis, ac maximus orci ullamcorper. Maecenas vitae sollicitudin mi. Integer et finibus lectus, et condimentum ligula. Donec elementum tristique quam vitae dapibus. Morbi euismod ipsum in tristique ullamcorper. + +Duis fermentum non enim eu auctor. Quisque lacinia nibh vehicula nibh posuere, eu volutpat turpis facilisis. Ut ac faucibus nulla. Sed eleifend quis ex et pellentesque. Vestibulum sollicitudin in libero id fringilla. Phasellus dignissim purus consequat, condimentum dui sit amet, condimentum ante. Pellentesque ac consectetur massa, quis sagittis est. Nulla maximus tristique risus accumsan convallis. Curabitur imperdiet ac lacus a ultrices. Nulla facilisi. Sed quis quam quis lectus placerat lobortis vel sed turpis. In mollis dui id neque iaculis, ut aliquet tellus malesuada. Proin at luctus odio, vel blandit sapien. Praesent dignissim tortor vehicula libero fringilla, nec ultrices erat suscipit. Maecenas scelerisque purus in dapibus fermentum. + +Curabitur magna odio, mattis in tortor ut, porttitor congue est. Vestibulum mollis lacinia elementum. Fusce maximus erat vitae nunc rutrum lobortis. Integer ligula eros, auctor vel elit non, posuere luctus lacus. Maecenas quis auctor massa. Ut ipsum lacus, efficitur posuere euismod et, hendrerit efficitur est. Phasellus fringilla, quam id tincidunt pretium, nunc dui sollicitudin orci, eu dignissim nisi metus ut magna. Integer lobortis interdum dolor, non bibendum purus posuere et. Donec non lectus aliquet, pretium dolor eu, cursus massa. Sed ut dui sapien. In sed vestibulum massa. Pellentesque blandit, dui non sodales vehicula, orci metus mollis nunc, non pharetra ex tellus ac est. Mauris sagittis metus et fermentum pretium. Nulla facilisi. Quisque quis ante ut nulla placerat mattis ut quis nisi. + +Sed quis nulla ligula. Quisque dignissim ligula urna, sed aliquam purus semper at. Suspendisse potenti. Nunc massa lectus, pharetra vehicula arcu bibendum, imperdiet sodales ipsum. Nam ac sapien diam. Mauris iaculis fringilla mattis. Pellentesque tempus eros sit amet justo volutpat mollis. Phasellus ac turpis ipsum. Morbi vel ante elit. Aenean posuere quam consequat velit varius suscipit. Donec tempor quam ut nibh cursus efficitur. + +Morbi molestie dolor nec sem egestas suscipit. Etiam placerat pharetra lectus, et ullamcorper risus tristique in. Sed faucibus ullamcorper lectus eget fringilla. Maecenas malesuada hendrerit congue. Sed eget neque a erat placerat tincidunt. Aliquam vitae dignissim turpis. Fusce at placerat magna, a laoreet lectus. Maecenas a purus nec diam gravida fringilla. Nam malesuada euismod ante non vehicula. In faucibus bibendum leo, faucibus posuere nisl pretium quis. Fusce finibus bibendum finibus. Vestibulum eu justo maximus, hendrerit diam nec, dignissim sapien. Aenean dolor lacus, malesuada quis vestibulum ac, venenatis ac ipsum. Cras a est id nunc finibus facilisis. Cras lacinia neque et interdum vehicula. Suspendisse vulputate tellus elit, eget tempor dui finibus vel. + +Cras sed pretium odio. Proin hendrerit elementum felis in tincidunt. Nam sed turpis vel justo molestie accumsan condimentum eu nunc. Praesent lobortis euismod rhoncus. Nulla vitae euismod nibh, quis mattis mi. Fusce ultrices placerat porttitor. Duis sem ipsum, pellentesque sit amet odio a, molestie vulputate mauris. + +Duis blandit mollis ligula, sit amet mattis ligula finibus sit amet. Nunc a leo molestie, placerat diam et, vestibulum leo. Suspendisse facilisis neque purus, nec pellentesque ligula fermentum nec. Aenean malesuada mauris lorem, eu blandit arcu pulvinar quis. Duis laoreet urna lacus, non maximus arcu rutrum ultricies. Nulla augue dolor, suscipit eu mollis eu, aliquam condimentum diam. Ut semper orci luctus, pharetra turpis at, euismod mi. Nulla leo diam, finibus sit amet purus sed, maximus dictum lorem. Integer eu mi id turpis laoreet rhoncus. + +Integer a mauris tincidunt, finibus orci ut, pretium mauris. Nulla molestie nunc mi, id finibus lorem elementum sed. Proin quis laoreet ante. Integer nulla augue, commodo id molestie quis, rutrum ut turpis. Suspendisse et tortor turpis. Sed ut pharetra massa. Pellentesque elementum blandit sem, ut elementum tellus egestas a. Fusce eu purus nibh. + +Cras dignissim ligula scelerisque magna faucibus ullamcorper. Proin at condimentum risus, auctor malesuada quam. Nullam interdum interdum egestas. Nulla aliquam nisi vitae felis mollis dictum. Suspendisse dapibus consectetur tortor. Ut ut nisi non sem bibendum tincidunt. Vivamus suscipit leo quis gravida dignissim. + +Aliquam interdum, leo id vehicula mollis, eros eros rhoncus diam, non mollis ligula mi eu mauris. Sed ultrices vel velit sollicitudin tincidunt. Nunc auctor metus at ligula gravida elementum. Praesent interdum eu elit et mollis. Duis egestas quam sit amet velit dignissim consequat. Aliquam ac turpis nec nunc convallis sagittis. Fusce blandit, erat ac fringilla consectetur, dolor eros sodales leo, vel aliquet risus nisl et diam. Aliquam luctus felis vitae est eleifend euismod facilisis et lacus. Sed leo tellus, auctor eu arcu in, volutpat sagittis nisl. Pellentesque nisl ligula, placerat vel ullamcorper at, vulputate ac odio. Morbi ac faucibus orci, et tempus nulla. Proin rhoncus rutrum dolor, in venenatis mauris. Suspendisse a fermentum augue, non semper mi. Nunc eget pretium neque. Phasellus augue erat, feugiat ac aliquam congue, rutrum non sapien. Pellentesque ac diam gravida, consectetur felis at, ornare neque. + +Nullam interdum mattis sapien quis porttitor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus aliquet rutrum ipsum id euismod. Maecenas consectetur massa et mi porta viverra. Nunc quam nibh, dignissim vitae maximus et, ullamcorper nec lorem. Nunc vitae justo dapibus, luctus lacus vitae, pretium elit. Maecenas et efficitur leo. Curabitur mauris lectus, placerat quis vehicula vitae, auctor ut urna. Quisque rhoncus pharetra luctus. In hac habitasse platea dictumst. Integer sit amet metus nec eros malesuada aliquam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi hendrerit mi ac leo aliquam, sit amet ultricies libero commodo. Mauris dapibus purus metus, sit amet viverra nibh imperdiet et. Nullam porta nulla tellus, quis vehicula diam imperdiet non. Vivamus enim massa, bibendum in fermentum in, ultrices at ex. + +Suspendisse fermentum id nibh eget accumsan. Duis dapibus bibendum erat ut sollicitudin. Aliquam nec felis risus. Pellentesque rhoncus ligula id sem maximus mollis sed nec massa. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ipsum ipsum, sodales sed enim id, convallis faucibus eros. Donec ultricies dictum tincidunt. Cras vitae nibh arcu. Pellentesque cursus, sapien nec consequat fermentum, ipsum ante suscipit dui, imperdiet hendrerit est nisl eu massa. Quisque vitae sem ligula. Aenean iaculis metus ut mauris interdum laoreet. Vivamus sed gravida dolor. + +Morbi nulla metus, porttitor sed eros sit amet, efficitur efficitur est. In vel nisl urna. Ut aliquet tellus at congue convallis. Phasellus imperdiet lobortis sollicitudin. Integer sodales, sem eu ultricies pharetra, erat erat porttitor odio, eget dapibus libero ipsum eget velit. Phasellus gravida nulla nisl, eu pharetra mi auctor vel. Sed blandit pharetra velit, ut egestas libero placerat non. Aliquam a interdum quam. Proin at tortor nec dui sollicitudin tempus sed vestibulum elit. Nunc non sollicitudin velit. + +Aenean consequat diam velit, sed rutrum tortor faucibus dictum. Quisque at semper augue. Duis ut est eget mi ornare bibendum id et ligula. Phasellus consequat tortor non leo pulvinar posuere. Proin vestibulum eleifend felis, in hendrerit tortor sollicitudin eu. Phasellus hendrerit, lacus vel laoreet interdum, dui tortor consequat justo, commodo ultricies arcu felis vitae enim. Vivamus eu sapien at leo suscipit rutrum eu at justo. Aenean et dolor a libero ullamcorper posuere. Integer laoreet placerat nisi in vulputate. Mauris laoreet eget risus sed cursus. Donec scelerisque neque a libero eleifend hendrerit. Nulla varius condimentum nunc sit amet fermentum. Aliquam lorem ex, varius nec mollis ut, ultrices in neque. Morbi sit amet porta leo. Integer iaculis fermentum lacus in vestibulum. + +Ut gravida, tellus ut maximus ultrices, erat est venenatis nisl, vitae pretium massa ex ac magna. Sed non purus eget ligula aliquet volutpat non quis arcu. Nam aliquam tincidunt risus, sit amet fringilla sapien vulputate ut. Mauris luctus suscipit pellentesque. Nunc porttitor dapibus ex quis tempus. Ut ullamcorper metus a eros vulputate, vitae viverra lectus convallis. Mauris semper imperdiet augue quis tincidunt. Integer porta pretium magna, sed cursus sem scelerisque sollicitudin. Nam efficitur, nibh pretium eleifend vestibulum, purus diam posuere sem, in egestas mauris augue sit amet urna. + +Vestibulum tincidunt euismod massa in congue. Duis interdum metus non laoreet fringilla. Donec at ligula congue, tincidunt nunc non, scelerisque nunc. Donec bibendum magna non est scelerisque feugiat at nec neque. Ut orci tortor, tempus eget massa non, dignissim faucibus dolor. Nam odio risus, accumsan pretium neque eget, accumsan dignissim dui. In ut neque auctor, scelerisque tellus sed, ullamcorper nisi. Suspendisse varius cursus quam at hendrerit. Vivamus elit libero, sagittis vitae sem ac, vulputate iaculis ligula. + +Sed lobortis laoreet purus sit amet rutrum. Pellentesque feugiat non leo vel lacinia. Quisque feugiat nisl a orci bibendum vestibulum. In et sollicitudin urna. Morbi a arcu ac metus faucibus tempus. Nam eu imperdiet sapien, suscipit mattis tortor. Aenean blandit ipsum nisi, a eleifend ligula euismod at. Integer tincidunt pharetra felis, mollis placerat mauris hendrerit at. Curabitur convallis, est sit amet luctus volutpat, massa lacus cursus augue, sed eleifend magna quam et risus. Aliquam lobortis tincidunt metus vitae porttitor. Suspendisse potenti. Aenean ullamcorper, neque id commodo luctus, nulla nunc lobortis quam, id dapibus neque dui nec mauris. Etiam quis lorem quis elit commodo ornare. Ut pharetra purus ultricies enim ultrices efficitur. Proin vehicula tincidunt molestie. Mauris et placerat sem. + +Aliquam erat volutpat. Suspendisse velit turpis, posuere ac lacus eu, lacinia laoreet velit. Sed interdum felis neque, id blandit sem malesuada sit amet. Ut sagittis justo erat, efficitur semper orci tempor sed. Donec enim massa, posuere varius lectus egestas, pellentesque posuere mi. Cras tincidunt ut libero sed mattis. Suspendisse quis magna et tellus posuere interdum vel at purus. Pellentesque fringilla tristique neque, id aliquet tellus ultricies non. Duis ut tellus vel odio lobortis vulputate. + +Integer at magna ac erat convallis vestibulum. Sed lobortis porttitor mauris. Fusce varius lorem et volutpat pulvinar. Aenean ac vulputate lectus, vitae consequat velit. Suspendisse ex dui, varius ut risus ut, dictum scelerisque sem. Vivamus urna orci, volutpat ut convallis ac, venenatis vitae urna. In hac habitasse platea dictumst. Etiam eu purus arcu. Aenean vulputate leo urna, vel tristique dui sagittis euismod. Suspendisse non tellus efficitur ante rhoncus volutpat at et sapien. + +Sed dapibus accumsan porttitor. Phasellus facilisis lectus finibus ligula dignissim, id pulvinar lectus feugiat. Nullam egestas commodo nisi posuere aliquet. Morbi sit amet tortor sagittis, rutrum dui nec, dapibus sapien. Sed posuere tortor tortor, interdum auctor magna varius vitae. Vestibulum id sagittis augue. Curabitur fermentum arcu sem, eu condimentum quam rutrum non. Phasellus rutrum nibh quis lectus rhoncus pretium. Curabitur dictum interdum elit. Vestibulum maximus sodales imperdiet. Mauris auctor nec purus sed venenatis. In in urna purus. + +Duis placerat molestie suscipit. Morbi a elit id purus efficitur consequat. Nunc ac commodo turpis. Etiam sit amet lacus a ipsum tempus venenatis sed vel nibh. Duis elementum aliquam mi sed tristique. Morbi ligula tortor, semper ac est vel, lobortis maximus erat. Curabitur ipsum felis, laoreet vel condimentum eget, ullamcorper sit amet mauris. Nulla facilisi. Nam at purus sed mi egestas placerat vitae vel magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse at dignissim diam. Phasellus consectetur eget neque vel viverra. Donec sollicitudin mattis dolor vel malesuada. Vivamus vehicula leo neque, vitae fermentum leo posuere et. Praesent dui est, finibus sit amet tristique quis, pharetra vel nibh. + +Duis nulla leo, accumsan eu odio eget, sagittis semper orci. Quisque ullamcorper ligula quam, commodo porttitor mauris ullamcorper eu. Cras varius sagittis felis in aliquam. Duis sodales risus ac justo vehicula, nec mattis diam lacinia. Cras eget lectus ipsum. Ut commodo, enim vitae malesuada hendrerit, ex dolor egestas lectus, sit amet hendrerit metus diam nec est. Vestibulum tortor metus, lobortis sit amet ante eget, tempor molestie lacus. In molestie et urna et semper. Mauris mollis, sem non hendrerit condimentum, sapien nisi cursus est, non suscipit quam justo non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam enim est, porta ac feugiat vitae, rutrum in lorem. Duis vehicula tortor ut posuere maximus. + +Nullam vestibulum non tellus sed commodo. Quisque mattis elit sit amet sapien sollicitudin, ut condimentum nisl congue. Aenean sagittis massa vel elit faucibus fermentum. Donec tincidunt nisi nec nisl sodales pellentesque. Mauris congue congue ligula ut suscipit. Vivamus velit tortor, tempor et gravida eget, fermentum sit amet ante. Nullam fringilla, lorem at ultrices cursus, urna neque ornare dolor, eu lacinia orci enim sed nibh. Ut a ullamcorper lectus, id mattis purus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean maximus sollicitudin posuere. Nunc at augue lacus. Aenean efficitur leo sit amet lacinia efficitur. + +Quisque venenatis quam mi, in pharetra odio vulputate eu. In vel nisl pulvinar, pulvinar ligula ut, sodales risus. Sed efficitur lectus at vestibulum tincidunt. Vestibulum eu ullamcorper elit. Fusce vestibulum magna enim, et tempor lacus posuere vitae. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer leo elit, luctus nec mattis sit amet, sollicitudin in turpis. + +Proin convallis venenatis leo, vitae tristique erat iaculis nec. Nulla facilisi. Duis porttitor, sapien et bibendum vulputate, sem libero sodales lacus, non malesuada felis erat ut libero. Nam non felis semper, finibus est a, mattis mauris. Praesent nec eros quam. Nulla hendrerit, augue consectetur eleifend ultricies, purus mi condimentum nulla, eget dapibus est nunc sed libero. Nullam elementum dui erat, vitae luctus libero sollicitudin et. Nulla odio magna, placerat in augue eu, dapibus imperdiet odio. Suspendisse imperdiet metus sit amet rhoncus dapibus. Cras at enim et urna vehicula cursus eu a mauris. Integer magna ante, eleifend ac placerat vitae, porta at nisi. Cras eget malesuada orci. Curabitur nunc est, vulputate id viverra et, dignissim sed odio. Curabitur non mattis sem. Sed bibendum, turpis vitae vehicula faucibus, nunc quam ultricies lectus, vitae viverra felis turpis at libero. + +Nullam ut egestas ligula. Proin hendrerit justo a lectus commodo venenatis. Nulla facilisi. Ut cursus lorem quis est bibendum condimentum. Aenean in tristique odio. Fusce tempor hendrerit ipsum. Curabitur mollis felis justo, quis dapibus erat auctor vel. Sed augue lectus, finibus ut urna quis, ullamcorper vestibulum dui. Etiam molestie aliquam tempor. Integer mattis sollicitudin erat, et tristique elit varius vel. Mauris a ex justo. + +Nam eros est, imperdiet non volutpat rutrum, pellentesque accumsan ligula. Duis sit amet turpis metus. Aenean in rhoncus metus, ac fringilla ex. Suspendisse condimentum egestas purus, ut pharetra odio vulputate vel. Duis tincidunt massa a placerat ultrices. Mauris ultricies nibh sit amet condimentum malesuada. Duis tincidunt id ipsum sed congue. + +Praesent eu ex augue. Nullam in porta ligula. In tincidunt accumsan arcu, in pellentesque magna tristique in. Mauris eleifend libero ac nisl viverra faucibus. Nam sollicitudin dolor in commodo hendrerit. Cras at orci metus. Ut quis laoreet orci. Vivamus ultrices leo pellentesque tempor aliquet. Maecenas ut eros vitae purus placerat vestibulum. Etiam vitae gravida dolor, quis rhoncus diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. + +Suspendisse fringilla lacinia sagittis. Integer tincidunt consectetur tristique. Morbi non orci convallis, congue sapien quis, vulputate nunc. Donec a libero vel magna elementum facilisis non quis mi. Mauris posuere tellus non ipsum ultrices elementum. Vivamus massa velit, facilisis quis placerat aliquet, aliquet nec leo. Praesent a maximus sem. Sed neque elit, feugiat vel quam non, molestie sagittis nunc. Etiam luctus nunc ac mauris scelerisque, nec rhoncus lacus convallis. Nunc pharetra, nunc ac pulvinar aliquam, ex ipsum euismod augue, nec porttitor lacus turpis vitae neque. Fusce bibendum odio id tortor faucibus pellentesque. Sed ac porta nibh, eu gravida erat. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam quis ullamcorper felis. Nulla mattis sagittis ante ac tincidunt. Integer ac felis efficitur, viverra libero et, facilisis ligula. Suspendisse a metus a massa rhoncus posuere. Phasellus suscipit ligula ut lacus facilisis, ac pellentesque ex tempor. Quisque consectetur massa mi, ac molestie libero dictum quis. Proin porttitor ligula quis erat tincidunt venenatis. Proin congue nunc sed elit gravida, nec consectetur lectus sodales. Etiam tincidunt convallis ipsum at vestibulum. Quisque maximus enim et mauris porttitor, et molestie magna tristique. Morbi vitae metus elit. Maecenas sed volutpat turpis. Aliquam vitae dolor vestibulum, elementum purus eget, dapibus nibh. Nullam egestas dui ac rutrum semper. + +Etiam hendrerit est metus, et condimentum metus aliquam ac. Pellentesque id neque id ipsum rhoncus vulputate. Aliquam erat nisl, posuere sit amet ligula ac, fermentum blandit felis. Vivamus fermentum mi risus, non lacinia purus viverra id. Aenean ac sapien consequat, finibus mauris nec, porta sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed quis consectetur ex, dignissim bibendum nulla. Phasellus ac libero at quam vehicula euismod non eu leo. Phasellus a sapien augue. + +Maecenas ligula dui, bibendum vitae mauris et, auctor laoreet felis. Duis non libero a mi semper mattis. Quisque consequat luctus massa, quis tristique eros auctor feugiat. Maecenas sodales euismod neque vitae facilisis. Nullam laoreet imperdiet velit at pellentesque. Etiam massa odio, facilisis a consequat vitae, placerat vel magna. Nunc sagittis eros nec urna fringilla, pulvinar vestibulum nibh scelerisque. Sed magna metus, cursus eu consequat et, pharetra a est. Suspendisse elementum neque a dui malesuada lacinia. Donec sed ipsum volutpat, cursus urna id, ullamcorper arcu. Maecenas laoreet nisl eget velit egestas sollicitudin. Etiam nisl turpis, mollis id dignissim vitae, tristique vehicula ante. Maecenas eget placerat est, at rutrum augue. Vivamus faucibus lacinia ullamcorper. Sed pulvinar urna sodales ante sodales, at gravida leo dictum. + +Morbi maximus, quam a lobortis bibendum, enim felis varius elit, ac vehicula elit nisl ut lacus. Quisque ut arcu augue. Praesent id turpis quam. Sed sed arcu eros. Maecenas at cursus lorem, ac eleifend nisi. Fusce mattis felis at commodo pharetra. Praesent ac commodo ipsum. Quisque finibus et eros vitae tincidunt. In hac habitasse platea dictumst. Praesent purus ipsum, luctus lobortis ornare quis, auctor eget justo. Nam vel enim sollicitudin, faucibus tortor eu, sagittis eros. Ut nec consectetur erat. Donec ultricies malesuada ligula, a hendrerit sapien volutpat in. Maecenas sed enim vitae sapien pulvinar faucibus. + +Proin semper nunc nibh, non consequat neque ullamcorper vel. Maecenas lobortis sagittis blandit. Aenean et arcu ultricies turpis malesuada malesuada. Ut quam ex, laoreet ut blandit cursus, feugiat vitae dolor. Etiam ex lacus, scelerisque vel erat vel, efficitur tincidunt magna. Morbi tristique lacinia dolor, in egestas magna ultrices vitae. Integer ultrices leo ac tempus venenatis. Praesent ac porta tortor. Vivamus ornare blandit tristique. Nulla rutrum finibus pellentesque. In non dui elementum, fermentum ipsum vel, varius magna. Pellentesque euismod tortor risus, ac pellentesque nisl faucibus eget. + +Vivamus eu enim purus. Cras ultrices rutrum egestas. Sed mollis erat nibh, at posuere nisl luctus nec. Nunc vulputate, sapien id auctor molestie, nisi diam tristique ante, non convallis tellus nibh at orci. Morbi a posuere purus, in ullamcorper ligula. Etiam elementum sit amet dui imperdiet iaculis. Proin vitae tincidunt ipsum, sit amet placerat lectus. Curabitur commodo sapien quam, et accumsan lectus fringilla non. Nullam eget accumsan enim, ac pharetra mauris. Sed quis tristique velit, vitae commodo nisi. Duis turpis dui, maximus ut risus at, finibus consequat nunc. Maecenas sed est accumsan, aliquet diam in, facilisis risus. Curabitur vehicula rutrum auctor. Nam iaculis risus pulvinar maximus viverra. Nulla vel augue et ex sagittis blandit. + +Ut sem nulla, porta ac ante ac, posuere laoreet eros. Donec sodales posuere justo a auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras mollis at orci hendrerit porta. Nullam sodales tortor tortor, non lacinia diam finibus id. Duis libero orci, suscipit ac odio et, dictum consequat ipsum. Pellentesque eu ligula sagittis, volutpat eros at, lacinia lorem. Cras euismod tellus in iaculis tempor. Quisque accumsan, magna a congue venenatis, ante ipsum aliquam lectus, at egestas enim nunc at justo. Quisque sem purus, viverra ut tristique ut, maximus id enim. Etiam quis placerat sem. In sollicitudin, lacus eu rutrum mollis, nulla eros luctus elit, vel dapibus urna purus nec urna. Phasellus egestas massa quam, ac molestie erat hendrerit a. Praesent ultrices neque ut turpis molestie auctor. Etiam molestie placerat purus, et euismod erat aliquam in. Morbi id suscipit justo. + +Proin est ante, consequat at varius a, mattis quis felis. Sed accumsan nibh sit amet ipsum elementum posuere. Vestibulum bibendum id diam sit amet gravida. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi nec dolor vel ipsum dignissim hendrerit vel non ipsum. Praesent facilisis orci quis elit auctor lobortis. Phasellus cursus risus lectus, vel lobortis libero dapibus in. Quisque tristique tempus leo a pulvinar. Pellentesque a magna tincidunt, pellentesque massa nec, laoreet orci. Morbi congue ornare dolor quis commodo. Phasellus massa nisi, tincidunt at eros dictum, hendrerit lobortis urna. Maecenas porta, magna id mattis molestie, nibh tellus lobortis sem, eget tincidunt ipsum quam eu turpis. + +Ut gravida orci risus, vel rutrum mauris vehicula id. Etiam bibendum, neque a placerat condimentum, ex orci imperdiet lectus, quis dapibus arcu lacus eget lectus. Sed consequat non mi sit amet venenatis. Fusce vestibulum erat libero, eget hendrerit risus vulputate sollicitudin. Integer sed eleifend felis. Donec commodo, sem eu mattis placerat, urna odio aliquam tellus, et laoreet justo tellus eget erat. Fusce sed suscipit tortor. Nam hendrerit nibh ac nunc auctor lacinia. Pellentesque placerat condimentum ipsum, eget semper tortor hendrerit vel. Nullam non urna eu lacus pellentesque congue ut id eros. + +Nunc finibus leo in rhoncus tristique. Sed eu ipsum nec nisl egestas faucibus eget a felis. Pellentesque vitae nisi in nulla accumsan fermentum. Sed venenatis feugiat eleifend. Fusce porttitor varius placerat. Aliquam aliquet lacus sit amet mattis mollis. Sed vel nulla quis dolor suscipit vehicula ac viverra lorem. Duis viverra ipsum eget nulla ullamcorper fermentum. Mauris tincidunt arcu quis quam fringilla ornare. Donec et iaculis tortor. Nam ultricies libero vel ipsum aliquet efficitur. Morbi eget dolor aliquam, tempus sapien eget, viverra ante. Donec varius mollis ex, sed efficitur purus euismod interdum. Quisque vel sapien non neque tincidunt semper. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Suspendisse sit amet purus leo. Fusce lectus lorem, aliquam ac nulla eget, imperdiet ornare eros. Nullam sem augue, varius in nisi non, sollicitudin pellentesque ante. Etiam eu odio condimentum, tempor libero et, egestas arcu. Cras pellentesque eleifend aliquet. Pellentesque non blandit ligula. Ut congue viverra rhoncus. Phasellus mattis mi ac eros placerat, eu feugiat tellus ultrices. Aenean mollis laoreet libero eu imperdiet. Cras sed pulvinar mi, ac vehicula ligula. Vestibulum sit amet ex massa. In a egestas eros. + +Mauris pretium ipsum risus, venenatis cursus ante imperdiet id. Praesent eu turpis nec risus feugiat maximus ullamcorper ac lectus. Integer placerat at mi vel dapibus. Vestibulum fermentum turpis sit amet turpis viverra, id aliquet diam suscipit. Nam nec ex sed ante ullamcorper pharetra quis sit amet risus. Sed ac faucibus velit, id feugiat nibh. Nullam eget ipsum ex. Vivamus tincidunt non nunc non faucibus. Quisque bibendum viverra facilisis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at nisi hendrerit quam suscipit egestas. Curabitur laoreet maximus ultricies. Duis ut tellus ac augue molestie dictum. + +Suspendisse rhoncus iaculis erat, ut ullamcorper est tristique eget. Donec auctor nec risus at gravida. Vivamus volutpat vulputate tellus, vel ultricies eros suscipit eget. Ut pulvinar id mi eu tempus. Morbi malesuada augue in dui varius, nec blandit neque vehicula. Donec ornare nec nisl in mollis. Morbi enim nisi, rhoncus nec est id, dapibus tempus urna. Ut id elit a felis vestibulum consectetur. Duis lectus quam, pharetra sit amet diam sed, posuere vestibulum erat. Fusce vitae maximus massa. Nullam id metus tempus, iaculis risus eu, lobortis urna. Quisque in congue urna. Pellentesque placerat neque in augue dapibus, non varius ex malesuada. Curabitur ut eleifend libero. Fusce vitae ligula luctus, fermentum enim vitae, ultrices erat. + +Sed viverra augue turpis, scelerisque egestas sapien mattis eu. Duis laoreet magna at ex pharetra dapibus. Praesent eget odio vel quam venenatis dictum. Nulla in sollicitudin dolor. Mauris lobortis nec eros vel rhoncus. Vestibulum porta viverra venenatis. Curabitur vel scelerisque quam, a egestas velit. Praesent volutpat tincidunt magna at laoreet. + +Cras nec lorem odio. Pellentesque quis dui urna. Praesent at tellus ac lectus scelerisque placerat nec eu risus. Vestibulum sit amet mattis ligula. Vivamus sed nisi at leo elementum accumsan at sit amet arcu. Aenean mattis tellus nec leo gravida, eget hendrerit nisl faucibus. Mauris pellentesque luctus condimentum. Maecenas pretium sapien nunc, eget commodo dolor maximus id. Mauris vestibulum accumsan massa a dictum. Phasellus interdum quam ligula, ut maximus diam blandit aliquam. Nunc vitae ex eu erat condimentum consectetur. Maecenas interdum condimentum volutpat. + +Donec et enim a libero rutrum laoreet. Praesent a condimentum sem, at tincidunt quam. In vel molestie risus. Sed urna dui, molestie vitae mollis laoreet, tempor quis lectus. Praesent vitae auctor est, et aliquet nunc. Curabitur vulputate blandit nulla, at gravida metus. Maecenas gravida dui eu iaculis tristique. Pellentesque posuere turpis nec auctor eleifend. Suspendisse bibendum diam eu tellus lobortis, et laoreet quam congue. In hac habitasse platea dictumst. Morbi dictum neque velit, eget rutrum eros ultrices sit amet. + +Phasellus fermentum risus pharetra consectetur bibendum. Donec magna tortor, lacinia vitae nibh quis, aliquet pretium lorem. Donec turpis nisi, pretium eu enim volutpat, mattis malesuada augue. Nullam vel tellus iaculis, sollicitudin elit eget, tincidunt lacus. Fusce elementum elementum felis et iaculis. Suspendisse porta eros nec neque malesuada, in malesuada ante sollicitudin. Vivamus bibendum viverra molestie. + +Integer feugiat, erat nec convallis aliquam, velit felis congue erat, molestie eleifend tellus erat in tellus. Nunc et justo purus. Donec egestas fermentum dui non feugiat. Quisque in sapien sagittis, gravida quam id, iaculis lectus. Cras sagittis rhoncus bibendum. Fusce quis metus in velit scelerisque tincidunt at non ipsum. Vivamus efficitur ante eu odio vulputate, vitae ultricies risus vehicula. Proin eget odio eu sem tincidunt feugiat vel id lorem. + +Vestibulum sit amet nulla dignissim, euismod mi in, fermentum tortor. Donec ut aliquet libero, lacinia accumsan velit. Donec et nulla quam. Nullam laoreet odio nec nunc imperdiet, a congue eros venenatis. Quisque nec tellus sit amet neque interdum posuere. Duis quis mi gravida, tincidunt diam convallis, ultricies augue. Mauris consequat risus non porttitor congue. Ut in ligula consequat, viverra nunc a, eleifend enim. Duis ligula urna, imperdiet nec facilisis et, ornare eu ex. Proin lobortis lectus a lobortis porttitor. Nulla leo metus, egestas eu libero sed, pretium faucibus felis. Vestibulum non sem tortor. Nam cursus est leo. Vivamus luctus enim odio, non interdum sem dapibus a. Aenean accumsan consequat lectus in imperdiet. + +Donec vehicula laoreet ipsum in posuere. Quisque vel quam imperdiet, sollicitudin nisi quis, suscipit velit. Morbi id sodales mauris. Curabitur tellus arcu, feugiat sed dui sit amet, sodales sagittis libero. Aenean vel suscipit metus, non placerat leo. Vestibulum quis nulla elit. Proin scelerisque non ante ut commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. + +Sed non urna dolor. Suspendisse convallis mi porta pulvinar ultrices. Suspendisse quam ipsum, hendrerit non scelerisque molestie, interdum dictum nunc. Morbi condimentum condimentum turpis eu luctus. Pellentesque sagittis sollicitudin odio, sed ultricies felis ornare sit amet. Sed ultrices ex leo, a tincidunt nisl gravida sed. Nullam ornare accumsan porta. Praesent consectetur id est nec sollicitudin. + +In hac habitasse platea dictumst. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed sed ultrices nibh. Duis accumsan suscipit eros, a dictum odio tempus sit amet. Aenean imperdiet erat ac lacus finibus, scelerisque cursus massa imperdiet. Mauris molestie risus ut lacinia posuere. Nulla et sodales purus. Maecenas orci erat, placerat in tristique quis, placerat in mi. + +Donec sollicitudin pellentesque odio in feugiat. Morbi eu dolor ut mauris congue sollicitudin. Aliquam erat volutpat. Nulla id varius dui. Curabitur finibus urna ante, consectetur interdum nisi volutpat a. Quisque quis mi tristique, consequat tellus eget, rutrum sapien. Vivamus vitae tellus vulputate, rutrum ex eu, vulputate sem. Suspendisse viverra lorem tellus, vel interdum orci gravida quis. Ut laoreet arcu at mi ullamcorper finibus. Duis porta sagittis vestibulum. Sed commodo nisl vitae urna sollicitudin, nec lacinia est sodales. Curabitur imperdiet sodales dui sed iaculis. Sed ac tellus maximus, eleifend quam sit amet, feugiat elit. Aenean viverra, dui at mattis varius, est odio vestibulum sapien, sit amet mollis libero massa nec velit. Etiam quis sodales justo. + +Ut ultricies, sem eget sodales feugiat, nunc arcu congue elit, ac tempor justo massa nec purus. Maecenas enim nunc, pharetra eget dictum sit amet, tempus pellentesque velit. Suspendisse venenatis ligula in nulla mattis, et imperdiet ex tincidunt. Etiam vulputate, tellus et ultrices suscipit, enim velit laoreet massa, vitae congue odio enim ac urna. Morbi quam lorem, iaculis ac varius sagittis, euismod quis dolor. In ut dui eu purus feugiat consectetur. Vestibulum cursus velit quis lacus pellentesque iaculis. Cras in risus sed mauris porta rutrum. Nulla facilisi. Nullam eu bibendum est, non pellentesque lectus. Sed imperdiet feugiat lorem, quis convallis ante auctor in. Maecenas justo magna, scelerisque sit amet tellus eget, varius elementum risus. Duis placerat et quam sed varius. + +Duis nec nibh vitae nibh dignissim mollis quis sed felis. Curabitur vitae quam placerat, venenatis purus ut, euismod nisl. Curabitur porttitor nibh eu pulvinar ullamcorper. Suspendisse posuere nec ipsum ac dapibus. Cras convallis consectetur urna. Phasellus a nibh in dolor lacinia posuere id eget augue. In eu pharetra lorem, vitae cursus lacus. Aliquam tincidunt nibh lectus. Aenean facilisis ultricies posuere. Sed ut placerat orci. Curabitur scelerisque gravida blandit. Maecenas placerat ligula eget suscipit fringilla. Mauris a tortor justo. Aliquam hendrerit semper mollis. Phasellus et tincidunt libero. Etiam vel quam libero. + +Quisque aliquet tempor ex. Ut ante sem, vehicula at enim vel, gravida porta elit. Etiam vitae lacus a neque lobortis consectetur. Mauris sed interdum odio. Mauris elementum ex blandit tempor cursus. Integer in enim in leo viverra elementum. Fusce consectetur metus et sem rutrum, mattis euismod diam semper. Nunc sed ipsum vel urna consequat vehicula. Donec cursus pretium lorem, vestibulum pretium felis commodo sit amet. Nam blandit felis enim, eget gravida ex faucibus a. In nec neque massa. Etiam laoreet posuere ipsum. Praesent volutpat nunc dolor, ac vulputate magna facilisis non. Aenean congue turpis vel lectus sollicitudin tristique. Sed nec consequat purus, non vehicula quam. Etiam ultricies, est ac dictum tincidunt, turpis turpis pretium massa, a vulputate libero justo at nibh. + +Aliquam erat volutpat. Cras ultrices augue ac sollicitudin lobortis. Curabitur et aliquet purus. Duis feugiat semper facilisis. Phasellus lobortis cursus velit, a sollicitudin tortor. Nam feugiat sapien non dapibus condimentum. Morbi at mi bibendum, commodo quam at, laoreet enim. Integer eu ultrices enim. Sed vestibulum eu urna ut dictum. Curabitur at mattis leo, sed cursus massa. Aliquam porttitor, felis quis fermentum porttitor, justo velit feugiat nulla, eget condimentum sem dui ut sapien. + +In fringilla elit eu orci aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut eget fringilla tellus. Curabitur fermentum, mi et condimentum suscipit, elit neque bibendum dui, et hendrerit nunc metus id ipsum. Morbi placerat mi in hendrerit congue. Ut feugiat mauris eget scelerisque viverra. Vivamus sit amet erat dictum, sagittis lectus nec, pulvinar lorem. Sed non enim ac dui sollicitudin aliquet. Quisque ut lacus dolor. Fusce hendrerit malesuada euismod. Nulla faucibus vel mauris eu mollis. Mauris est diam, fringilla ac arcu feugiat, efficitur volutpat turpis. Aliquam venenatis cursus massa sed porttitor. Ut ac finibus enim, in tincidunt sapien. + +Nunc faucibus semper turpis a lacinia. Phasellus gravida, libero vel pulvinar ornare, ex sem tincidunt lectus, sit amet convallis augue risus at tortor. Quisque sit amet ipsum id nulla posuere vestibulum. Pellentesque scelerisque mauris vel leo viverra sodales. Nulla viverra aliquam ex, ut rutrum enim fermentum venenatis. Aenean eget dapibus ex, eget faucibus metus. Vestibulum volutpat leo in diam semper, eget porta magna suscipit. Sed sit amet nulla blandit, aliquam dolor ac, gravida velit. Sed vel velit viverra, maximus est id, convallis justo. + +Curabitur nulla ante, vulputate at libero vel, ullamcorper rutrum nibh. Pellentesque porttitor eu mauris id mattis. Duis vulputate augue elit, eget interdum justo pretium vel. Maecenas eu vulputate arcu, eget posuere purus. Suspendisse viverra a velit dictum eleifend. Suspendisse vitae dapibus diam. Donec vehicula justo in ante interdum, eu luctus diam placerat. Vivamus convallis ipsum eu orci suscipit, sed fermentum enim euismod. Maecenas faucibus elit vitae ex ornare tristique. Donec vestibulum nec elit sit amet porttitor. Aenean tempor lectus eget tortor hendrerit luctus. Nullam interdum vitae lectus vel feugiat. Cras in risus non magna consectetur lobortis. Sed faucibus enim quis gravida convallis. + +Phasellus eget massa sit amet libero ultrices suscipit. Vivamus at risus sapien. Nam mollis nunc eget velit dictum maximus. Sed pellentesque, nunc ac fringilla lacinia, quam enim mattis ex, sed euismod tortor metus eu neque. Ut mattis nisl ut lectus rhoncus, sodales bibendum eros porta. Nulla porttitor enim nec diam sagittis, eget porta velit efficitur. Vestibulum ultricies eros neque. Phasellus rutrum suscipit enim, in interdum ante gravida vitae. Sed in sagittis diam, non commodo velit. + +Morbi hendrerit odio orci, nec tincidunt odio rhoncus nec. Mauris neque velit, vehicula a lorem at, suscipit tristique dui. Sed finibus, nisl in mattis convallis, turpis neque sodales lacus, eu porta enim magna non diam. Nam commodo sodales risus consectetur malesuada. In eget elementum justo. Phasellus sit amet massa imperdiet, dapibus nunc sit amet, suscipit orci. Fusce condimentum laoreet feugiat. Ut ut viverra ante. Praesent bibendum interdum commodo. Nulla mollis nisi a est ornare volutpat. Sed at ligula eu nisi dapibus tempus. Proin cursus vestibulum justo, nec efficitur justo dignissim vel. Nunc quis maximus eros. + +Cras viverra, diam a tristique mattis, libero felis vulputate tellus, a ornare felis leo a dui. Nulla ante nulla, finibus ut tellus ut, blandit pharetra nibh. Proin eleifend fermentum ex, eget auctor libero vulputate in. Nullam ultricies, mauris placerat pretium placerat, leo urna lobortis leo, vel placerat arcu libero sed mauris. Aliquam mauris ligula, ornare at urna at, eleifend gravida ligula. Vestibulum consectetur ut nulla non scelerisque. Donec ornare, sem nec elementum aliquam, urna nulla bibendum metus, eu euismod dui ligula ac est. Fusce laoreet erat eu ex lobortis, quis bibendum ligula interdum. Sed vel mi erat. Vivamus id lacus ac enim mattis tempor. Nunc ultricies pellentesque enim sed euismod. Fusce tincidunt convallis elit quis aliquam. Mauris nulla ipsum, sollicitudin quis diam ac, feugiat volutpat tellus. In nibh nibh, vulputate quis tincidunt quis, pulvinar eget magna. Pellentesque quis finibus dolor. Suspendisse viverra vitae lectus non eleifend. + +Nunc ut orci et sapien maximus semper. Nulla dignissim sem urna, ac varius lectus ultricies id. Quisque aliquet pulvinar pretium. In ultricies molestie tellus vehicula porta. Nam enim lorem, aliquam eget ex et, hendrerit volutpat quam. Maecenas diam lacus, pellentesque eget tempus ac, pharetra eu elit. Donec vel eros a sem facilisis vulputate. Nullam ac nisi vulputate, laoreet nisl ac, eleifend sem. Nullam mi massa, rhoncus sed pharetra interdum, tincidunt eget nunc. Aliquam viverra mattis posuere. Mauris et dui sed nisl sollicitudin fermentum quis ut arcu. Nam placerat eget orci at tincidunt. Curabitur vel turpis metus. Phasellus nibh nulla, fermentum scelerisque sem vel, gravida tincidunt velit. Pellentesque vel quam tempor, finibus massa pellentesque, condimentum dui. + +Donec at mattis neque. Etiam velit diam, consequat auctor mauris id, hendrerit faucibus metus. Maecenas ullamcorper eros a est sodales, ac consectetur odio scelerisque. Donec leo metus, imperdiet at pellentesque vel, feugiat id erat. Suspendisse at magna enim. Vestibulum placerat sodales lorem id sollicitudin. Aenean at euismod ligula, eget mollis diam. Phasellus pulvinar, orci nec pretium condimentum, est erat facilisis purus, quis feugiat augue elit aliquam nulla. Aenean vitae tortor id risus congue tincidunt. Sed dolor enim, mattis a ullamcorper id, volutpat ac leo. + +Proin vehicula feugiat augue, id feugiat quam sodales quis. Donec et ultricies massa, a lacinia nulla. Duis aliquam augue ornare euismod viverra. Ut lectus risus, rutrum sit amet efficitur a, luctus nec nisl. Cras volutpat ullamcorper congue. Sed vitae odio metus. Phasellus aliquet euismod varius. + +Nullam sem ex, malesuada ut magna ut, pretium mollis arcu. Nam porttitor eros cursus mi lacinia faucibus. Suspendisse aliquet eleifend iaculis. Maecenas sit amet viverra tortor. Nunc a mollis risus. Etiam tempus dolor in tortor malesuada mattis. Ut tincidunt venenatis est sit amet dignissim. Vestibulum massa enim, tristique sed scelerisque eu, fringilla ac velit. Donec efficitur quis urna sit amet malesuada. Vestibulum consequat ac ligula in dapibus. Maecenas massa massa, molestie non posuere nec, elementum ut magna. In nisi erat, mollis non venenatis eu, faucibus in justo. Morbi gravida non ex non egestas. Pellentesque finibus laoreet diam, eu commodo augue congue vitae. + +Aenean sem mi, ullamcorper dapibus lobortis vitae, interdum tincidunt tortor. Vivamus eget vulputate libero. Ut bibendum posuere lectus, vel tincidunt tortor aliquet at. Phasellus malesuada orci et bibendum accumsan. Aliquam quis libero vel leo mollis porta. Sed sagittis leo ac lacus dictum, ac malesuada elit finibus. Suspendisse pharetra luctus commodo. Vivamus ultricies a odio non interdum. Vivamus scelerisque tincidunt turpis quis tempor. Pellentesque tortor ligula, varius non nunc eu, blandit sollicitudin neque. Nunc imperdiet, diam et tristique luctus, ipsum ex condimentum nunc, sit amet aliquam justo velit sed libero. Duis vel suscipit ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed tincidunt neque vel massa ultricies, id dictum leo consequat. Curabitur lobortis ultricies tellus, eget mattis nisl aliquam sit amet. + +Proin at suscipit justo. Vivamus ut vestibulum nisl. Pellentesque enim odio, pharetra non magna sed, efficitur auctor magna. Praesent tincidunt ante quis ante hendrerit viverra. Pellentesque vel ipsum id magna vulputate efficitur. Sed nec neque accumsan, pulvinar sapien quis, euismod mauris. Donec condimentum laoreet sapien quis gravida. Quisque sed mattis purus. Vestibulum placerat vel neque maximus scelerisque. + +Vestibulum mattis quam quis efficitur elementum. Duis dictum dolor ac scelerisque commodo. Fusce sollicitudin nisi sit amet dictum placerat. Suspendisse euismod pharetra eleifend. In eros nisl, porttitor sed mauris at, consectetur aliquet mauris. Donec euismod viverra neque sed fermentum. Phasellus libero magna, accumsan ut ultricies vitae, dignissim eget metus. Donec tellus turpis, interdum eget maximus nec, hendrerit eget massa. Curabitur auctor ligula in iaculis auctor. In ultrices quam suscipit cursus finibus. Aenean id mi at dolor interdum iaculis vitae ut lorem. Nullam sed nibh fringilla, lacinia odio nec, placerat erat. In dui libero, viverra ac viverra ac, pellentesque sit amet turpis. + +Nulla in enim ex. Sed feugiat est et consectetur venenatis. Cras varius facilisis dui vel convallis. Vestibulum et elit eget tellus feugiat pellentesque. In ut ante eu purus aliquet posuere. Nulla nec ornare sem, sed luctus lorem. Nam varius iaculis odio, eget faucibus nisl ullamcorper in. Sed eget cursus felis, nec efficitur nisi. + +Vivamus commodo et sem quis pulvinar. Pellentesque libero ante, venenatis vitae ligula sit amet, ornare sollicitudin nulla. Mauris eget tellus hendrerit, pulvinar metus quis, tempor nisi. Proin magna ex, laoreet sed tortor quis, varius fermentum enim. Integer eu dolor dictum, vulputate tortor et, aliquet ligula. Vestibulum vitae justo id mauris luctus sollicitudin. Suspendisse eget auctor neque, sodales egestas lorem. Vestibulum lacinia egestas metus vitae euismod. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus ex tellus, volutpat nec pulvinar sit amet, condimentum vitae dui. Curabitur vel felis sodales, lacinia nunc iaculis, ullamcorper augue. Pellentesque consequat dolor quis eros efficitur malesuada. Nulla ut malesuada lectus. + +Morbi et tristique ante. Aliquam erat volutpat. Vivamus vitae dui nec turpis pellentesque fermentum. Quisque eget velit massa. Pellentesque tristique aliquam nisl, eu sollicitudin justo venenatis sed. Duis eleifend sem eros, ut aliquam libero porttitor id. Sed non nunc consequat, rhoncus diam eu, commodo erat. Praesent fermentum in lectus id blandit. Donec quis ipsum at justo volutpat finibus. Nulla blandit justo nulla, at mollis lacus consequat eget. Aenean sollicitudin quis eros ut ullamcorper. + +Pellentesque venenatis nulla ut mi aliquet feugiat. Cras semper vel magna nec pharetra. Integer mattis felis et sapien commodo imperdiet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis quis luctus felis. Vestibulum justo nibh, aliquam non lectus vitae, molestie placerat justo. Donec lorem nibh, gravida sit amet hendrerit ac, maximus id ipsum. Nunc ac libero sodales risus eleifend sagittis. Phasellus est massa, lobortis elementum ex sed, scelerisque consectetur neque. Nunc faucibus neque id lorem malesuada, eget convallis ex mattis. + +Sed turpis tortor, fermentum non turpis id, posuere varius nibh. Donec iaculis lorem dui. Etiam eros ante, sodales eget venenatis at, consectetur eget risus. Curabitur non aliquam ante, a pretium justo. Maecenas tempor nisl tortor, vitae dictum nisi ultrices eu. Duis eget dui ultrices, porttitor lacus sed, lobortis purus. Quisque mattis elit nec neque sagittis, sed commodo leo blandit. Mauris sodales interdum eleifend. Vestibulum condimentum consectetur augue, id luctus diam convallis et. + +Nunc suscipit risus in justo accumsan, a placerat magna tincidunt. Proin a nisl ipsum. Sed libero dui, tristique in augue quis, auctor tristique risus. Sed porttitor ex augue, eu porta augue molestie a. Duis rhoncus purus libero, eu tempus turpis condimentum at. Sed mollis nisi id lectus placerat tincidunt. Maecenas non scelerisque elit, quis rutrum orci. Donec in tellus pharetra urna ornare lobortis. Phasellus id risus at nisi varius rutrum eu ut turpis. + +Duis dictum justo quis nisl porta, eget tincidunt magna suscipit. Sed velit massa, ullamcorper eu sodales ac, pretium a massa. Duis et rutrum tortor. Nulla accumsan hendrerit sapien, cursus volutpat eros egestas eget. Donec sollicitudin at ante quis sollicitudin. Aenean blandit feugiat diam, id feugiat eros faucibus eget. Donec viverra dolor vel justo scelerisque dignissim. Nulla semper sem nunc, rhoncus semper tellus ultricies sed. Duis in ornare diam. Donec vehicula feugiat varius. Maecenas ut suscipit est. Vivamus sem sem, finibus at dolor sit amet, euismod dapibus ligula. Vestibulum fringilla odio dapibus, congue massa eget, congue sem. Donec feugiat magna eget tortor lacinia scelerisque non et ipsum. + +Suspendisse potenti. Nunc convallis sollicitudin ex eget venenatis. Sed iaculis nibh ex, vel ornare ligula congue dignissim. Quisque sollicitudin dolor ac dui vestibulum, sit amet molestie nisi aliquet. Donec at risus felis. Aenean sollicitudin metus a feugiat porta. Aenean a tortor ut dolor cursus sagittis. Vivamus consectetur porttitor nunc in facilisis. Proin sit amet mi vel lectus consectetur ultrices. + +Sed cursus lectus vitae nunc tristique, nec commodo turpis dapibus. Pellentesque luctus ex id facilisis ornare. Morbi quis placerat dolor. Donec in lectus in arcu mattis porttitor ac sit amet metus. Cras congue mauris non risus sodales, vitae feugiat ipsum bibendum. Nulla venenatis urna sed libero elementum, a cursus lorem commodo. Mauris faucibus lobortis eros nec commodo. + +Nullam suscipit ligula ullamcorper lorem commodo blandit. Nulla porta nibh quis pulvinar placerat. Vivamus eu arcu justo. Vestibulum imperdiet est ut fermentum porttitor. Pellentesque consectetur libero in sapien efficitur scelerisque. Curabitur ac erat sit amet odio aliquet dignissim. Pellentesque mi sem, rhoncus et luctus at, porttitor rutrum lectus. Vestibulum sollicitudin sollicitudin suscipit. Aenean efficitur dolor non ultrices imperdiet. Donec vel sem ex. + +Sed convallis mauris aliquam rutrum cursus. Ut tempor porttitor sodales. Etiam eu risus ac augue gravida egestas et eu dolor. Proin id magna ex. Suspendisse quis lectus quis lorem ultricies tempus. Donec porttitor velit vitae tincidunt faucibus. Aliquam vitae semper nisi. Morbi ultrices, leo non pretium dapibus, dui libero pellentesque ex, vel placerat enim ante vitae dui. Nunc varius, sem sit amet sagittis lobortis, lectus odio scelerisque mauris, ut vestibulum orci magna quis neque. Sed id congue justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris congue nisi est, malesuada mollis elit tincidunt sed. Curabitur sed ex sit amet felis tristique elementum vitae vel nibh. + +Etiam mollis pretium lobortis. Mauris augue lacus, efficitur at lacus sed, mollis tincidunt lectus. Aliquam erat volutpat. Donec at euismod elit, et mattis felis. Sed id lobortis urna. Morbi imperdiet vestibulum leo, sed maximus leo blandit eu. Aliquam semper lorem neque, nec euismod turpis mattis mollis. Quisque lobortis urna ultrices odio pretium, ac venenatis orci faucibus. Suspendisse bibendum odio ligula, sed lobortis massa pharetra nec. Donec turpis justo, iaculis at dictum ac, finibus eu libero. Maecenas quis porttitor mi, sit amet aliquet neque. + +Vivamus auctor vulputate ante, at egestas lorem. Donec eu risus in nulla mollis ultricies at et urna. Duis accumsan porta egestas. Ut vel euismod augue. Fusce convallis nulla ante, nec fringilla velit aliquet at. Nam malesuada dapibus ligula, a aliquam nibh scelerisque ac. Praesent malesuada neque et pellentesque interdum. Curabitur volutpat at turpis vitae tristique. Vivamus porttitor semper congue. Quisque suscipit lacus mi, rhoncus ultrices tortor auctor quis. Maecenas neque neque, molestie ac facilisis eget, luctus ac lorem. In ut odio ut lacus suscipit pulvinar vitae sed elit. Nulla imperdiet, sem quis euismod sagittis, dui erat luctus dolor, faucibus faucibus erat sem eget nunc. Nam accumsan placerat malesuada. Maecenas convallis finibus pulvinar. + +Cras at placerat tortor. Morbi facilisis auctor felis sit amet molestie. Donec sodales sed lorem vitae suscipit. Etiam fermentum pharetra ipsum, nec luctus orci gravida eu. Pellentesque gravida, est non condimentum tempus, mauris ligula molestie est, in congue dolor nisl vel sapien. Duis congue tempor augue, id rutrum eros porta dapibus. Etiam rutrum eget est eget vestibulum. Aenean mollis arcu vel consequat varius. Praesent at condimentum felis. Duis nec interdum nisl. Donec commodo lorem sed sapien scelerisque malesuada non eu urna. In blandit non ipsum at porta. Nam lobortis leo vitae dui auctor, non feugiat quam bibendum. Donec auctor lectus sagittis laoreet maximus. Maecenas rhoncus laoreet porttitor. Vestibulum porttitor augue ut lectus hendrerit, eget posuere mi gravida. + +Sed mattis ex in erat pulvinar, eu imperdiet magna dapibus. Etiam nisi nibh, tempus non tellus sit amet, mattis tempor odio. Quisque nec lorem feugiat, lobortis odio et, commodo nunc. Maecenas semper purus nisi, nec vehicula nibh eleifend vitae. Nulla fermentum a lectus at maximus. Phasellus finibus metus non euismod ultrices. Etiam a pulvinar ante. Quisque convallis nec metus sit amet facilisis. Praesent laoreet massa et sollicitudin laoreet. Vestibulum in mauris aliquet, convallis mi ut, elementum purus. Nulla purus nulla, sodales at hendrerit quis, tempus sed lectus. + +Nam ut laoreet neque, ut maximus nibh. Maecenas quis justo pellentesque, sollicitudin elit at, venenatis velit. Aenean nunc velit, vehicula scelerisque odio at, consectetur laoreet purus. Duis dui purus, malesuada quis ipsum sit amet, tempor interdum libero. Curabitur porta scelerisque sapien, vitae cursus diam condimentum eu. Phasellus sed orci quam. Nullam vitae dui quis purus tincidunt vestibulum. Curabitur quis nulla porta, cursus arcu non, auctor enim. Etiam sollicitudin ex id sem vehicula mollis. Morbi viverra laoreet tincidunt. Praesent ut semper dui. Nam sit amet pretium neque. Mauris vitae luctus diam, in lacinia purus. Maecenas ut placerat justo, ut porta felis. Integer eu mauris ante. + +Aenean porttitor tellus diam, tempor consequat metus efficitur id. Suspendisse ut felis at erat tempor dictum at nec sapien. Sed vestibulum interdum felis, ac mattis mauris porta in. Nunc et condimentum massa. Sed cursus dictum justo et luctus. Integer convallis enim nisl, a rutrum lectus ultricies in. Donec dapibus lacus at nulla dapibus, id sollicitudin velit hendrerit. Fusce a magna at orci mollis rutrum ac a dolor. Aliquam erat volutpat. Morbi varius porta nunc, sit amet sodales ex hendrerit commodo. Donec tincidunt tortor sapien, vitae egestas sapien vehicula eget. + +Suspendisse potenti. Donec pulvinar felis nec leo malesuada interdum. Integer posuere placerat maximus. Donec nibh ipsum, tincidunt vitae luctus vitae, bibendum at leo. Sed cursus nisl ut ex faucibus aliquet sed nec eros. Curabitur molestie posuere felis. Integer faucibus velit eget consequat iaculis. Mauris sed vulputate odio. Phasellus maximus, elit a pharetra egestas, lorem magna semper tellus, vestibulum semper diam felis at sapien. Suspendisse facilisis, nisl sit amet euismod vehicula, libero nulla vehicula dolor, quis fermentum nibh elit sit amet diam. + +Morbi lorem enim, euismod eu varius ut, scelerisque quis odio. Nam tempus vitae eros id molestie. Nunc pretium in nulla eget accumsan. Quisque mattis est ut semper aliquet. Maecenas eget diam elementum, fermentum ipsum a, euismod sapien. Duis quam ligula, cursus et velit nec, ullamcorper tincidunt magna. Donec vulputate nisl est, et ullamcorper urna tempor sit amet. + +Proin lacinia dui non turpis congue pretium. Morbi posuere metus vel purus imperdiet interdum. Morbi venenatis vel eros non ultricies. Nulla vel semper elit. Ut quis purus tincidunt, auctor justo ut, faucibus turpis. Proin quis mattis erat, at faucibus ligula. Mauris in mauris enim. Donec facilisis enim at est feugiat hendrerit. Nam vel nisi lorem. Fusce ultricies convallis diam, in feugiat tortor luctus quis. Donec tempor, leo vitae volutpat aliquam, magna elit feugiat leo, quis placerat sapien felis eget arcu. Donec ornare fermentum eleifend. Integer a est orci. + +Proin rhoncus egestas leo. Nulla ultricies porta elit quis ornare. Nunc fermentum interdum vehicula. In in ligula lorem. Donec nec arcu sit amet orci lobortis iaculis. Mauris at mollis erat, sit amet mollis tortor. Mauris laoreet justo ullamcorper porttitor auctor. Aenean sit amet aliquam lectus, id fermentum eros. Praesent urna sem, vehicula ac fermentum id, dapibus ut purus. Vestibulum vitae tempus nunc. Donec at nunc ornare metus volutpat porta at eget magna. Donec varius aliquet metus, eu lobortis risus aliquam sed. Ut dapibus fermentum velit, ac tincidunt libero faucibus at. + +In in purus auctor, feugiat massa quis, facilisis nisi. Donec dolor purus, gravida eget dolor ac, porttitor imperdiet urna. Donec faucibus placerat erat, a sagittis ante finibus ac. Sed venenatis dignissim elit, in iaculis felis posuere faucibus. Praesent sed viverra dolor. Mauris sed nulla consectetur nunc laoreet molestie in ut metus. Proin ac ex sit amet magna vulputate hendrerit ac condimentum urna. Proin ligula metus, gravida et sollicitudin facilisis, iaculis ut odio. Cras tincidunt urna et augue varius, ut facilisis urna consequat. Aenean vehicula finibus quam. Ut iaculis eu diam ac mollis. Nam mi lorem, tristique eget varius at, sodales at urna. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin vitae dictum erat, et auctor ipsum. Nullam nunc nunc, sollicitudin quis magna a, vestibulum fermentum mauris. Praesent at erat dolor. Proin laoreet tristique nulla vel efficitur. Nam sed ultrices nibh, id rutrum nunc. Curabitur eleifend a erat sit amet sollicitudin. Nullam metus quam, laoreet vitae dapibus id, placerat sed leo. Aliquam erat volutpat. Donec turpis nisl, cursus eu ex sit amet, lacinia pellentesque nisl. Sed id ipsum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec interdum scelerisque lorem eu mattis. + +Vivamus ac tristique massa, nec facilisis nisl. Nam ipsum neque, tincidunt vel urna in, cursus imperdiet enim. Nam pellentesque egestas tempus. Morbi facilisis imperdiet libero vitae fringilla. Nam lacinia ligula at sapien facilisis malesuada. Nullam accumsan pulvinar sem, et cursus libero porta sit amet. Curabitur vulputate erat elit, ut pulvinar erat maximus vel. + +Cras aliquet metus ut purus sagittis, vel venenatis ante consectetur. Pellentesque nulla lacus, viverra viverra mattis non, placerat vitae nibh. Donec enim turpis, accumsan sit amet tincidunt eu, imperdiet non metus. Morbi ipsum eros, tincidunt vel est ac, tristique porttitor nibh. Praesent ut ullamcorper mauris. Sed laoreet sit amet diam congue venenatis. Integer porta purus nec orci sagittis posuere. + +Donec vehicula mauris eget lacus mollis venenatis et sed nibh. Nam sodales ligula ipsum, scelerisque lacinia ligula sagittis in. Nam sit amet ipsum at erat malesuada congue. Aenean ut sollicitudin sapien. Etiam at tempor odio. Mauris vitae purus ut magna suscipit consequat. Vivamus quis sapien neque. Nulla vulputate sem sit amet massa pellentesque, eleifend tristique ligula egestas. Suspendisse tincidunt gravida mi, in pulvinar lectus egestas non. Aenean imperdiet ex sit amet nunc sollicitudin porta. Integer justo odio, ultricies at interdum in, rhoncus vitae sem. Sed porttitor arcu quis purus aliquet hendrerit. Praesent tempor tortor at dolor dictum pulvinar. Nulla aliquet nunc non ligula scelerisque accumsan. Donec nulla justo, congue vitae massa in, faucibus hendrerit magna. Donec non egestas purus. + +Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibus mattis neque dictum sed. Sed convallis fermentum molestie. Nulla facilisi turpis duis. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vulputate, ipsum quis interdum fermentum, lorem sem fermentum eros, vitae auctor neque lacus in nisi. Suspendisse potenti. Maecenas et scelerisque elit, in tincidunt quam. Sed eu tincidunt quam. Nullam justo ex, imperdiet a imperdiet et, fermentum sit amet eros. Aenean quis tempus sem. Pellentesque accumsan magna mi, ut mollis velit sagittis id. Etiam quis ipsum orci. Fusce purus ante, accumsan a lobortis at, venenatis eu nisl. Praesent ornare sed ante placerat accumsan. Suspendisse tempus dignissim fermentum. Nunc a leo ac lacus sodales iaculis eu vitae mi. In feugiat ante at massa finibus cursus. Suspendisse posuere fringilla ornare. Mauris elementum ac quam id convallis. Vestibulum non elit quis urna volutpat aliquam a eu lacus. + +Aliquam vestibulum imperdiet neque, suscipit aliquam elit ultrices bibendum. Suspendisse ultrices pulvinar cursus. Morbi risus nisi, cursus consequat rutrum vitae, molestie sed dui. Fusce posuere, augue quis dignissim aliquam, nisi ipsum porttitor ante, quis fringilla nisl turpis ac nisi. Nulla varius enim eget lorem vehicula gravida. Donec finibus malesuada leo nec semper. Proin ac enim eros. Vivamus non tincidunt nisi, vel tristique lorem. + +Nunc consequat ex id eros dignissim, id rutrum risus laoreet. Sed euismod non erat eu ultricies. Etiam vehicula gravida lacus ut porta. Vestibulum eu eros quis nunc aliquet luctus. Cras quis semper ligula. Nullam gravida vehicula quam sed porta. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In porta cursus vulputate. Quisque porta a nisi eget cursus. Aliquam risus leo, luctus ac magna in, efficitur cursus magna. In condimentum non mi id semper. Donec interdum ante eget commodo maximus. + +Vivamus sit amet vestibulum lectus. Fusce tincidunt mi sapien, dictum sollicitudin diam vulputate in. Integer fringilla consequat mollis. Cras aliquet consequat felis eget feugiat. Nunc tempor cursus arcu, vitae ornare nunc varius et. Vestibulum et tortor vel ante viverra porttitor. Nam at tortor ullamcorper, facilisis augue quis, tristique erat. Aenean ut euismod nibh. Quisque eu tincidunt est, nec euismod eros. + +Proin vehicula nibh non viverra egestas. Phasellus sem dolor, ultricies ac sagittis tristique, lacinia a purus. Vestibulum in ante eros. Pellentesque lacus nulla, tristique vitae interdum vel, malesuada ac diam. Aenean bibendum posuere turpis in accumsan. Ut est nulla, ullamcorper quis turpis at, viverra sagittis mauris. Sed in interdum purus. Praesent scelerisque nibh eget sem euismod, ut imperdiet mi venenatis. Vivamus pulvinar orci sed dapibus auctor. Nulla facilisi. Vestibulum tincidunt erat nec porttitor egestas. Mauris quis risus ante. Nulla facilisi. + +Aliquam ullamcorper ornare lobortis. Phasellus quis sem et ipsum mollis malesuada sed in ex. Ut aliquam ex eget metus finibus maximus. Proin suscipit mauris eu nibh lacinia, quis feugiat dui dapibus. Nam sed libero est. Aenean vulputate orci sit amet diam faucibus, eu sagittis sapien volutpat. Nam imperdiet felis turpis, at pretium odio pulvinar in. Sed vestibulum id eros nec ultricies. Sed quis aliquam tortor, vitae ullamcorper tellus. Donec egestas laoreet eros, id suscipit est rutrum nec. Sed auctor nulla eget metus aliquam, ut condimentum enim elementum. + +Aliquam suscipit non turpis sit amet bibendum. Fusce velit ligula, euismod et maximus at, luctus sed neque. Quisque pretium, nisl at ullamcorper finibus, lectus leo mattis sapien, vel euismod mauris diam ullamcorper ex. Nulla ut risus finibus, lacinia ligula at, auctor erat. Mauris consectetur sagittis ligula vel dapibus. Nullam libero libero, lobortis aliquam libero vel, venenatis ultricies leo. Duis porttitor, nibh congue fermentum posuere, erat libero pulvinar tortor, a pellentesque nunc ipsum vel sem. Nullam volutpat, eros sit amet facilisis consectetur, ipsum est vehicula massa, non vestibulum neque elit in mauris. Nunc hendrerit ipsum non enim bibendum, vitae rhoncus mi egestas. Etiam ullamcorper massa vel nisl sagittis, nec bibendum arcu malesuada. Aenean aliquet turpis justo, a consectetur arcu mollis convallis. Etiam tellus ipsum, ultricies vitae lorem et, ornare facilisis orci. Praesent fringilla justo urna, vel mollis neque pulvinar vestibulum. + +Donec non iaculis erat. Aliquam et mi sed nunc pulvinar ultricies in ut ipsum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Praesent feugiat lacus ac dignissim semper. Phasellus vitae quam nisi. Morbi vel diam ultricies risus lobortis ornare. Fusce maximus et ligula quis iaculis. Sed congue ex eget felis convallis, sit amet hendrerit elit tempor. Donec vehicula blandit ante eget commodo. Vestibulum eleifend diam at feugiat euismod. Etiam magna tellus, dignissim eget fermentum vel, vestibulum vitae mauris. Nam accumsan et erat id sagittis. Donec lacinia, odio ut ornare ultricies, dolor velit accumsan tortor, non finibus erat tellus quis ligula. Nunc quis metus in leo volutpat ornare vulputate eu nisl. + +Donec quis viverra ex. Nullam id feugiat mauris, eu fringilla nulla. Vestibulum id maximus elit. Cras elementum elit sed felis lobortis, eget sagittis nisi hendrerit. Vivamus vitae elit neque. Donec vulputate lacus ut libero ultrices accumsan. Vivamus accumsan nulla orci, in dignissim est laoreet sagittis. Proin at commodo velit. Curabitur in velit felis. Aliquam erat volutpat. Sed consequat, nulla et cursus sodales, nisi lacus mattis risus, quis eleifend erat ex nec turpis. Sed suscipit ultrices lorem in hendrerit. + +Morbi vitae lacus nec libero ornare tempus eu et diam. Suspendisse magna ipsum, fermentum vel odio quis, molestie aliquam urna. Fusce mollis turpis a eros accumsan porttitor. Pellentesque rhoncus dolor sit amet magna rutrum, et dapibus justo tempor. Sed purus nisi, maximus vitae fringilla eu, molestie nec urna. Fusce malesuada finibus pretium. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec sed aliquet eros. Pellentesque luctus diam ante, eget euismod nisl aliquet eu. Sed accumsan elit purus, tempor varius ligula tempus nec. Curabitur ornare leo suscipit suscipit fermentum. Morbi eget nulla est. Maecenas faucibus interdum tristique. + +Etiam ut elit eros. Nulla pharetra suscipit molestie. Nulla facilisis bibendum nisl non molestie. Curabitur turpis lectus, facilisis vel diam non, vulputate ultrices mauris. Aenean placerat aliquam convallis. Suspendisse sed scelerisque tellus. Vivamus lacinia neque eget risus cursus suscipit. Proin consequat dolor vel neque tempor, eu aliquam sem scelerisque. Duis non eros a purus malesuada pharetra non et nulla. Suspendisse potenti. Mauris libero eros, finibus vel nulla id, sagittis dapibus ante. Proin iaculis sed nunc et cursus. + +Quisque accumsan lorem sit amet lorem aliquet euismod. Curabitur fermentum rutrum posuere. Etiam ultricies, sem id pellentesque suscipit, urna magna lacinia eros, quis efficitur risus nisl at lacus. Nulla quis lacus tortor. Mauris placerat ex in dolor tincidunt, vel aliquet nisi pretium. Cras iaculis risus vitae pellentesque aliquet. Quisque a enim imperdiet, ullamcorper arcu vitae, rutrum risus. Nullam consectetur libero at felis fringilla, nec congue nibh dignissim. Nam et lobortis felis, eu pellentesque ligula. Aenean facilisis, ligula non imperdiet maximus, massa orci gravida sapien, at sagittis lacus nisl in lacus. Nulla quis mauris luctus, scelerisque felis consequat, tempus risus. Fusce auctor nisl non nulla luctus molestie. Maecenas sapien nisl, auctor non dolor et, iaculis scelerisque lorem. Suspendisse egestas enim aliquet, accumsan mauris nec, posuere quam. Nulla iaculis dui dui, sit amet vestibulum erat ultricies ac. + +Cras eget dolor erat. Proin at nisl ut leo consectetur ultricies vel ut arcu. Nulla in felis malesuada, ullamcorper tortor et, convallis massa. Nunc urna justo, ornare in nibh vitae, hendrerit condimentum libero. Etiam vitae libero in purus venenatis fringilla. Nullam velit nulla, consequat ut turpis non, egestas hendrerit nibh. Duis tortor turpis, interdum non ante ac, cursus accumsan lectus. Cras pharetra bibendum augue quis dictum. Sed euismod vestibulum justo. Proin porta lobortis purus. Duis venenatis diam tortor, sit amet condimentum eros rhoncus a. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc at magna nec diam lobortis efficitur sit amet ut lacus. Nulla quis orci tortor. Pellentesque tempus velit a odio finibus porta. + +Proin feugiat mauris a tellus scelerisque convallis. Maecenas libero magna, blandit nec ultrices id, congue vel mi. Aliquam lacinia, quam vel condimentum convallis, tortor turpis aliquam odio, sed blandit libero lacus et eros. In eleifend iaculis magna ac finibus. Praesent auctor facilisis tellus in congue. Sed molestie lobortis dictum. Nam quis dignissim augue, vel euismod lorem. Curabitur posuere dapibus luctus. Donec ultricies dictum lectus, quis blandit arcu commodo ac. Aenean tincidunt ligula in nunc imperdiet dignissim. Curabitur egestas sollicitudin sapien ut semper. Aenean nec dignissim lacus. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec aliquam dictum vehicula. Donec tortor est, volutpat non nisi nec, varius gravida ex. Nunc vel tristique nunc, vitae mattis nisi. Nunc nec luctus ex, vitae tincidunt lectus. In hac habitasse platea dictumst. Curabitur lobortis ex eget tincidunt tempor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut a vehicula mi. + +Fusce eu libero finibus, interdum nulla a, placerat neque. Cras bibendum tempor libero nec feugiat. Cras ut sodales eros. Proin viverra, massa sit amet viverra egestas, neque nisl porta ex, sit amet hendrerit libero ligula vel urna. Mauris suscipit lacus id justo rhoncus suscipit. Etiam vel libero tellus. Maecenas non diam molestie, condimentum tellus a, bibendum enim. Mauris aliquet imperdiet tellus, eget sagittis dolor. Sed blandit in neque et luctus. Cras elementum sagittis nunc, vel mollis lorem euismod et. Donec posuere at lacus eget suscipit. + +Nulla nunc mi, pretium non massa vel, tempor semper magna. Nunc a leo pulvinar, tincidunt nunc at, dignissim mi. Aliquam erat volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut viverra nulla a nisl finibus, at hendrerit ligula ullamcorper. Donec a lorem semper, tempor magna et, lobortis libero. Mauris id sapien leo. Donec dignissim, quam vitae porttitor dignissim, quam justo mattis dui, vel consequat odio elit quis orci. Etiam nec pretium neque, sit amet pretium orci. Duis ac tortor venenatis, feugiat purus non, feugiat nunc. Proin scelerisque nisl in turpis aliquam vulputate. + +Praesent sed est semper, fringilla lorem vitae, tincidunt nibh. Cras eros metus, auctor at mauris sit amet, sodales semper orci. Nunc a ornare ex. Curabitur bibendum arcu congue urna vulputate egestas. Vestibulum finibus id risus et accumsan. Aenean ut volutpat tellus. Aenean tincidunt malesuada urna sit amet vestibulum. Mauris vel tellus dictum, varius lacus quis, dictum arcu. + +Aenean quis metus eu erat feugiat cursus vel at ligula. Proin dapibus sodales urna, id euismod lectus tempus id. Pellentesque ex ligula, convallis et erat vel, vulputate condimentum nisl. Pellentesque pharetra nulla quis massa eleifend hendrerit. Praesent sed massa ipsum. Maecenas vehicula dolor massa, id sodales urna faucibus et. Mauris ac quam non massa tincidunt feugiat et at lacus. Fusce libero massa, vulputate vel scelerisque non, mollis in leo. Ut sit amet ultricies odio. Suspendisse in sapien viverra, facilisis purus ut, pretium libero. + +Vivamus tristique pharetra molestie. Nam a volutpat purus. Praesent consequat gravida nisi, ac blandit nisi suscipit ut. Quisque posuere, ligula a ultrices laoreet, ligula nunc vulputate libero, ut rutrum erat odio tincidunt justo. Sed vitae leo at leo fringilla bibendum. Vestibulum ut augue nec dolor auctor accumsan. Praesent laoreet id eros pulvinar commodo. Suspendisse potenti. Ut pharetra, mauris vitae blandit fringilla, odio ante tincidunt lorem, sit amet tempor metus diam ut turpis. + +Praesent quis egestas arcu. Nullam at porta arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi vulputate ligula malesuada ligula luctus, vulputate tempus erat bibendum. Nunc ullamcorper non lectus at euismod. Etiam nibh felis, tincidunt a metus vel, pellentesque rhoncus neque. Etiam at diam in erat luctus interdum. Nunc vel ipsum pulvinar, sollicitudin lacus ac, tempus urna. Etiam vel lacinia sapien. Pellentesque sagittis velit vel mi efficitur iaculis. Integer euismod sit amet urna in sagittis. Cras eleifend ut nibh in facilisis. Donec et lacus vitae nunc placerat sodales. Nulla sed hendrerit ligula, at dapibus sapien. + +Praesent at iaculis ex. Curabitur est purus, cursus a faucibus quis, dictum id velit. Donec dignissim fringilla viverra. Nunc mauris felis, laoreet sit amet sagittis at, vestibulum in libero. Maecenas quis orci turpis. Quisque ut nibh vitae magna mollis consequat id at mauris. Aliquam eu odio eget nulla bibendum sodales. Quisque vel orci eleifend nisi pretium lacinia. Suspendisse eget risus eget mi volutpat molestie eget quis lacus. Duis nisi libero, tincidunt nec nulla id, faucibus cursus felis. + +Donec tempor eget risus pellentesque molestie. Phasellus porta neque vel arcu egestas, nec blandit velit fringilla. Nullam porta faucibus justo vitae laoreet. Pellentesque viverra id nunc eu varius. Nulla pulvinar lobortis iaculis. Etiam vestibulum odio nec velit tristique, a tristique nisi mattis. In sed fringilla orci, vitae efficitur odio. Quisque dui odio, ornare eget velit at, lacinia consequat libero. Quisque lectus nulla, aliquet eu leo in, porta rutrum diam. Donec nec mattis neque. Nam rutrum, odio ac eleifend bibendum, dolor arcu rutrum neque, eget porta elit tellus a lacus. Sed massa metus, sollicitudin et sapien eu, finibus tempus orci. Proin et sapien sit amet erat molestie interdum. In quis rutrum velit, faucibus ultrices tellus. + +Sed sagittis sed justo eget tincidunt. Maecenas ut leo sagittis, feugiat magna et, viverra velit. Maecenas ex arcu, feugiat at consequat vitae, auctor eu massa. Integer egestas, enim vitae maximus convallis, est lectus pretium mauris, ac posuere lectus nisl quis quam. Aliquam tempus laoreet mi, vitae dapibus dolor varius dapibus. Suspendisse potenti. Donec sit amet purus nec libero dapibus tristique. Pellentesque viverra bibendum ligula. Donec sed felis et ex lobortis laoreet. Phasellus a fringilla libero, vitae malesuada nulla. Pellentesque blandit mattis lacus, et blandit tortor laoreet consequat. Suspendisse libero nunc, viverra sed fermentum in, accumsan egestas arcu. Proin in placerat elit. Sed interdum imperdiet malesuada. Suspendisse aliquet quis mauris eget sollicitudin. + +Vivamus accumsan tellus non erat volutpat, quis dictum dolor feugiat. Praesent rutrum nunc ac est mollis cursus. Fusce semper volutpat dui ut egestas. Curabitur sit amet posuere massa. Cras tincidunt nulla et mi mollis imperdiet. Suspendisse scelerisque ex id sodales vulputate. In nunc augue, pharetra in placerat eu, mattis id tellus. Vivamus cursus efficitur vehicula. Nulla aliquet vehicula aliquet. + +Sed cursus tellus sed porta pulvinar. Sed vitae nisi neque. Nullam aliquet, lorem et efficitur scelerisque, arcu diam aliquam felis, sed pulvinar lorem odio et turpis. Praesent convallis pulvinar turpis eu iaculis. Aliquam nec gravida mi. Curabitur eu nibh tempor, blandit justo in, ultrices felis. Fusce placerat metus non mi sagittis rutrum. Morbi sed dui fringilla, sagittis mauris eget, imperdiet nunc. Phasellus hendrerit sem elit, id hendrerit libero auctor sit amet. Integer sodales elit sit amet consequat cursus. + +Nam semper est eget nunc mollis, in pellentesque lectus fringilla. In finibus vel diam id semper. Nunc mattis quis erat eu consectetur. In hac habitasse platea dictumst. Nullam et ipsum vestibulum ex pulvinar ultricies sit amet id velit. Aenean suscipit mi tortor, a lobortis magna viverra non. Nulla condimentum aliquet ante et ullamcorper. Pellentesque porttitor arcu a posuere tempus. Aenean lacus quam, imperdiet eu justo vitae, pretium efficitur ex. Duis id purus id magna rhoncus ultrices id eu risus. Nunc dignissim et libero id dictum. + +Quisque a tincidunt neque. Phasellus commodo mi sit amet tempor fringilla. Ut rhoncus, neque non porttitor elementum, libero nulla egestas augue, sed fringilla sapien felis ac velit. Phasellus viverra rhoncus mollis. Nam ullamcorper leo vel erat laoreet luctus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus semper a metus a cursus. Nulla sed orci egestas, efficitur purus ac, malesuada tellus. Aenean rutrum velit at tellus fermentum mollis. Aliquam eleifend euismod metus. + +In hac habitasse platea dictumst. Vestibulum volutpat neque vitae porttitor laoreet. Nam at tellus consequat, sodales quam in, pulvinar arcu. Maecenas varius convallis diam, ac lobortis tellus pellentesque quis. Maecenas eget augue massa. Nullam volutpat nibh ac justo rhoncus, ut iaculis tellus rutrum. Fusce efficitur efficitur libero quis condimentum. Curabitur congue neque non tincidunt tristique. Fusce eget tempor ex, at pellentesque odio. Praesent luctus dictum vestibulum. Etiam non orci nunc. Vivamus vitae laoreet purus, a lobortis velit. Curabitur tincidunt purus ac lectus elementum pellentesque. Quisque sed tincidunt est. + +Sed vel ultrices massa, vitae ultricies justo. Cras finibus mauris nec lacus tempus dignissim. Cras faucibus maximus velit, eget faucibus orci luctus vehicula. Nulla massa nunc, porta ac consequat eget, rhoncus non tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce sed maximus metus, vel imperdiet ipsum. Ut scelerisque lectus at blandit porttitor. Ut vulputate nunc pharetra, aliquet sapien ac, sollicitudin sapien. Aenean eget ante lorem. Nam accumsan venenatis tellus id dignissim. + +Curabitur fringilla, magna non maximus dapibus, nulla sapien vestibulum lectus, sit amet semper dolor neque vitae nisl. Nunc ultrices vehicula augue sed iaculis. Maecenas nec diam mollis, suscipit orci et, vestibulum ante. Pellentesque eu nisl tortor. Nunc eleifend, lacus quis volutpat volutpat, nisi mi molestie sem, quis mollis ipsum libero a tellus. Ut viverra dolor mattis convallis interdum. Sed tempus nisl at nunc scelerisque aliquet. Quisque tempor tempor lorem id feugiat. Nullam blandit lectus velit, vitae porta lacus tincidunt a. Vivamus sit amet arcu ultrices, tincidunt mi quis, viverra quam. Aenean fringilla libero elementum lorem semper, quis pulvinar eros gravida. Nullam sodales blandit mauris, sed fermentum velit fermentum sit amet. Donec malesuada mauris in augue sodales vulputate. Vestibulum gravida turpis id elit rhoncus dignissim. Integer non congue lorem, eu viverra orci. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at dolor magna. Aliquam consectetur erat augue, id iaculis velit pharetra ac. Integer rutrum venenatis dignissim. Integer non sodales elit. Curabitur ut magna ut nibh feugiat aliquam ac ut risus. Morbi nibh quam, aliquam id placerat nec, vestibulum eget velit. Suspendisse at dignissim quam. Vivamus aliquet sem sed nisl volutpat, ut cursus orci ultrices. Aliquam ultrices lacinia enim, vitae aliquet neque. + +Quisque scelerisque finibus diam in mattis. Cras cursus auctor velit. Aliquam sem leo, fermentum et maximus et, molestie a libero. Aenean justo elit, rutrum a ornare id, egestas eget enim. Aenean auctor tristique erat. Curabitur condimentum libero lacus, nec consequat orci vestibulum sed. Fusce elit ligula, blandit vitae sapien vitae, dictum ultrices risus. Nam laoreet suscipit sapien, at interdum velit faucibus sit amet. Duis quis metus egestas lectus elementum posuere non nec libero. Aliquam a dolor bibendum, facilisis nunc a, maximus diam. Vestibulum suscipit tristique magna, non dignissim turpis sodales sed. Nunc ornare, velit ac facilisis fringilla, dolor mi consectetur lorem, vitae finibus erat justo suscipit urna. Maecenas sit amet eros erat. Nunc non arcu ornare, suscipit lorem eget, sodales mauris. Aliquam tincidunt, quam nec mollis lacinia, nisi orci fermentum libero, consequat eleifend lectus quam et sapien. Vestibulum a quam urna. + +Cras arcu leo, euismod ac ullamcorper at, faucibus sed massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus porttitor velit in enim interdum, non commodo metus ornare. Morbi vel lorem quis nisl luctus tristique quis vitae nisl. Suspendisse condimentum tortor enim, nec eleifend ipsum euismod et. Sed gravida quam ut tristique lacinia. Mauris eu interdum ipsum, ac ultrices odio. Nullam auctor tellus a risus porttitor vehicula. Nulla blandit euismod dictum. In pharetra, enim iaculis pulvinar interdum, dui nunc placerat nunc, sit amet pretium lectus nulla vitae quam. Phasellus quis enim sollicitudin, varius nulla id, ornare purus. Donec quam lacus, vestibulum quis nunc ac, mollis dictum nisi. Cras ut mollis elit. Maecenas ultrices ligula at risus faucibus scelerisque. Etiam vitae porttitor purus. Curabitur blandit lectus urna, ut hendrerit tortor feugiat ut. + +Phasellus fringilla, sapien pellentesque commodo pharetra, ante libero aliquam tellus, ut consectetur augue libero a sapien. Maecenas blandit luctus nisl eget aliquet. Maecenas vitae porta dolor, faucibus laoreet sapien. Suspendisse lobortis, ipsum sed vehicula aliquam, elit purus scelerisque dui, rutrum consectetur diam odio et lorem. In nec lacinia metus. Donec viverra libero est, vel bibendum erat condimentum quis. Donec feugiat purus leo. In laoreet vitae felis a porttitor. Mauris ullamcorper, lacus id condimentum suscipit, neque magna pellentesque arcu, eget cursus neque tellus id metus. Curabitur volutpat ac orci vel ultricies. + +Sed ut finibus erat. Sed diam purus, varius non tincidunt quis, ultrices sit amet ipsum. Donec et egestas nulla. Suspendisse placerat nisi at dui laoreet iaculis. Aliquam aliquet leo at augue faucibus molestie. Nullam lacus augue, hendrerit sed nisi eu, faucibus porta est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam ut leo aliquet sem fermentum rutrum quis ac justo. Integer placerat aliquam nisl ut sagittis. Proin erat orci, lobortis et sem eget, eleifend fringilla augue. Mauris varius laoreet arcu, sed tincidunt felis. Pellentesque venenatis lorem odio, id pulvinar velit molestie feugiat. Donec mattis lacus sed eleifend pulvinar. + +Sed condimentum ex in tincidunt hendrerit. Etiam eget risus lacinia, euismod nibh eu, pellentesque quam. Proin elit eros, convallis id mauris ac, bibendum ultrices lectus. Morbi venenatis, purus id fermentum consequat, nunc libero tincidunt ligula, non dictum ligula orci nec quam. Nulla nec ultrices lorem. Aenean maximus augue vel dictum pharetra. Etiam turpis urna, pellentesque quis malesuada eu, molestie faucibus felis. + +Vestibulum pharetra augue ut quam blandit congue in nec risus. Proin eu nibh eu dui eleifend porta vitae id lectus. Proin lacus nibh, lobortis sed ligula vitae, interdum lobortis erat. Suspendisse potenti. In sollicitudin quis sapien ut aliquet. Mauris ac nulla arcu. Fusce tristique justo quis lectus mollis, eu volutpat lectus finibus. Vivamus venenatis facilisis ex ut vestibulum. + +Etiam varius lobortis purus, in hendrerit elit tristique at. In tempus, augue vestibulum fermentum gravida, ligula tellus vulputate arcu, eu molestie ex sapien at purus. Vestibulum nec egestas metus. Duis pulvinar quam nec consequat interdum. Aenean non dapibus lacus. Aliquam sit amet aliquet nulla. Sed venenatis volutpat purus nec convallis. Phasellus aliquet semper sodales. Cras risus sapien, condimentum auctor urna a, pulvinar ornare nisl. Sed tincidunt felis elit, ut elementum est bibendum ac. Morbi interdum justo vel dui faucibus condimentum. + +Sed convallis eu sem at tincidunt. Nullam at auctor est, et ullamcorper ipsum. Pellentesque eget ante ante. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer euismod, sapien sed dapibus ornare, nibh enim maximus lacus, lacinia placerat urna quam quis felis. Morbi accumsan id nisl ut condimentum. Donec bibendum nisi est, sed volutpat lorem rhoncus in. Vestibulum ac lacinia nunc, eget volutpat magna. Integer aliquam pharetra ipsum, id placerat nunc volutpat quis. Etiam urna diam, rhoncus sit amet varius vel, euismod vel sem. Nullam vel molestie urna. Vivamus ornare erat at venenatis euismod. Suspendisse potenti. Fusce diam justo, tincidunt vel sem at, commodo faucibus nisl. Duis gravida efficitur diam, vel sagittis erat pulvinar ut. + +Quisque vel pharetra felis. Duis efficitur tortor dolor, vitae porttitor erat fermentum sed. Sed eu mi purus. Etiam dignissim tortor eu tempus molestie. Aenean pretium erat enim, in hendrerit ante hendrerit at. Sed ut risus vel nunc venenatis ultricies quis in lacus. Pellentesque vitae purus euismod, placerat risus non, ullamcorper augue. Quisque varius quam ligula, nec aliquet ex faucibus vitae. Quisque rhoncus sit amet leo tincidunt mattis. Cras id mauris eget purus pretium gravida sit amet eu augue. Aliquam dapibus odio augue, id lacinia velit pulvinar eu. + +Mauris fringilla, tellus nec pharetra iaculis, neque nisi ultrices massa, et tincidunt sem dui sed mi. Curabitur erat lorem, venenatis quis tempus lacinia, tempus sit amet nunc. Aliquam at neque ac metus commodo dictum quis vitae justo. Phasellus eget lacus tempus, blandit lorem vel, rutrum est. Aenean pharetra sem ut augue lobortis dignissim. Sed rhoncus at nulla id ultrices. Cras id condimentum felis. In suscipit luctus vulputate. Donec tincidunt lacus nec enim tincidunt sollicitudin ut quis enim. Nam at libero urna. Praesent sit amet massa vitae massa ullamcorper vehicula. + +Nullam bibendum augue ut turpis condimentum bibendum. Proin sit amet urna hendrerit, sodales tortor a, lobortis lectus. Integer sagittis velit turpis, et tincidunt nisi commodo eget. Duis tincidunt elit finibus accumsan cursus. Aenean dignissim scelerisque felis vel lacinia. Nunc lacinia maximus luctus. In hac habitasse platea dictumst. Vestibulum eget urna et enim tempor tempor. Nam feugiat, felis vel vestibulum tempus, orci justo viverra diam, id dapibus lorem justo in ligula. + +Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In ac pellentesque sem. Vestibulum lacinia magna dui, eu lacinia augue placerat et. Maecenas pulvinar congue est. Pellentesque commodo dui non pulvinar scelerisque. Etiam interdum est posuere sem bibendum, ac commodo magna dictum. Cras ipsum turpis, rhoncus nec posuere vitae, laoreet a arcu. Integer ac massa sit amet enim placerat lacinia sed ultrices arcu. Suspendisse sem nibh, luctus sit amet volutpat in, pellentesque eu metus. Ut gravida neque eget mi accumsan tempus. Nam sit amet aliquet nibh. + +Pellentesque a purus cursus nulla hendrerit congue quis et odio. Aenean hendrerit, leo ullamcorper sagittis hendrerit, erat dui molestie quam, sed condimentum lacus risus sed tellus. Morbi a dapibus lectus, ut feugiat ex. Phasellus pretium quam et sapien mollis, vel iaculis dui dignissim. Sed ullamcorper est turpis, a viverra lorem consectetur in. Aenean aliquet nibh non cursus rutrum. Suspendisse at tristique urna, id lobortis urna. In hac habitasse platea dictumst. Phasellus libero velit, rutrum sed tellus nec, dapibus tincidunt ligula. Quisque vel dui venenatis, consequat nisl ut, lacinia ipsum. Phasellus vitae magna pellentesque, lobortis est id, faucibus quam. Nam eleifend faucibus dui vel pellentesque. + +Etiam ut est non lacus tincidunt interdum. Maecenas sed massa urna. Quisque ut nibh tortor. Pellentesque felis ipsum, tempor finibus ipsum et, euismod pretium metus. Donec sit amet est ipsum. Quisque rhoncus justo non finibus elementum. Nulla nec lectus ac tortor placerat fringilla. Phasellus ac ultrices nunc, eu efficitur nisl. Nulla rhoncus nunc vitae ante dictum tincidunt. Nunc ultrices, massa sit amet malesuada dignissim, lectus lacus consequat sapien, non eleifend metus sem in eros. Phasellus mauris ante, dictum sit amet suscipit ac, rhoncus eget nisi. Phasellus at orci mollis, imperdiet neque eget, faucibus nulla. In at purus massa. Pellentesque quis rutrum lectus. + +Integer eu faucibus turpis, sit amet mollis massa. Vestibulum id nulla commodo, rutrum ipsum sed, semper ante. Phasellus condimentum orci nec nibh convallis, ac maximus orci ullamcorper. Maecenas vitae sollicitudin mi. Integer et finibus lectus, et condimentum ligula. Donec elementum tristique quam vitae dapibus. Morbi euismod ipsum in tristique ullamcorper. + +Duis fermentum non enim eu auctor. Quisque lacinia nibh vehicula nibh posuere, eu volutpat turpis facilisis. Ut ac faucibus nulla. Sed eleifend quis ex et pellentesque. Vestibulum sollicitudin in libero id fringilla. Phasellus dignissim purus consequat, condimentum dui sit amet, condimentum ante. Pellentesque ac consectetur massa, quis sagittis est. Nulla maximus tristique risus accumsan convallis. Curabitur imperdiet ac lacus a ultrices. Nulla facilisi. Sed quis quam quis lectus placerat lobortis vel sed turpis. In mollis dui id neque iaculis, ut aliquet tellus malesuada. Proin at luctus odio, vel blandit sapien. Praesent dignissim tortor vehicula libero fringilla, nec ultrices erat suscipit. Maecenas scelerisque purus in dapibus fermentum. + +Curabitur magna odio, mattis in tortor ut, porttitor congue est. Vestibulum mollis lacinia elementum. Fusce maximus erat vitae nunc rutrum lobortis. Integer ligula eros, auctor vel elit non, posuere luctus lacus. Maecenas quis auctor massa. Ut ipsum lacus, efficitur posuere euismod et, hendrerit efficitur est. Phasellus fringilla, quam id tincidunt pretium, nunc dui sollicitudin orci, eu dignissim nisi metus ut magna. Integer lobortis interdum dolor, non bibendum purus posuere et. Donec non lectus aliquet, pretium dolor eu, cursus massa. Sed ut dui sapien. In sed vestibulum massa. Pellentesque blandit, dui non sodales vehicula, orci metus mollis nunc, non pharetra ex tellus ac est. Mauris sagittis metus et fermentum pretium. Nulla facilisi. Quisque quis ante ut nulla placerat mattis ut quis nisi. + +Sed quis nulla ligula. Quisque dignissim ligula urna, sed aliquam purus semper at. Suspendisse potenti. Nunc massa lectus, pharetra vehicula arcu bibendum, imperdiet sodales ipsum. Nam ac sapien diam. Mauris iaculis fringilla mattis. Pellentesque tempus eros sit amet justo volutpat mollis. Phasellus ac turpis ipsum. Morbi vel ante elit. Aenean posuere quam consequat velit varius suscipit. Donec tempor quam ut nibh cursus efficitur. + +Morbi molestie dolor nec sem egestas suscipit. Etiam placerat pharetra lectus, et ullamcorper risus tristique in. Sed faucibus ullamcorper lectus eget fringilla. Maecenas malesuada hendrerit congue. Sed eget neque a erat placerat tincidunt. Aliquam vitae dignissim turpis. Fusce at placerat magna, a laoreet lectus. Maecenas a purus nec diam gravida fringilla. Nam malesuada euismod ante non vehicula. In faucibus bibendum leo, faucibus posuere nisl pretium quis. Fusce finibus bibendum finibus. Vestibulum eu justo maximus, hendrerit diam nec, dignissim sapien. Aenean dolor lacus, malesuada quis vestibulum ac, venenatis ac ipsum. Cras a est id nunc finibus facilisis. Cras lacinia neque et interdum vehicula. Suspendisse vulputate tellus elit, eget tempor dui finibus vel. + +Cras sed pretium odio. Proin hendrerit elementum felis in tincidunt. Nam sed turpis vel justo molestie accumsan condimentum eu nunc. Praesent lobortis euismod rhoncus. Nulla vitae euismod nibh, quis mattis mi. Fusce ultrices placerat porttitor. Duis sem ipsum, pellentesque sit amet odio a, molestie vulputate mauris. + +Duis blandit mollis ligula, sit amet mattis ligula finibus sit amet. Nunc a leo molestie, placerat diam et, vestibulum leo. Suspendisse facilisis neque purus, nec pellentesque ligula fermentum nec. Aenean malesuada mauris lorem, eu blandit arcu pulvinar quis. Duis laoreet urna lacus, non maximus arcu rutrum ultricies. Nulla augue dolor, suscipit eu mollis eu, aliquam condimentum diam. Ut semper orci luctus, pharetra turpis at, euismod mi. Nulla leo diam, finibus sit amet purus sed, maximus dictum lorem. Integer eu mi id turpis laoreet rhoncus. + +Integer a mauris tincidunt, finibus orci ut, pretium mauris. Nulla molestie nunc mi, id finibus lorem elementum sed. Proin quis laoreet ante. Integer nulla augue, commodo id molestie quis, rutrum ut turpis. Suspendisse et tortor turpis. Sed ut pharetra massa. Pellentesque elementum blandit sem, ut elementum tellus egestas a. Fusce eu purus nibh. + +Cras dignissim ligula scelerisque magna faucibus ullamcorper. Proin at condimentum risus, auctor malesuada quam. Nullam interdum interdum egestas. Nulla aliquam nisi vitae felis mollis dictum. Suspendisse dapibus consectetur tortor. Ut ut nisi non sem bibendum tincidunt. Vivamus suscipit leo quis gravida dignissim. + +Aliquam interdum, leo id vehicula mollis, eros eros rhoncus diam, non mollis ligula mi eu mauris. Sed ultrices vel velit sollicitudin tincidunt. Nunc auctor metus at ligula gravida elementum. Praesent interdum eu elit et mollis. Duis egestas quam sit amet velit dignissim consequat. Aliquam ac turpis nec nunc convallis sagittis. Fusce blandit, erat ac fringilla consectetur, dolor eros sodales leo, vel aliquet risus nisl et diam. Aliquam luctus felis vitae est eleifend euismod facilisis et lacus. Sed leo tellus, auctor eu arcu in, volutpat sagittis nisl. Pellentesque nisl ligula, placerat vel ullamcorper at, vulputate ac odio. Morbi ac faucibus orci, et tempus nulla. Proin rhoncus rutrum dolor, in venenatis mauris. Suspendisse a fermentum augue, non semper mi. Nunc eget pretium neque. Phasellus augue erat, feugiat ac aliquam congue, rutrum non sapien. Pellentesque ac diam gravida, consectetur felis at, ornare neque. + +Nullam interdum mattis sapien quis porttitor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus aliquet rutrum ipsum id euismod. Maecenas consectetur massa et mi porta viverra. Nunc quam nibh, dignissim vitae maximus et, ullamcorper nec lorem. Nunc vitae justo dapibus, luctus lacus vitae, pretium elit. Maecenas et efficitur leo. Curabitur mauris lectus, placerat quis vehicula vitae, auctor ut urna. Quisque rhoncus pharetra luctus. In hac habitasse platea dictumst. Integer sit amet metus nec eros malesuada aliquam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi hendrerit mi ac leo aliquam, sit amet ultricies libero commodo. Mauris dapibus purus metus, sit amet viverra nibh imperdiet et. Nullam porta nulla tellus, quis vehicula diam imperdiet non. Vivamus enim massa, bibendum in fermentum in, ultrices at ex. + +Suspendisse fermentum id nibh eget accumsan. Duis dapibus bibendum erat ut sollicitudin. Aliquam nec felis risus. Pellentesque rhoncus ligula id sem maximus mollis sed nec massa. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ipsum ipsum, sodales sed enim id, convallis faucibus eros. Donec ultricies dictum tincidunt. Cras vitae nibh arcu. Pellentesque cursus, sapien nec consequat fermentum, ipsum ante suscipit dui, imperdiet hendrerit est nisl eu massa. Quisque vitae sem ligula. Aenean iaculis metus ut mauris interdum laoreet. Vivamus sed gravida dolor. + +Morbi nulla metus, porttitor sed eros sit amet, efficitur efficitur est. In vel nisl urna. Ut aliquet tellus at congue convallis. Phasellus imperdiet lobortis sollicitudin. Integer sodales, sem eu ultricies pharetra, erat erat porttitor odio, eget dapibus libero ipsum eget velit. Phasellus gravida nulla nisl, eu pharetra mi auctor vel. Sed blandit pharetra velit, ut egestas libero placerat non. Aliquam a interdum quam. Proin at tortor nec dui sollicitudin tempus sed vestibulum elit. Nunc non sollicitudin velit. + +Aenean consequat diam velit, sed rutrum tortor faucibus dictum. Quisque at semper augue. Duis ut est eget mi ornare bibendum id et ligula. Phasellus consequat tortor non leo pulvinar posuere. Proin vestibulum eleifend felis, in hendrerit tortor sollicitudin eu. Phasellus hendrerit, lacus vel laoreet interdum, dui tortor consequat justo, commodo ultricies arcu felis vitae enim. Vivamus eu sapien at leo suscipit rutrum eu at justo. Aenean et dolor a libero ullamcorper posuere. Integer laoreet placerat nisi in vulputate. Mauris laoreet eget risus sed cursus. Donec scelerisque neque a libero eleifend hendrerit. Nulla varius condimentum nunc sit amet fermentum. Aliquam lorem ex, varius nec mollis ut, ultrices in neque. Morbi sit amet porta leo. Integer iaculis fermentum lacus in vestibulum. + +Ut gravida, tellus ut maximus ultrices, erat est venenatis nisl, vitae pretium massa ex ac magna. Sed non purus eget ligula aliquet volutpat non quis arcu. Nam aliquam tincidunt risus, sit amet fringilla sapien vulputate ut. Mauris luctus suscipit pellentesque. Nunc porttitor dapibus ex quis tempus. Ut ullamcorper metus a eros vulputate, vitae viverra lectus convallis. Mauris semper imperdiet augue quis tincidunt. Integer porta pretium magna, sed cursus sem scelerisque sollicitudin. Nam efficitur, nibh pretium eleifend vestibulum, purus diam posuere sem, in egestas mauris augue sit amet urna. + +Vestibulum tincidunt euismod massa in congue. Duis interdum metus non laoreet fringilla. Donec at ligula congue, tincidunt nunc non, scelerisque nunc. Donec bibendum magna non est scelerisque feugiat at nec neque. Ut orci tortor, tempus eget massa non, dignissim faucibus dolor. Nam odio risus, accumsan pretium neque eget, accumsan dignissim dui. In ut neque auctor, scelerisque tellus sed, ullamcorper nisi. Suspendisse varius cursus quam at hendrerit. Vivamus elit libero, sagittis vitae sem ac, vulputate iaculis ligula. + +Sed lobortis laoreet purus sit amet rutrum. Pellentesque feugiat non leo vel lacinia. Quisque feugiat nisl a orci bibendum vestibulum. In et sollicitudin urna. Morbi a arcu ac metus faucibus tempus. Nam eu imperdiet sapien, suscipit mattis tortor. Aenean blandit ipsum nisi, a eleifend ligula euismod at. Integer tincidunt pharetra felis, mollis placerat mauris hendrerit at. Curabitur convallis, est sit amet luctus volutpat, massa lacus cursus augue, sed eleifend magna quam et risus. Aliquam lobortis tincidunt metus vitae porttitor. Suspendisse potenti. Aenean ullamcorper, neque id commodo luctus, nulla nunc lobortis quam, id dapibus neque dui nec mauris. Etiam quis lorem quis elit commodo ornare. Ut pharetra purus ultricies enim ultrices efficitur. Proin vehicula tincidunt molestie. Mauris et placerat sem. + +Aliquam erat volutpat. Suspendisse velit turpis, posuere ac lacus eu, lacinia laoreet velit. Sed interdum felis neque, id blandit sem malesuada sit amet. Ut sagittis justo erat, efficitur semper orci tempor sed. Donec enim massa, posuere varius lectus egestas, pellentesque posuere mi. Cras tincidunt ut libero sed mattis. Suspendisse quis magna et tellus posuere interdum vel at purus. Pellentesque fringilla tristique neque, id aliquet tellus ultricies non. Duis ut tellus vel odio lobortis vulputate. + +Integer at magna ac erat convallis vestibulum. Sed lobortis porttitor mauris. Fusce varius lorem et volutpat pulvinar. Aenean ac vulputate lectus, vitae consequat velit. Suspendisse ex dui, varius ut risus ut, dictum scelerisque sem. Vivamus urna orci, volutpat ut convallis ac, venenatis vitae urna. In hac habitasse platea dictumst. Etiam eu purus arcu. Aenean vulputate leo urna, vel tristique dui sagittis euismod. Suspendisse non tellus efficitur ante rhoncus volutpat at et sapien. + +Sed dapibus accumsan porttitor. Phasellus facilisis lectus finibus ligula dignissim, id pulvinar lectus feugiat. Nullam egestas commodo nisi posuere aliquet. Morbi sit amet tortor sagittis, rutrum dui nec, dapibus sapien. Sed posuere tortor tortor, interdum auctor magna varius vitae. Vestibulum id sagittis augue. Curabitur fermentum arcu sem, eu condimentum quam rutrum non. Phasellus rutrum nibh quis lectus rhoncus pretium. Curabitur dictum interdum elit. Vestibulum maximus sodales imperdiet. Mauris auctor nec purus sed venenatis. In in urna purus. + +Duis placerat molestie suscipit. Morbi a elit id purus efficitur consequat. Nunc ac commodo turpis. Etiam sit amet lacus a ipsum tempus venenatis sed vel nibh. Duis elementum aliquam mi sed tristique. Morbi ligula tortor, semper ac est vel, lobortis maximus erat. Curabitur ipsum felis, laoreet vel condimentum eget, ullamcorper sit amet mauris. Nulla facilisi. Nam at purus sed mi egestas placerat vitae vel magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse at dignissim diam. Phasellus consectetur eget neque vel viverra. Donec sollicitudin mattis dolor vel malesuada. Vivamus vehicula leo neque, vitae fermentum leo posuere et. Praesent dui est, finibus sit amet tristique quis, pharetra vel nibh. + +Duis nulla leo, accumsan eu odio eget, sagittis semper orci. Quisque ullamcorper ligula quam, commodo porttitor mauris ullamcorper eu. Cras varius sagittis felis in aliquam. Duis sodales risus ac justo vehicula, nec mattis diam lacinia. Cras eget lectus ipsum. Ut commodo, enim vitae malesuada hendrerit, ex dolor egestas lectus, sit amet hendrerit metus diam nec est. Vestibulum tortor metus, lobortis sit amet ante eget, tempor molestie lacus. In molestie et urna et semper. Mauris mollis, sem non hendrerit condimentum, sapien nisi cursus est, non suscipit quam justo non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam enim est, porta ac feugiat vitae, rutrum in lorem. Duis vehicula tortor ut posuere maximus. + +Nullam vestibulum non tellus sed commodo. Quisque mattis elit sit amet sapien sollicitudin, ut condimentum nisl congue. Aenean sagittis massa vel elit faucibus fermentum. Donec tincidunt nisi nec nisl sodales pellentesque. Mauris congue congue ligula ut suscipit. Vivamus velit tortor, tempor et gravida eget, fermentum sit amet ante. Nullam fringilla, lorem at ultrices cursus, urna neque ornare dolor, eu lacinia orci enim sed nibh. Ut a ullamcorper lectus, id mattis purus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean maximus sollicitudin posuere. Nunc at augue lacus. Aenean efficitur leo sit amet lacinia efficitur. + +Quisque venenatis quam mi, in pharetra odio vulputate eu. In vel nisl pulvinar, pulvinar ligula ut, sodales risus. Sed efficitur lectus at vestibulum tincidunt. Vestibulum eu ullamcorper elit. Fusce vestibulum magna enim, et tempor lacus posuere vitae. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer leo elit, luctus nec mattis sit amet, sollicitudin in turpis. + +Proin convallis venenatis leo, vitae tristique erat iaculis nec. Nulla facilisi. Duis porttitor, sapien et bibendum vulputate, sem libero sodales lacus, non malesuada felis erat ut libero. Nam non felis semper, finibus est a, mattis mauris. Praesent nec eros quam. Nulla hendrerit, augue consectetur eleifend ultricies, purus mi condimentum nulla, eget dapibus est nunc sed libero. Nullam elementum dui erat, vitae luctus libero sollicitudin et. Nulla odio magna, placerat in augue eu, dapibus imperdiet odio. Suspendisse imperdiet metus sit amet rhoncus dapibus. Cras at enim et urna vehicula cursus eu a mauris. Integer magna ante, eleifend ac placerat vitae, porta at nisi. Cras eget malesuada orci. Curabitur nunc est, vulputate id viverra et, dignissim sed odio. Curabitur non mattis sem. Sed bibendum, turpis vitae vehicula faucibus, nunc quam ultricies lectus, vitae viverra felis turpis at libero. + +Nullam ut egestas ligula. Proin hendrerit justo a lectus commodo venenatis. Nulla facilisi. Ut cursus lorem quis est bibendum condimentum. Aenean in tristique odio. Fusce tempor hendrerit ipsum. Curabitur mollis felis justo, quis dapibus erat auctor vel. Sed augue lectus, finibus ut urna quis, ullamcorper vestibulum dui. Etiam molestie aliquam tempor. Integer mattis sollicitudin erat, et tristique elit varius vel. Mauris a ex justo. + +Nam eros est, imperdiet non volutpat rutrum, pellentesque accumsan ligula. Duis sit amet turpis metus. Aenean in rhoncus metus, ac fringilla ex. Suspendisse condimentum egestas purus, ut pharetra odio vulputate vel. Duis tincidunt massa a placerat ultrices. Mauris ultricies nibh sit amet condimentum malesuada. Duis tincidunt id ipsum sed congue. + +Praesent eu ex augue. Nullam in porta ligula. In tincidunt accumsan arcu, in pellentesque magna tristique in. Mauris eleifend libero ac nisl viverra faucibus. Nam sollicitudin dolor in commodo hendrerit. Cras at orci metus. Ut quis laoreet orci. Vivamus ultrices leo pellentesque tempor aliquet. Maecenas ut eros vitae purus placerat vestibulum. Etiam vitae gravida dolor, quis rhoncus diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. + +Suspendisse fringilla lacinia sagittis. Integer tincidunt consectetur tristique. Morbi non orci convallis, congue sapien quis, vulputate nunc. Donec a libero vel magna elementum facilisis non quis mi. Mauris posuere tellus non ipsum ultrices elementum. Vivamus massa velit, facilisis quis placerat aliquet, aliquet nec leo. Praesent a maximus sem. Sed neque elit, feugiat vel quam non, molestie sagittis nunc. Etiam luctus nunc ac mauris scelerisque, nec rhoncus lacus convallis. Nunc pharetra, nunc ac pulvinar aliquam, ex ipsum euismod augue, nec porttitor lacus turpis vitae neque. Fusce bibendum odio id tortor faucibus pellentesque. Sed ac porta nibh, eu gravida erat. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam quis ullamcorper felis. Nulla mattis sagittis ante ac tincidunt. Integer ac felis efficitur, viverra libero et, facilisis ligula. Suspendisse a metus a massa rhoncus posuere. Phasellus suscipit ligula ut lacus facilisis, ac pellentesque ex tempor. Quisque consectetur massa mi, ac molestie libero dictum quis. Proin porttitor ligula quis erat tincidunt venenatis. Proin congue nunc sed elit gravida, nec consectetur lectus sodales. Etiam tincidunt convallis ipsum at vestibulum. Quisque maximus enim et mauris porttitor, et molestie magna tristique. Morbi vitae metus elit. Maecenas sed volutpat turpis. Aliquam vitae dolor vestibulum, elementum purus eget, dapibus nibh. Nullam egestas dui ac rutrum semper. + +Etiam hendrerit est metus, et condimentum metus aliquam ac. Pellentesque id neque id ipsum rhoncus vulputate. Aliquam erat nisl, posuere sit amet ligula ac, fermentum blandit felis. Vivamus fermentum mi risus, non lacinia purus viverra id. Aenean ac sapien consequat, finibus mauris nec, porta sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed quis consectetur ex, dignissim bibendum nulla. Phasellus ac libero at quam vehicula euismod non eu leo. Phasellus a sapien augue. + +Maecenas ligula dui, bibendum vitae mauris et, auctor laoreet felis. Duis non libero a mi semper mattis. Quisque consequat luctus massa, quis tristique eros auctor feugiat. Maecenas sodales euismod neque vitae facilisis. Nullam laoreet imperdiet velit at pellentesque. Etiam massa odio, facilisis a consequat vitae, placerat vel magna. Nunc sagittis eros nec urna fringilla, pulvinar vestibulum nibh scelerisque. Sed magna metus, cursus eu consequat et, pharetra a est. Suspendisse elementum neque a dui malesuada lacinia. Donec sed ipsum volutpat, cursus urna id, ullamcorper arcu. Maecenas laoreet nisl eget velit egestas sollicitudin. Etiam nisl turpis, mollis id dignissim vitae, tristique vehicula ante. Maecenas eget placerat est, at rutrum augue. Vivamus faucibus lacinia ullamcorper. Sed pulvinar urna sodales ante sodales, at gravida leo dictum. + +Morbi maximus, quam a lobortis bibendum, enim felis varius elit, ac vehicula elit nisl ut lacus. Quisque ut arcu augue. Praesent id turpis quam. Sed sed arcu eros. Maecenas at cursus lorem, ac eleifend nisi. Fusce mattis felis at commodo pharetra. Praesent ac commodo ipsum. Quisque finibus et eros vitae tincidunt. In hac habitasse platea dictumst. Praesent purus ipsum, luctus lobortis ornare quis, auctor eget justo. Nam vel enim sollicitudin, faucibus tortor eu, sagittis eros. Ut nec consectetur erat. Donec ultricies malesuada ligula, a hendrerit sapien volutpat in. Maecenas sed enim vitae sapien pulvinar faucibus. + +Proin semper nunc nibh, non consequat neque ullamcorper vel. Maecenas lobortis sagittis blandit. Aenean et arcu ultricies turpis malesuada malesuada. Ut quam ex, laoreet ut blandit cursus, feugiat vitae dolor. Etiam ex lacus, scelerisque vel erat vel, efficitur tincidunt magna. Morbi tristique lacinia dolor, in egestas magna ultrices vitae. Integer ultrices leo ac tempus venenatis. Praesent ac porta tortor. Vivamus ornare blandit tristique. Nulla rutrum finibus pellentesque. In non dui elementum, fermentum ipsum vel, varius magna. Pellentesque euismod tortor risus, ac pellentesque nisl faucibus eget. + +Vivamus eu enim purus. Cras ultrices rutrum egestas. Sed mollis erat nibh, at posuere nisl luctus nec. Nunc vulputate, sapien id auctor molestie, nisi diam tristique ante, non convallis tellus nibh at orci. Morbi a posuere purus, in ullamcorper ligula. Etiam elementum sit amet dui imperdiet iaculis. Proin vitae tincidunt ipsum, sit amet placerat lectus. Curabitur commodo sapien quam, et accumsan lectus fringilla non. Nullam eget accumsan enim, ac pharetra mauris. Sed quis tristique velit, vitae commodo nisi. Duis turpis dui, maximus ut risus at, finibus consequat nunc. Maecenas sed est accumsan, aliquet diam in, facilisis risus. Curabitur vehicula rutrum auctor. Nam iaculis risus pulvinar maximus viverra. Nulla vel augue et ex sagittis blandit. + +Ut sem nulla, porta ac ante ac, posuere laoreet eros. Donec sodales posuere justo a auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras mollis at orci hendrerit porta. Nullam sodales tortor tortor, non lacinia diam finibus id. Duis libero orci, suscipit ac odio et, dictum consequat ipsum. Pellentesque eu ligula sagittis, volutpat eros at, lacinia lorem. Cras euismod tellus in iaculis tempor. Quisque accumsan, magna a congue venenatis, ante ipsum aliquam lectus, at egestas enim nunc at justo. Quisque sem purus, viverra ut tristique ut, maximus id enim. Etiam quis placerat sem. In sollicitudin, lacus eu rutrum mollis, nulla eros luctus elit, vel dapibus urna purus nec urna. Phasellus egestas massa quam, ac molestie erat hendrerit a. Praesent ultrices neque ut turpis molestie auctor. Etiam molestie placerat purus, et euismod erat aliquam in. Morbi id suscipit justo. + +Proin est ante, consequat at varius a, mattis quis felis. Sed accumsan nibh sit amet ipsum elementum posuere. Vestibulum bibendum id diam sit amet gravida. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi nec dolor vel ipsum dignissim hendrerit vel non ipsum. Praesent facilisis orci quis elit auctor lobortis. Phasellus cursus risus lectus, vel lobortis libero dapibus in. Quisque tristique tempus leo a pulvinar. Pellentesque a magna tincidunt, pellentesque massa nec, laoreet orci. Morbi congue ornare dolor quis commodo. Phasellus massa nisi, tincidunt at eros dictum, hendrerit lobortis urna. Maecenas porta, magna id mattis molestie, nibh tellus lobortis sem, eget tincidunt ipsum quam eu turpis. + +Ut gravida orci risus, vel rutrum mauris vehicula id. Etiam bibendum, neque a placerat condimentum, ex orci imperdiet lectus, quis dapibus arcu lacus eget lectus. Sed consequat non mi sit amet venenatis. Fusce vestibulum erat libero, eget hendrerit risus vulputate sollicitudin. Integer sed eleifend felis. Donec commodo, sem eu mattis placerat, urna odio aliquam tellus, et laoreet justo tellus eget erat. Fusce sed suscipit tortor. Nam hendrerit nibh ac nunc auctor lacinia. Pellentesque placerat condimentum ipsum, eget semper tortor hendrerit vel. Nullam non urna eu lacus pellentesque congue ut id eros. + +Nunc finibus leo in rhoncus tristique. Sed eu ipsum nec nisl egestas faucibus eget a felis. Pellentesque vitae nisi in nulla accumsan fermentum. Sed venenatis feugiat eleifend. Fusce porttitor varius placerat. Aliquam aliquet lacus sit amet mattis mollis. Sed vel nulla quis dolor suscipit vehicula ac viverra lorem. Duis viverra ipsum eget nulla ullamcorper fermentum. Mauris tincidunt arcu quis quam fringilla ornare. Donec et iaculis tortor. Nam ultricies libero vel ipsum aliquet efficitur. Morbi eget dolor aliquam, tempus sapien eget, viverra ante. Donec varius mollis ex, sed efficitur purus euismod interdum. Quisque vel sapien non neque tincidunt semper. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Suspendisse sit amet purus leo. Fusce lectus lorem, aliquam ac nulla eget, imperdiet ornare eros. Nullam sem augue, varius in nisi non, sollicitudin pellentesque ante. Etiam eu odio condimentum, tempor libero et, egestas arcu. Cras pellentesque eleifend aliquet. Pellentesque non blandit ligula. Ut congue viverra rhoncus. Phasellus mattis mi ac eros placerat, eu feugiat tellus ultrices. Aenean mollis laoreet libero eu imperdiet. Cras sed pulvinar mi, ac vehicula ligula. Vestibulum sit amet ex massa. In a egestas eros. + +Mauris pretium ipsum risus, venenatis cursus ante imperdiet id. Praesent eu turpis nec risus feugiat maximus ullamcorper ac lectus. Integer placerat at mi vel dapibus. Vestibulum fermentum turpis sit amet turpis viverra, id aliquet diam suscipit. Nam nec ex sed ante ullamcorper pharetra quis sit amet risus. Sed ac faucibus velit, id feugiat nibh. Nullam eget ipsum ex. Vivamus tincidunt non nunc non faucibus. Quisque bibendum viverra facilisis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at nisi hendrerit quam suscipit egestas. Curabitur laoreet maximus ultricies. Duis ut tellus ac augue molestie dictum. + +Suspendisse rhoncus iaculis erat, ut ullamcorper est tristique eget. Donec auctor nec risus at gravida. Vivamus volutpat vulputate tellus, vel ultricies eros suscipit eget. Ut pulvinar id mi eu tempus. Morbi malesuada augue in dui varius, nec blandit neque vehicula. Donec ornare nec nisl in mollis. Morbi enim nisi, rhoncus nec est id, dapibus tempus urna. Ut id elit a felis vestibulum consectetur. Duis lectus quam, pharetra sit amet diam sed, posuere vestibulum erat. Fusce vitae maximus massa. Nullam id metus tempus, iaculis risus eu, lobortis urna. Quisque in congue urna. Pellentesque placerat neque in augue dapibus, non varius ex malesuada. Curabitur ut eleifend libero. Fusce vitae ligula luctus, fermentum enim vitae, ultrices erat. + +Sed viverra augue turpis, scelerisque egestas sapien mattis eu. Duis laoreet magna at ex pharetra dapibus. Praesent eget odio vel quam venenatis dictum. Nulla in sollicitudin dolor. Mauris lobortis nec eros vel rhoncus. Vestibulum porta viverra venenatis. Curabitur vel scelerisque quam, a egestas velit. Praesent volutpat tincidunt magna at laoreet. + +Cras nec lorem odio. Pellentesque quis dui urna. Praesent at tellus ac lectus scelerisque placerat nec eu risus. Vestibulum sit amet mattis ligula. Vivamus sed nisi at leo elementum accumsan at sit amet arcu. Aenean mattis tellus nec leo gravida, eget hendrerit nisl faucibus. Mauris pellentesque luctus condimentum. Maecenas pretium sapien nunc, eget commodo dolor maximus id. Mauris vestibulum accumsan massa a dictum. Phasellus interdum quam ligula, ut maximus diam blandit aliquam. Nunc vitae ex eu erat condimentum consectetur. Maecenas interdum condimentum volutpat. + +Donec et enim a libero rutrum laoreet. Praesent a condimentum sem, at tincidunt quam. In vel molestie risus. Sed urna dui, molestie vitae mollis laoreet, tempor quis lectus. Praesent vitae auctor est, et aliquet nunc. Curabitur vulputate blandit nulla, at gravida metus. Maecenas gravida dui eu iaculis tristique. Pellentesque posuere turpis nec auctor eleifend. Suspendisse bibendum diam eu tellus lobortis, et laoreet quam congue. In hac habitasse platea dictumst. Morbi dictum neque velit, eget rutrum eros ultrices sit amet. + +Phasellus fermentum risus pharetra consectetur bibendum. Donec magna tortor, lacinia vitae nibh quis, aliquet pretium lorem. Donec turpis nisi, pretium eu enim volutpat, mattis malesuada augue. Nullam vel tellus iaculis, sollicitudin elit eget, tincidunt lacus. Fusce elementum elementum felis et iaculis. Suspendisse porta eros nec neque malesuada, in malesuada ante sollicitudin. Vivamus bibendum viverra molestie. + +Integer feugiat, erat nec convallis aliquam, velit felis congue erat, molestie eleifend tellus erat in tellus. Nunc et justo purus. Donec egestas fermentum dui non feugiat. Quisque in sapien sagittis, gravida quam id, iaculis lectus. Cras sagittis rhoncus bibendum. Fusce quis metus in velit scelerisque tincidunt at non ipsum. Vivamus efficitur ante eu odio vulputate, vitae ultricies risus vehicula. Proin eget odio eu sem tincidunt feugiat vel id lorem. + +Vestibulum sit amet nulla dignissim, euismod mi in, fermentum tortor. Donec ut aliquet libero, lacinia accumsan velit. Donec et nulla quam. Nullam laoreet odio nec nunc imperdiet, a congue eros venenatis. Quisque nec tellus sit amet neque interdum posuere. Duis quis mi gravida, tincidunt diam convallis, ultricies augue. Mauris consequat risus non porttitor congue. Ut in ligula consequat, viverra nunc a, eleifend enim. Duis ligula urna, imperdiet nec facilisis et, ornare eu ex. Proin lobortis lectus a lobortis porttitor. Nulla leo metus, egestas eu libero sed, pretium faucibus felis. Vestibulum non sem tortor. Nam cursus est leo. Vivamus luctus enim odio, non interdum sem dapibus a. Aenean accumsan consequat lectus in imperdiet. + +Donec vehicula laoreet ipsum in posuere. Quisque vel quam imperdiet, sollicitudin nisi quis, suscipit velit. Morbi id sodales mauris. Curabitur tellus arcu, feugiat sed dui sit amet, sodales sagittis libero. Aenean vel suscipit metus, non placerat leo. Vestibulum quis nulla elit. Proin scelerisque non ante ut commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. + +Sed non urna dolor. Suspendisse convallis mi porta pulvinar ultrices. Suspendisse quam ipsum, hendrerit non scelerisque molestie, interdum dictum nunc. Morbi condimentum condimentum turpis eu luctus. Pellentesque sagittis sollicitudin odio, sed ultricies felis ornare sit amet. Sed ultrices ex leo, a tincidunt nisl gravida sed. Nullam ornare accumsan porta. Praesent consectetur id est nec sollicitudin. + +In hac habitasse platea dictumst. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed sed ultrices nibh. Duis accumsan suscipit eros, a dictum odio tempus sit amet. Aenean imperdiet erat ac lacus finibus, scelerisque cursus massa imperdiet. Mauris molestie risus ut lacinia posuere. Nulla et sodales purus. Maecenas orci erat, placerat in tristique quis, placerat in mi. + +Donec sollicitudin pellentesque odio in feugiat. Morbi eu dolor ut mauris congue sollicitudin. Aliquam erat volutpat. Nulla id varius dui. Curabitur finibus urna ante, consectetur interdum nisi volutpat a. Quisque quis mi tristique, consequat tellus eget, rutrum sapien. Vivamus vitae tellus vulputate, rutrum ex eu, vulputate sem. Suspendisse viverra lorem tellus, vel interdum orci gravida quis. Ut laoreet arcu at mi ullamcorper finibus. Duis porta sagittis vestibulum. Sed commodo nisl vitae urna sollicitudin, nec lacinia est sodales. Curabitur imperdiet sodales dui sed iaculis. Sed ac tellus maximus, eleifend quam sit amet, feugiat elit. Aenean viverra, dui at mattis varius, est odio vestibulum sapien, sit amet mollis libero massa nec velit. Etiam quis sodales justo. + +Ut ultricies, sem eget sodales feugiat, nunc arcu congue elit, ac tempor justo massa nec purus. Maecenas enim nunc, pharetra eget dictum sit amet, tempus pellentesque velit. Suspendisse venenatis ligula in nulla mattis, et imperdiet ex tincidunt. Etiam vulputate, tellus et ultrices suscipit, enim velit laoreet massa, vitae congue odio enim ac urna. Morbi quam lorem, iaculis ac varius sagittis, euismod quis dolor. In ut dui eu purus feugiat consectetur. Vestibulum cursus velit quis lacus pellentesque iaculis. Cras in risus sed mauris porta rutrum. Nulla facilisi. Nullam eu bibendum est, non pellentesque lectus. Sed imperdiet feugiat lorem, quis convallis ante auctor in. Maecenas justo magna, scelerisque sit amet tellus eget, varius elementum risus. Duis placerat et quam sed varius. + +Duis nec nibh vitae nibh dignissim mollis quis sed felis. Curabitur vitae quam placerat, venenatis purus ut, euismod nisl. Curabitur porttitor nibh eu pulvinar ullamcorper. Suspendisse posuere nec ipsum ac dapibus. Cras convallis consectetur urna. Phasellus a nibh in dolor lacinia posuere id eget augue. In eu pharetra lorem, vitae cursus lacus. Aliquam tincidunt nibh lectus. Aenean facilisis ultricies posuere. Sed ut placerat orci. Curabitur scelerisque gravida blandit. Maecenas placerat ligula eget suscipit fringilla. Mauris a tortor justo. Aliquam hendrerit semper mollis. Phasellus et tincidunt libero. Etiam vel quam libero. + +Quisque aliquet tempor ex. Ut ante sem, vehicula at enim vel, gravida porta elit. Etiam vitae lacus a neque lobortis consectetur. Mauris sed interdum odio. Mauris elementum ex blandit tempor cursus. Integer in enim in leo viverra elementum. Fusce consectetur metus et sem rutrum, mattis euismod diam semper. Nunc sed ipsum vel urna consequat vehicula. Donec cursus pretium lorem, vestibulum pretium felis commodo sit amet. Nam blandit felis enim, eget gravida ex faucibus a. In nec neque massa. Etiam laoreet posuere ipsum. Praesent volutpat nunc dolor, ac vulputate magna facilisis non. Aenean congue turpis vel lectus sollicitudin tristique. Sed nec consequat purus, non vehicula quam. Etiam ultricies, est ac dictum tincidunt, turpis turpis pretium massa, a vulputate libero justo at nibh. + +Aliquam erat volutpat. Cras ultrices augue ac sollicitudin lobortis. Curabitur et aliquet purus. Duis feugiat semper facilisis. Phasellus lobortis cursus velit, a sollicitudin tortor. Nam feugiat sapien non dapibus condimentum. Morbi at mi bibendum, commodo quam at, laoreet enim. Integer eu ultrices enim. Sed vestibulum eu urna ut dictum. Curabitur at mattis leo, sed cursus massa. Aliquam porttitor, felis quis fermentum porttitor, justo velit feugiat nulla, eget condimentum sem dui ut sapien. + +In fringilla elit eu orci aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut eget fringilla tellus. Curabitur fermentum, mi et condimentum suscipit, elit neque bibendum dui, et hendrerit nunc metus id ipsum. Morbi placerat mi in hendrerit congue. Ut feugiat mauris eget scelerisque viverra. Vivamus sit amet erat dictum, sagittis lectus nec, pulvinar lorem. Sed non enim ac dui sollicitudin aliquet. Quisque ut lacus dolor. Fusce hendrerit malesuada euismod. Nulla faucibus vel mauris eu mollis. Mauris est diam, fringilla ac arcu feugiat, efficitur volutpat turpis. Aliquam venenatis cursus massa sed porttitor. Ut ac finibus enim, in tincidunt sapien. + +Nunc faucibus semper turpis a lacinia. Phasellus gravida, libero vel pulvinar ornare, ex sem tincidunt lectus, sit amet convallis augue risus at tortor. Quisque sit amet ipsum id nulla posuere vestibulum. Pellentesque scelerisque mauris vel leo viverra sodales. Nulla viverra aliquam ex, ut rutrum enim fermentum venenatis. Aenean eget dapibus ex, eget faucibus metus. Vestibulum volutpat leo in diam semper, eget porta magna suscipit. Sed sit amet nulla blandit, aliquam dolor ac, gravida velit. Sed vel velit viverra, maximus est id, convallis justo. + +Curabitur nulla ante, vulputate at libero vel, ullamcorper rutrum nibh. Pellentesque porttitor eu mauris id mattis. Duis vulputate augue elit, eget interdum justo pretium vel. Maecenas eu vulputate arcu, eget posuere purus. Suspendisse viverra a velit dictum eleifend. Suspendisse vitae dapibus diam. Donec vehicula justo in ante interdum, eu luctus diam placerat. Vivamus convallis ipsum eu orci suscipit, sed fermentum enim euismod. Maecenas faucibus elit vitae ex ornare tristique. Donec vestibulum nec elit sit amet porttitor. Aenean tempor lectus eget tortor hendrerit luctus. Nullam interdum vitae lectus vel feugiat. Cras in risus non magna consectetur lobortis. Sed faucibus enim quis gravida convallis. + +Phasellus eget massa sit amet libero ultrices suscipit. Vivamus at risus sapien. Nam mollis nunc eget velit dictum maximus. Sed pellentesque, nunc ac fringilla lacinia, quam enim mattis ex, sed euismod tortor metus eu neque. Ut mattis nisl ut lectus rhoncus, sodales bibendum eros porta. Nulla porttitor enim nec diam sagittis, eget porta velit efficitur. Vestibulum ultricies eros neque. Phasellus rutrum suscipit enim, in interdum ante gravida vitae. Sed in sagittis diam, non commodo velit. + +Morbi hendrerit odio orci, nec tincidunt odio rhoncus nec. Mauris neque velit, vehicula a lorem at, suscipit tristique dui. Sed finibus, nisl in mattis convallis, turpis neque sodales lacus, eu porta enim magna non diam. Nam commodo sodales risus consectetur malesuada. In eget elementum justo. Phasellus sit amet massa imperdiet, dapibus nunc sit amet, suscipit orci. Fusce condimentum laoreet feugiat. Ut ut viverra ante. Praesent bibendum interdum commodo. Nulla mollis nisi a est ornare volutpat. Sed at ligula eu nisi dapibus tempus. Proin cursus vestibulum justo, nec efficitur justo dignissim vel. Nunc quis maximus eros. + +Cras viverra, diam a tristique mattis, libero felis vulputate tellus, a ornare felis leo a dui. Nulla ante nulla, finibus ut tellus ut, blandit pharetra nibh. Proin eleifend fermentum ex, eget auctor libero vulputate in. Nullam ultricies, mauris placerat pretium placerat, leo urna lobortis leo, vel placerat arcu libero sed mauris. Aliquam mauris ligula, ornare at urna at, eleifend gravida ligula. Vestibulum consectetur ut nulla non scelerisque. Donec ornare, sem nec elementum aliquam, urna nulla bibendum metus, eu euismod dui ligula ac est. Fusce laoreet erat eu ex lobortis, quis bibendum ligula interdum. Sed vel mi erat. Vivamus id lacus ac enim mattis tempor. Nunc ultricies pellentesque enim sed euismod. Fusce tincidunt convallis elit quis aliquam. Mauris nulla ipsum, sollicitudin quis diam ac, feugiat volutpat tellus. In nibh nibh, vulputate quis tincidunt quis, pulvinar eget magna. Pellentesque quis finibus dolor. Suspendisse viverra vitae lectus non eleifend. + +Nunc ut orci et sapien maximus semper. Nulla dignissim sem urna, ac varius lectus ultricies id. Quisque aliquet pulvinar pretium. In ultricies molestie tellus vehicula porta. Nam enim lorem, aliquam eget ex et, hendrerit volutpat quam. Maecenas diam lacus, pellentesque eget tempus ac, pharetra eu elit. Donec vel eros a sem facilisis vulputate. Nullam ac nisi vulputate, laoreet nisl ac, eleifend sem. Nullam mi massa, rhoncus sed pharetra interdum, tincidunt eget nunc. Aliquam viverra mattis posuere. Mauris et dui sed nisl sollicitudin fermentum quis ut arcu. Nam placerat eget orci at tincidunt. Curabitur vel turpis metus. Phasellus nibh nulla, fermentum scelerisque sem vel, gravida tincidunt velit. Pellentesque vel quam tempor, finibus massa pellentesque, condimentum dui. + +Donec at mattis neque. Etiam velit diam, consequat auctor mauris id, hendrerit faucibus metus. Maecenas ullamcorper eros a est sodales, ac consectetur odio scelerisque. Donec leo metus, imperdiet at pellentesque vel, feugiat id erat. Suspendisse at magna enim. Vestibulum placerat sodales lorem id sollicitudin. Aenean at euismod ligula, eget mollis diam. Phasellus pulvinar, orci nec pretium condimentum, est erat facilisis purus, quis feugiat augue elit aliquam nulla. Aenean vitae tortor id risus congue tincidunt. Sed dolor enim, mattis a ullamcorper id, volutpat ac leo. + +Proin vehicula feugiat augue, id feugiat quam sodales quis. Donec et ultricies massa, a lacinia nulla. Duis aliquam augue ornare euismod viverra. Ut lectus risus, rutrum sit amet efficitur a, luctus nec nisl. Cras volutpat ullamcorper congue. Sed vitae odio metus. Phasellus aliquet euismod varius. + +Nullam sem ex, malesuada ut magna ut, pretium mollis arcu. Nam porttitor eros cursus mi lacinia faucibus. Suspendisse aliquet eleifend iaculis. Maecenas sit amet viverra tortor. Nunc a mollis risus. Etiam tempus dolor in tortor malesuada mattis. Ut tincidunt venenatis est sit amet dignissim. Vestibulum massa enim, tristique sed scelerisque eu, fringilla ac velit. Donec efficitur quis urna sit amet malesuada. Vestibulum consequat ac ligula in dapibus. Maecenas massa massa, molestie non posuere nec, elementum ut magna. In nisi erat, mollis non venenatis eu, faucibus in justo. Morbi gravida non ex non egestas. Pellentesque finibus laoreet diam, eu commodo augue congue vitae. + +Aenean sem mi, ullamcorper dapibus lobortis vitae, interdum tincidunt tortor. Vivamus eget vulputate libero. Ut bibendum posuere lectus, vel tincidunt tortor aliquet at. Phasellus malesuada orci et bibendum accumsan. Aliquam quis libero vel leo mollis porta. Sed sagittis leo ac lacus dictum, ac malesuada elit finibus. Suspendisse pharetra luctus commodo. Vivamus ultricies a odio non interdum. Vivamus scelerisque tincidunt turpis quis tempor. Pellentesque tortor ligula, varius non nunc eu, blandit sollicitudin neque. Nunc imperdiet, diam et tristique luctus, ipsum ex condimentum nunc, sit amet aliquam justo velit sed libero. Duis vel suscipit ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed tincidunt neque vel massa ultricies, id dictum leo consequat. Curabitur lobortis ultricies tellus, eget mattis nisl aliquam sit amet. + +Proin at suscipit justo. Vivamus ut vestibulum nisl. Pellentesque enim odio, pharetra non magna sed, efficitur auctor magna. Praesent tincidunt ante quis ante hendrerit viverra. Pellentesque vel ipsum id magna vulputate efficitur. Sed nec neque accumsan, pulvinar sapien quis, euismod mauris. Donec condimentum laoreet sapien quis gravida. Quisque sed mattis purus. Vestibulum placerat vel neque maximus scelerisque. + +Vestibulum mattis quam quis efficitur elementum. Duis dictum dolor ac scelerisque commodo. Fusce sollicitudin nisi sit amet dictum placerat. Suspendisse euismod pharetra eleifend. In eros nisl, porttitor sed mauris at, consectetur aliquet mauris. Donec euismod viverra neque sed fermentum. Phasellus libero magna, accumsan ut ultricies vitae, dignissim eget metus. Donec tellus turpis, interdum eget maximus nec, hendrerit eget massa. Curabitur auctor ligula in iaculis auctor. In ultrices quam suscipit cursus finibus. Aenean id mi at dolor interdum iaculis vitae ut lorem. Nullam sed nibh fringilla, lacinia odio nec, placerat erat. In dui libero, viverra ac viverra ac, pellentesque sit amet turpis. + +Nulla in enim ex. Sed feugiat est et consectetur venenatis. Cras varius facilisis dui vel convallis. Vestibulum et elit eget tellus feugiat pellentesque. In ut ante eu purus aliquet posuere. Nulla nec ornare sem, sed luctus lorem. Nam varius iaculis odio, eget faucibus nisl ullamcorper in. Sed eget cursus felis, nec efficitur nisi. + +Vivamus commodo et sem quis pulvinar. Pellentesque libero ante, venenatis vitae ligula sit amet, ornare sollicitudin nulla. Mauris eget tellus hendrerit, pulvinar metus quis, tempor nisi. Proin magna ex, laoreet sed tortor quis, varius fermentum enim. Integer eu dolor dictum, vulputate tortor et, aliquet ligula. Vestibulum vitae justo id mauris luctus sollicitudin. Suspendisse eget auctor neque, sodales egestas lorem. Vestibulum lacinia egestas metus vitae euismod. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus ex tellus, volutpat nec pulvinar sit amet, condimentum vitae dui. Curabitur vel felis sodales, lacinia nunc iaculis, ullamcorper augue. Pellentesque consequat dolor quis eros efficitur malesuada. Nulla ut malesuada lectus. + +Morbi et tristique ante. Aliquam erat volutpat. Vivamus vitae dui nec turpis pellentesque fermentum. Quisque eget velit massa. Pellentesque tristique aliquam nisl, eu sollicitudin justo venenatis sed. Duis eleifend sem eros, ut aliquam libero porttitor id. Sed non nunc consequat, rhoncus diam eu, commodo erat. Praesent fermentum in lectus id blandit. Donec quis ipsum at justo volutpat finibus. Nulla blandit justo nulla, at mollis lacus consequat eget. Aenean sollicitudin quis eros ut ullamcorper. + +Pellentesque venenatis nulla ut mi aliquet feugiat. Cras semper vel magna nec pharetra. Integer mattis felis et sapien commodo imperdiet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis quis luctus felis. Vestibulum justo nibh, aliquam non lectus vitae, molestie placerat justo. Donec lorem nibh, gravida sit amet hendrerit ac, maximus id ipsum. Nunc ac libero sodales risus eleifend sagittis. Phasellus est massa, lobortis elementum ex sed, scelerisque consectetur neque. Nunc faucibus neque id lorem malesuada, eget convallis ex mattis. + +Sed turpis tortor, fermentum non turpis id, posuere varius nibh. Donec iaculis lorem dui. Etiam eros ante, sodales eget venenatis at, consectetur eget risus. Curabitur non aliquam ante, a pretium justo. Maecenas tempor nisl tortor, vitae dictum nisi ultrices eu. Duis eget dui ultrices, porttitor lacus sed, lobortis purus. Quisque mattis elit nec neque sagittis, sed commodo leo blandit. Mauris sodales interdum eleifend. Vestibulum condimentum consectetur augue, id luctus diam convallis et. + +Nunc suscipit risus in justo accumsan, a placerat magna tincidunt. Proin a nisl ipsum. Sed libero dui, tristique in augue quis, auctor tristique risus. Sed porttitor ex augue, eu porta augue molestie a. Duis rhoncus purus libero, eu tempus turpis condimentum at. Sed mollis nisi id lectus placerat tincidunt. Maecenas non scelerisque elit, quis rutrum orci. Donec in tellus pharetra urna ornare lobortis. Phasellus id risus at nisi varius rutrum eu ut turpis. + +Duis dictum justo quis nisl porta, eget tincidunt magna suscipit. Sed velit massa, ullamcorper eu sodales ac, pretium a massa. Duis et rutrum tortor. Nulla accumsan hendrerit sapien, cursus volutpat eros egestas eget. Donec sollicitudin at ante quis sollicitudin. Aenean blandit feugiat diam, id feugiat eros faucibus eget. Donec viverra dolor vel justo scelerisque dignissim. Nulla semper sem nunc, rhoncus semper tellus ultricies sed. Duis in ornare diam. Donec vehicula feugiat varius. Maecenas ut suscipit est. Vivamus sem sem, finibus at dolor sit amet, euismod dapibus ligula. Vestibulum fringilla odio dapibus, congue massa eget, congue sem. Donec feugiat magna eget tortor lacinia scelerisque non et ipsum. + +Suspendisse potenti. Nunc convallis sollicitudin ex eget venenatis. Sed iaculis nibh ex, vel ornare ligula congue dignissim. Quisque sollicitudin dolor ac dui vestibulum, sit amet molestie nisi aliquet. Donec at risus felis. Aenean sollicitudin metus a feugiat porta. Aenean a tortor ut dolor cursus sagittis. Vivamus consectetur porttitor nunc in facilisis. Proin sit amet mi vel lectus consectetur ultrices. + +Sed cursus lectus vitae nunc tristique, nec commodo turpis dapibus. Pellentesque luctus ex id facilisis ornare. Morbi quis placerat dolor. Donec in lectus in arcu mattis porttitor ac sit amet metus. Cras congue mauris non risus sodales, vitae feugiat ipsum bibendum. Nulla venenatis urna sed libero elementum, a cursus lorem commodo. Mauris faucibus lobortis eros nec commodo. + +Nullam suscipit ligula ullamcorper lorem commodo blandit. Nulla porta nibh quis pulvinar placerat. Vivamus eu arcu justo. Vestibulum imperdiet est ut fermentum porttitor. Pellentesque consectetur libero in sapien efficitur scelerisque. Curabitur ac erat sit amet odio aliquet dignissim. Pellentesque mi sem, rhoncus et luctus at, porttitor rutrum lectus. Vestibulum sollicitudin sollicitudin suscipit. Aenean efficitur dolor non ultrices imperdiet. Donec vel sem ex. + +Sed convallis mauris aliquam rutrum cursus. Ut tempor porttitor sodales. Etiam eu risus ac augue gravida egestas et eu dolor. Proin id magna ex. Suspendisse quis lectus quis lorem ultricies tempus. Donec porttitor velit vitae tincidunt faucibus. Aliquam vitae semper nisi. Morbi ultrices, leo non pretium dapibus, dui libero pellentesque ex, vel placerat enim ante vitae dui. Nunc varius, sem sit amet sagittis lobortis, lectus odio scelerisque mauris, ut vestibulum orci magna quis neque. Sed id congue justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris congue nisi est, malesuada mollis elit tincidunt sed. Curabitur sed ex sit amet felis tristique elementum vitae vel nibh. + +Etiam mollis pretium lobortis. Mauris augue lacus, efficitur at lacus sed, mollis tincidunt lectus. Aliquam erat volutpat. Donec at euismod elit, et mattis felis. Sed id lobortis urna. Morbi imperdiet vestibulum leo, sed maximus leo blandit eu. Aliquam semper lorem neque, nec euismod turpis mattis mollis. Quisque lobortis urna ultrices odio pretium, ac venenatis orci faucibus. Suspendisse bibendum odio ligula, sed lobortis massa pharetra nec. Donec turpis justo, iaculis at dictum ac, finibus eu libero. Maecenas quis porttitor mi, sit amet aliquet neque. + +Vivamus auctor vulputate ante, at egestas lorem. Donec eu risus in nulla mollis ultricies at et urna. Duis accumsan porta egestas. Ut vel euismod augue. Fusce convallis nulla ante, nec fringilla velit aliquet at. Nam malesuada dapibus ligula, a aliquam nibh scelerisque ac. Praesent malesuada neque et pellentesque interdum. Curabitur volutpat at turpis vitae tristique. Vivamus porttitor semper congue. Quisque suscipit lacus mi, rhoncus ultrices tortor auctor quis. Maecenas neque neque, molestie ac facilisis eget, luctus ac lorem. In ut odio ut lacus suscipit pulvinar vitae sed elit. Nulla imperdiet, sem quis euismod sagittis, dui erat luctus dolor, faucibus faucibus erat sem eget nunc. Nam accumsan placerat malesuada. Maecenas convallis finibus pulvinar. + +Cras at placerat tortor. Morbi facilisis auctor felis sit amet molestie. Donec sodales sed lorem vitae suscipit. Etiam fermentum pharetra ipsum, nec luctus orci gravida eu. Pellentesque gravida, est non condimentum tempus, mauris ligula molestie est, in congue dolor nisl vel sapien. Duis congue tempor augue, id rutrum eros porta dapibus. Etiam rutrum eget est eget vestibulum. Aenean mollis arcu vel consequat varius. Praesent at condimentum felis. Duis nec interdum nisl. Donec commodo lorem sed sapien scelerisque malesuada non eu urna. In blandit non ipsum at porta. Nam lobortis leo vitae dui auctor, non feugiat quam bibendum. Donec auctor lectus sagittis laoreet maximus. Maecenas rhoncus laoreet porttitor. Vestibulum porttitor augue ut lectus hendrerit, eget posuere mi gravida. + +Sed mattis ex in erat pulvinar, eu imperdiet magna dapibus. Etiam nisi nibh, tempus non tellus sit amet, mattis tempor odio. Quisque nec lorem feugiat, lobortis odio et, commodo nunc. Maecenas semper purus nisi, nec vehicula nibh eleifend vitae. Nulla fermentum a lectus at maximus. Phasellus finibus metus non euismod ultrices. Etiam a pulvinar ante. Quisque convallis nec metus sit amet facilisis. Praesent laoreet massa et sollicitudin laoreet. Vestibulum in mauris aliquet, convallis mi ut, elementum purus. Nulla purus nulla, sodales at hendrerit quis, tempus sed lectus. + +Nam ut laoreet neque, ut maximus nibh. Maecenas quis justo pellentesque, sollicitudin elit at, venenatis velit. Aenean nunc velit, vehicula scelerisque odio at, consectetur laoreet purus. Duis dui purus, malesuada quis ipsum sit amet, tempor interdum libero. Curabitur porta scelerisque sapien, vitae cursus diam condimentum eu. Phasellus sed orci quam. Nullam vitae dui quis purus tincidunt vestibulum. Curabitur quis nulla porta, cursus arcu non, auctor enim. Etiam sollicitudin ex id sem vehicula mollis. Morbi viverra laoreet tincidunt. Praesent ut semper dui. Nam sit amet pretium neque. Mauris vitae luctus diam, in lacinia purus. Maecenas ut placerat justo, ut porta felis. Integer eu mauris ante. + +Aenean porttitor tellus diam, tempor consequat metus efficitur id. Suspendisse ut felis at erat tempor dictum at nec sapien. Sed vestibulum interdum felis, ac mattis mauris porta in. Nunc et condimentum massa. Sed cursus dictum justo et luctus. Integer convallis enim nisl, a rutrum lectus ultricies in. Donec dapibus lacus at nulla dapibus, id sollicitudin velit hendrerit. Fusce a magna at orci mollis rutrum ac a dolor. Aliquam erat volutpat. Morbi varius porta nunc, sit amet sodales ex hendrerit commodo. Donec tincidunt tortor sapien, vitae egestas sapien vehicula eget. + +Suspendisse potenti. Donec pulvinar felis nec leo malesuada interdum. Integer posuere placerat maximus. Donec nibh ipsum, tincidunt vitae luctus vitae, bibendum at leo. Sed cursus nisl ut ex faucibus aliquet sed nec eros. Curabitur molestie posuere felis. Integer faucibus velit eget consequat iaculis. Mauris sed vulputate odio. Phasellus maximus, elit a pharetra egestas, lorem magna semper tellus, vestibulum semper diam felis at sapien. Suspendisse facilisis, nisl sit amet euismod vehicula, libero nulla vehicula dolor, quis fermentum nibh elit sit amet diam. + +Morbi lorem enim, euismod eu varius ut, scelerisque quis odio. Nam tempus vitae eros id molestie. Nunc pretium in nulla eget accumsan. Quisque mattis est ut semper aliquet. Maecenas eget diam elementum, fermentum ipsum a, euismod sapien. Duis quam ligula, cursus et velit nec, ullamcorper tincidunt magna. Donec vulputate nisl est, et ullamcorper urna tempor sit amet. + +Proin lacinia dui non turpis congue pretium. Morbi posuere metus vel purus imperdiet interdum. Morbi venenatis vel eros non ultricies. Nulla vel semper elit. Ut quis purus tincidunt, auctor justo ut, faucibus turpis. Proin quis mattis erat, at faucibus ligula. Mauris in mauris enim. Donec facilisis enim at est feugiat hendrerit. Nam vel nisi lorem. Fusce ultricies convallis diam, in feugiat tortor luctus quis. Donec tempor, leo vitae volutpat aliquam, magna elit feugiat leo, quis placerat sapien felis eget arcu. Donec ornare fermentum eleifend. Integer a est orci. + +Proin rhoncus egestas leo. Nulla ultricies porta elit quis ornare. Nunc fermentum interdum vehicula. In in ligula lorem. Donec nec arcu sit amet orci lobortis iaculis. Mauris at mollis erat, sit amet mollis tortor. Mauris laoreet justo ullamcorper porttitor auctor. Aenean sit amet aliquam lectus, id fermentum eros. Praesent urna sem, vehicula ac fermentum id, dapibus ut purus. Vestibulum vitae tempus nunc. Donec at nunc ornare metus volutpat porta at eget magna. Donec varius aliquet metus, eu lobortis risus aliquam sed. Ut dapibus fermentum velit, ac tincidunt libero faucibus at. + +In in purus auctor, feugiat massa quis, facilisis nisi. Donec dolor purus, gravida eget dolor ac, porttitor imperdiet urna. Donec faucibus placerat erat, a sagittis ante finibus ac. Sed venenatis dignissim elit, in iaculis felis posuere faucibus. Praesent sed viverra dolor. Mauris sed nulla consectetur nunc laoreet molestie in ut metus. Proin ac ex sit amet magna vulputate hendrerit ac condimentum urna. Proin ligula metus, gravida et sollicitudin facilisis, iaculis ut odio. Cras tincidunt urna et augue varius, ut facilisis urna consequat. Aenean vehicula finibus quam. Ut iaculis eu diam ac mollis. Nam mi lorem, tristique eget varius at, sodales at urna. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin vitae dictum erat, et auctor ipsum. Nullam nunc nunc, sollicitudin quis magna a, vestibulum fermentum mauris. Praesent at erat dolor. Proin laoreet tristique nulla vel efficitur. Nam sed ultrices nibh, id rutrum nunc. Curabitur eleifend a erat sit amet sollicitudin. Nullam metus quam, laoreet vitae dapibus id, placerat sed leo. Aliquam erat volutpat. Donec turpis nisl, cursus eu ex sit amet, lacinia pellentesque nisl. Sed id ipsum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec interdum scelerisque lorem eu mattis. + +Vivamus ac tristique massa, nec facilisis nisl. Nam ipsum neque, tincidunt vel urna in, cursus imperdiet enim. Nam pellentesque egestas tempus. Morbi facilisis imperdiet libero vitae fringilla. Nam lacinia ligula at sapien facilisis malesuada. Nullam accumsan pulvinar sem, et cursus libero porta sit amet. Curabitur vulputate erat elit, ut pulvinar erat maximus vel. + +Cras aliquet metus ut purus sagittis, vel venenatis ante consectetur. Pellentesque nulla lacus, viverra viverra mattis non, placerat vitae nibh. Donec enim turpis, accumsan sit amet tincidunt eu, imperdiet non metus. Morbi ipsum eros, tincidunt vel est ac, tristique porttitor nibh. Praesent ut ullamcorper mauris. Sed laoreet sit amet diam congue venenatis. Integer porta purus nec orci sagittis posuere. + +Donec vehicula mauris eget lacus mollis venenatis et sed nibh. Nam sodales ligula ipsum, scelerisque lacinia ligula sagittis in. Nam sit amet ipsum at erat malesuada congue. Aenean ut sollicitudin sapien. Etiam at tempor odio. Mauris vitae purus ut magna suscipit consequat. Vivamus quis sapien neque. Nulla vulputate sem sit amet massa pellentesque, eleifend tristique ligula egestas. Suspendisse tincidunt gravida mi, in pulvinar lectus egestas non. Aenean imperdiet ex sit amet nunc sollicitudin porta. Integer justo odio, ultricies at interdum in, rhoncus vitae sem. Sed porttitor arcu quis purus aliquet hendrerit. Praesent tempor tortor at dolor dictum pulvinar. Nulla aliquet nunc non ligula scelerisque accumsan. Donec nulla justo, congue vitae massa in, faucibus hendrerit magna. Donec non egestas purus. + +Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibus mattis neque dictum sed. Sed convallis fermentum molestie. Nulla facilisi turpis duis. diff --git a/extensions/vscode-api-tests/yarn.lock b/extensions/vscode-api-tests/yarn.lock index 7585841254a..2d8b725ff2d 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.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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== 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 702e36e66cd..6045e073d02 100644 --- a/extensions/vscode-colorize-tests/package.json +++ b/extensions/vscode-colorize-tests/package.json @@ -12,7 +12,7 @@ "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.14.8", + "@types/node": "^12.11.7", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "vscode": "1.1.5" diff --git a/extensions/vscode-colorize-tests/yarn.lock b/extensions/vscode-colorize-tests/yarn.lock index 368b81f2f96..23ac03a3948 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.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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== ajv@^5.1.0: version "5.3.0" diff --git a/extensions/vscode-test-resolver/package.json b/extensions/vscode-test-resolver/package.json index 0d93c4ea6d0..a458e14185d 100644 --- a/extensions/vscode-test-resolver/package.json +++ b/extensions/vscode-test-resolver/package.json @@ -21,7 +21,7 @@ ], "main": "./out/extension", "devDependencies": { - "@types/node": "^10.14.8", + "@types/node": "^12.11.7", "vscode": "1.1.5" }, "contributes": { @@ -90,4 +90,4 @@ } -} \ No newline at end of file +} diff --git a/extensions/vscode-test-resolver/src/extension.ts b/extensions/vscode-test-resolver/src/extension.ts index 64734212d79..d95ee976f6a 100644 --- a/extensions/vscode-test-resolver/src/extension.ts +++ b/extensions/vscode-test-resolver/src/extension.ts @@ -102,8 +102,8 @@ export function activate(context: vscode.ExtensionContext) { 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.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; @@ -210,7 +210,7 @@ export function activate(context: vscode.ExtensionContext) { resolve(_authority: string): Thenable { return vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, - title: 'Open TestResolver Remote ([details](command:remote-testresolver.showLog))', + title: 'Open TestResolver Remote ([details](command:vscode-testresolver.showLog))', cancellable: false }, (progress) => doResolve(_authority, progress)); } diff --git a/extensions/vscode-test-resolver/yarn.lock b/extensions/vscode-test-resolver/yarn.lock index 925cef2c142..4bc1451096e 100644 --- a/extensions/vscode-test-resolver/yarn.lock +++ b/extensions/vscode-test-resolver/yarn.lock @@ -2,10 +2,10 @@ # 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== +"@types/node@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== ajv@^6.5.5: version "6.10.0" diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 2595e3b4416..9c5283d2aa7 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.6.3: - version "3.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3.tgz#fea942fabb20f7e1ca7164ff626f1a9f3f70b4da" - integrity sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw== +typescript@3.7.1-rc: + version "3.7.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.1-rc.tgz#2054b872d67f8dc732e36c1df397f9327f37ada0" + integrity sha512-2rMtWppLsaPvmpXsoIAXWDBQVnJMw1ITGGSnidMuayLj9iCmMRT69ncKZw/Mk5rXfJkilApKucWQZxproALoRw== diff --git a/package.json b/package.json index f817969f87f..b9238dd5721 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", - "version": "1.39.0", - "distro": "6b38928f3a0aa32043c1d72ed00c0fe265d3b4c1", + "version": "1.41.0", + "distro": "70835b1ab9573f2b85f762d5f027f41788f7a042", "author": { "name": "Microsoft Corporation" }, @@ -18,6 +18,7 @@ "monaco-editor-test": "mocha --only-monaco-editor", "precommit": "node build/gulpfile.hygiene.js", "gulp": "gulp --max_old_space_size=8192", + "electron": "node build/lib/electron", "7z": "7z", "update-grammars": "node build/npm/update-all-grammars.js", "update-localization-extension": "node build/npm/update-localization-extension.js", @@ -25,22 +26,22 @@ "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", - "update-distro": "node build/npm/update-distro.js" + "update-distro": "node build/npm/update-distro.js", + "web": "node scripts/code-web.js" }, "dependencies": { - "@microsoft/applicationinsights-web": "^2.1.1", "applicationinsights": "1.0.8", - "chokidar": "3.1.0", + "chokidar": "3.2.3", "graceful-fs": "4.1.11", "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.1", + "https-proxy-agent": "^2.2.3", "iconv-lite": "0.5.0", "jschardet": "1.6.0", "keytar": "^4.11.0", "native-is-elevated": "0.3.0", "native-keymap": "2.0.0", "native-watchdog": "1.2.0", - "node-pty": "0.9.0-beta19", + "node-pty": "^0.10.0-beta2", "nsfw": "1.2.5", "onigasm-umd": "^2.2.2", "semver-umd": "^5.5.3", @@ -48,19 +49,22 @@ "sudo-prompt": "9.0.0", "v8-inspect-profiler": "^0.0.20", "vscode-minimist": "^1.2.1", - "vscode-proxy-agent": "0.4.0", + "vscode-proxy-agent": "^0.5.1", "vscode-ripgrep": "^1.5.7", "vscode-sqlite3": "4.0.8", - "vscode-textmate": "^4.2.2", - "xterm": "4.0.0", - "xterm-addon-search": "0.2.0", - "xterm-addon-web-links": "0.2.0", + "vscode-textmate": "^4.3.0", + "xterm": "4.2.0", + "xterm-addon-search": "0.3.0", + "xterm-addon-web-links": "0.2.1", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, "devDependencies": { "7zip": "0.0.6", + "@types/chokidar": "2.1.3", "@types/cookie": "^0.3.3", + "@types/graceful-fs": "4.1.2", + "@types/iconv-lite": "0.0.1", "@types/keytar": "^4.4.0", "@types/mocha": "2.2.39", "@types/node": "^10.12.12", @@ -97,10 +101,11 @@ "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.4", "gulp-shell": "^0.6.5", - "gulp-tsb": "4.0.4", + "gulp-tsb": "4.0.5", "gulp-tslint": "^8.1.3", "gulp-untar": "^0.0.7", "gulp-vinyl-zip": "^2.1.2", + "husky": "^0.13.1", "innosetup": "5.6.1", "is": "^3.1.0", "istanbul-lib-coverage": "^2.0.5", @@ -127,7 +132,7 @@ "source-map": "^0.4.4", "ts-loader": "^4.4.2", "tslint": "^5.16.0", - "typescript": "3.6", + "typescript": "3.7.1-rc", "typescript-formatter": "7.1.0", "underscore": "^1.8.2", "vinyl": "^2.0.0", @@ -147,10 +152,10 @@ "url": "https://github.com/Microsoft/vscode/issues" }, "optionalDependencies": { - "vscode-windows-ca-certs": "0.1.0", + "vscode-windows-ca-certs": "0.2.0", "vscode-windows-registry": "1.0.2", "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/package.json b/remote/package.json index 4c37100ec67..51966abe69d 100644 --- a/remote/package.json +++ b/remote/package.json @@ -2,28 +2,27 @@ "name": "vscode-reh", "version": "0.0.0", "dependencies": { - "@microsoft/applicationinsights-web": "^2.1.1", "applicationinsights": "1.0.8", - "chokidar": "3.1.0", + "chokidar": "3.2.3", "cookie": "^0.4.0", "graceful-fs": "4.1.11", "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.1", + "https-proxy-agent": "^2.2.3", "iconv-lite": "0.5.0", "jschardet": "1.6.0", "native-watchdog": "1.2.0", - "node-pty": "0.9.0-beta19", + "node-pty": "^0.10.0-beta2", "nsfw": "1.2.5", "onigasm-umd": "^2.2.2", "semver-umd": "^5.5.3", "spdlog": "^0.9.0", "vscode-minimist": "^1.2.1", - "vscode-proxy-agent": "0.4.0", + "vscode-proxy-agent": "^0.5.1", "vscode-ripgrep": "^1.5.7", - "vscode-textmate": "^4.2.2", - "xterm": "4.0.0", - "xterm-addon-search": "0.2.0", - "xterm-addon-web-links": "0.2.0", + "vscode-textmate": "^4.3.0", + "xterm": "4.2.0", + "xterm-addon-search": "0.3.0", + "xterm-addon-web-links": "0.2.1", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index d488944039d..46207aac124 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -2,12 +2,11 @@ "name": "vscode-web", "version": "0.0.0", "dependencies": { - "@microsoft/applicationinsights-web": "^2.1.1", "onigasm-umd": "^2.2.2", "semver-umd": "^5.5.3", - "vscode-textmate": "^4.2.2", - "xterm": "4.0.0", - "xterm-addon-search": "0.2.0", - "xterm-addon-web-links": "0.2.0" + "vscode-textmate": "^4.3.0", + "xterm": "4.2.0", + "xterm-addon-search": "0.3.0", + "xterm-addon-web-links": "0.2.1" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 7b0ddab9d16..0a1c1d9859a 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -2,69 +2,6 @@ # yarn lockfile v1 -"@microsoft/applicationinsights-analytics-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-2.1.1.tgz#6d09c1915f808026e2d45165d04802f09affed59" - integrity sha512-VKIutoFKY99CyKwxLUuj6Vnq14/QwXo9/QSQDpYnHEjo+uKn7QmLsHqWw0K9uYNfNAXt4BZimX/zDg6jZtzeXg== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-channel-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-2.1.1.tgz#e205eddd93e49d17d9e0711a612b4bfc9810888f" - integrity sha512-fYr9IAqtaEr9AmaPaL3SLQVT3t3GQzl+n74gpNKyAVakDIm0nYQ/bimjdcAhJMDf1VGNSPg/xICneyuZg7Wxlg== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-common@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-common/-/applicationinsights-common-2.1.1.tgz#27e6074584a7a3a8ca3f11f7ff2b7ff0f395bf2d" - integrity sha512-2hkS1Ia1FmAjCuYZ5JlG20/WgObqdsKtmK5YALAFGHIB4KSQ/Za1qazS+7GsG+E0F9UJivNWL1geUIcNqg5Qjg== - dependencies: - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-core-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.1.1.tgz#30fb6a519cc1c6119c419c4811ce72c260217d9e" - integrity sha512-4t4wf6SKqIcWEQDPg/uOhm+BxtHhu/AFreyEoYZmMfcxzAu33h1FtTQRtxBNbYH1+thiNZCh80yUpnT7d9Hrlw== - dependencies: - tslib "^1.9.3" - -"@microsoft/applicationinsights-dependencies-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-2.1.1.tgz#8154c3efcb24617d015d0bce7c2cc47797a8d3c4" - integrity sha512-yhb4EToBp+aI+qLo0h5NDNtoo3sDFV60uyIOK843YjzXqVotcXX/lRShlghTkJtYH09QhrdzDjViUHnD4sMFSQ== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-properties-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-2.1.1.tgz#ca34232766eb16167b5d87693e2ae5d94f2a1559" - integrity sha512-8l+/ppw6xKTam2RL4EHZ52Lcf217olw81j6kyBNKtIcGwSnLNHrFwEeF3vBWIteG2JKzlg1GhGjrkB3oxXsV2g== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-web@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web/-/applicationinsights-web-2.1.1.tgz#1a44eddda7c244b88d9eb052dab6c855682e4f05" - integrity sha512-crvhCkNsNxkFuPWmttyWNSAA96D5FxBtKS6UA9MV9f9XHevTfchf/E3AuU9JZcsXufWMQLwLrUQ9ZiA1QJ0EWA== - dependencies: - "@microsoft/applicationinsights-analytics-js" "2.1.1" - "@microsoft/applicationinsights-channel-js" "2.1.1" - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - "@microsoft/applicationinsights-dependencies-js" "2.1.1" - "@microsoft/applicationinsights-properties-js" "2.1.1" - nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" @@ -87,29 +24,24 @@ semver-umd@^5.5.3: resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.3.tgz#b64d7a2d4f5a717b369d56e31940a38e47e34d1e" integrity sha512-HOnQrn2iKnVe/xlqCTzMXQdvSz3rPbD0DmQXYuQ+oK1dpptGFfPghonQrx5JHl2O7EJwDqtQnjhE7ME23q6ngw== -tslib@^1.9.3: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - -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== +vscode-textmate@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.3.0.tgz#6e1f0f273d84148cfa1e9c7ed85bd16c974f9f61" + integrity sha512-MhEZ3hvxOVuYGsrRzW/PZLDR2VdtG2+V6TIKPvmE9JT+RAq/OtPlrFd1+ZQwBefoHEhjRNuRJ0OktcFezuxPmg== dependencies: oniguruma "^7.2.0" -xterm-addon-search@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" - integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== +xterm-addon-search@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0.tgz#fc6843bebab1873eff0c89e31f7b74bb3c4d8947" + integrity sha512-ZvRmkNBSz2dT00w0qJ3Hd5cwYoOfkVZpHou7Xxy1kO34wQglU/8Ec4DNTvU27sS9BUzEg8kUcTTru0DxhJXrTA== -xterm-addon-web-links@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" - integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== +xterm-addon-web-links@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2" + integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ== -xterm@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.0.0.tgz#eac93e08cbe69cf238cbace9185ed9e38873df1a" - integrity sha512-Xbx3vvf9FnrUcI1qU31Jww7/fc/NqpXGqgByTvjj7+g3/yPvt/RvLkP/LLMcof2kLAC3evzZGMiovs7NkjdWDw== +xterm@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0.tgz#b9980b2ae18c64ed31bcc95eace3bcecffebbbd9" + integrity sha512-oNfLqt+LmghLPOt5UcskP5Km1fXpTBHsTZ99nxJKY2N0MNFXBKIVXUcNNhHCa74JGZFMGhLT58A/UN3HcPXSfg== diff --git a/remote/yarn.lock b/remote/yarn.lock index 037aedc8cfd..c9f3ddd6ebc 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -2,87 +2,31 @@ # yarn lockfile v1 -"@microsoft/applicationinsights-analytics-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-2.1.1.tgz#6d09c1915f808026e2d45165d04802f09affed59" - integrity sha512-VKIutoFKY99CyKwxLUuj6Vnq14/QwXo9/QSQDpYnHEjo+uKn7QmLsHqWw0K9uYNfNAXt4BZimX/zDg6jZtzeXg== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-channel-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-2.1.1.tgz#e205eddd93e49d17d9e0711a612b4bfc9810888f" - integrity sha512-fYr9IAqtaEr9AmaPaL3SLQVT3t3GQzl+n74gpNKyAVakDIm0nYQ/bimjdcAhJMDf1VGNSPg/xICneyuZg7Wxlg== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-common@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-common/-/applicationinsights-common-2.1.1.tgz#27e6074584a7a3a8ca3f11f7ff2b7ff0f395bf2d" - integrity sha512-2hkS1Ia1FmAjCuYZ5JlG20/WgObqdsKtmK5YALAFGHIB4KSQ/Za1qazS+7GsG+E0F9UJivNWL1geUIcNqg5Qjg== - dependencies: - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-core-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.1.1.tgz#30fb6a519cc1c6119c419c4811ce72c260217d9e" - integrity sha512-4t4wf6SKqIcWEQDPg/uOhm+BxtHhu/AFreyEoYZmMfcxzAu33h1FtTQRtxBNbYH1+thiNZCh80yUpnT7d9Hrlw== - dependencies: - tslib "^1.9.3" - -"@microsoft/applicationinsights-dependencies-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-2.1.1.tgz#8154c3efcb24617d015d0bce7c2cc47797a8d3c4" - integrity sha512-yhb4EToBp+aI+qLo0h5NDNtoo3sDFV60uyIOK843YjzXqVotcXX/lRShlghTkJtYH09QhrdzDjViUHnD4sMFSQ== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-properties-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-2.1.1.tgz#ca34232766eb16167b5d87693e2ae5d94f2a1559" - integrity sha512-8l+/ppw6xKTam2RL4EHZ52Lcf217olw81j6kyBNKtIcGwSnLNHrFwEeF3vBWIteG2JKzlg1GhGjrkB3oxXsV2g== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-web@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web/-/applicationinsights-web-2.1.1.tgz#1a44eddda7c244b88d9eb052dab6c855682e4f05" - integrity sha512-crvhCkNsNxkFuPWmttyWNSAA96D5FxBtKS6UA9MV9f9XHevTfchf/E3AuU9JZcsXufWMQLwLrUQ9ZiA1QJ0EWA== - dependencies: - "@microsoft/applicationinsights-analytics-js" "2.1.1" - "@microsoft/applicationinsights-channel-js" "2.1.1" - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - "@microsoft/applicationinsights-dependencies-js" "2.1.1" - "@microsoft/applicationinsights-properties-js" "2.1.1" - -agent-base@4, agent-base@^4.1.0: +agent-base@4: 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: +agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +agent-base@~4.2.1: 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" -anymatch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.0.tgz#e609350e50a9313b472789b2f14ef35808ee14d6" - integrity sha512-Ozz7l4ixzI7Oxj2+cw+p0tVUt27BpaJ+1+q1TCeANWxHpvyn2+Un+YamBdfKu0uh8xLodGhoa1v7595NhKDAuA== +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -108,7 +52,7 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -braces@^3.0.2: +braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -120,20 +64,20 @@ buffer-crc32@~0.2.3: resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= -chokidar@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.1.0.tgz#ff23d077682a90eadd209bfa76eb10ed6d359668" - integrity sha512-6vZfo+7W0EOlbSo0nhVKMz4yyssrwiPbBZ8wj1lq8/+l4ZhGZ2U4Md7PspvmijXp1a26D3B7AHEBmIB7aVtaOQ== +chokidar@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.2.3.tgz#b9270a565d14f02f6bfdd537a6a2bbf5549b8c8c" + integrity sha512-GtrxGuRf6bzHQmXWRepvsGnXpkQkVU+D2/9a7dAe4a7v1NhrfZOZ2oKf76M3nOs46fFYL8D+Q8JYA4GYeJ8Cjw== dependencies: - anymatch "^3.1.0" - braces "^3.0.2" - glob-parent "^5.0.0" - is-binary-path "^2.1.0" - is-glob "^4.0.1" - normalize-path "^3.0.0" - readdirp "^3.1.1" + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.2.0" optionalDependencies: - fsevents "^2.0.6" + fsevents "~2.1.1" cookie@^0.4.0: version "0.4.0" @@ -199,15 +143,15 @@ fs-extra@^7.0.0: jsonfile "^4.0.0" universalify "^0.1.0" -fsevents@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a" - integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ== +fsevents@~2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.1.tgz#74c64e21df71721845d0c44fe54b7f56b82995a9" + integrity sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw== -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== +glob-parent@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" + integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== dependencies: is-glob "^4.0.1" @@ -221,7 +165,7 @@ graceful-fs@^4.1.6: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== -http-proxy-agent@2.1.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== @@ -229,12 +173,12 @@ http-proxy-agent@2.1.0, http-proxy-agent@^2.1.0: 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== +https-proxy-agent@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== dependencies: - agent-base "^4.1.0" + agent-base "^4.3.0" debug "^3.1.0" iconv-lite@0.5.0: @@ -249,7 +193,7 @@ ip@^1.1.5: resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= -is-binary-path@^2.1.0: +is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== @@ -261,7 +205,7 @@ is-extglob@^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: +is-glob@^4.0.1, 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== @@ -312,7 +256,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -nan@^2.0.0, nan@^2.13.2, nan@^2.14.0: +nan@^2.0.0, nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -327,14 +271,14 @@ node-addon-api@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== +node-pty@^0.10.0-beta2: + version "0.10.0-beta2" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta2.tgz#6fd0d2fbbe881869e4e19795a05c557ac958da81" + integrity sha512-IU2lzlPUZ+gKG7pHJjzBHpnuwPTxWGgT3iyQicZfdL7dwLvP5cm00QxavAXCInBmRkOMhvM4aBSKvfzqQnCDBA== dependencies: - nan "^2.13.2" + nan "^2.14.0" -normalize-path@^3.0.0: +normalize-path@^3.0.0, 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== @@ -371,10 +315,10 @@ picomatch@^2.0.4: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== -readdirp@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.2.tgz#fa85d2d14d4289920e4671dead96431add2ee78a" - integrity sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw== +readdirp@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" + integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== dependencies: picomatch "^2.0.4" @@ -393,26 +337,26 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== -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== +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== -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== +socks-proxy-agent@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" + integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== dependencies: - agent-base "~4.2.0" - socks "~2.2.0" + agent-base "~4.2.1" + socks "~2.3.2" -socks@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9" - integrity sha512-0GabKw7n9mI46vcNrVfs0o6XzWzjVa3h6GaSo2UPxtWAROXUWavfJWh1M4PR5tnE0dcnQXZIDFP4yrAysLze/w== +socks@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e" + integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ== dependencies: ip "^1.1.5" - smart-buffer "^4.0.1" + smart-buffer "4.0.2" spdlog@^0.9.0: version "0.9.0" @@ -430,11 +374,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tslib@^1.9.3: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -445,25 +384,25 @@ vscode-minimist@^1.2.1: resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.1.tgz#e63d3f4a9bf3680dcb8f9304eed612323fd6926a" integrity sha512-cmB72+qDoiCFJ1UKnGUBdGYfXzdpJ3bQM/D/+XhkVk5v7uZgLbYiCz5JcwVyk7NC7hSi5VGtQ4wihzmi12NeXw== -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== +vscode-proxy-agent@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.1.tgz#7fd15e157c02176a0dca9f87840ad0991a62ca57" + integrity sha512-Nnkc7gBk9iAbbZURYZm3p/wvDvRVwDvdzEvDqF1Jh40p6przwQU/JTlV1XLrmd4cCwh6TOAWD81Z3cq+K7Xdmw== dependencies: - debug "3.1.0" - http-proxy-agent "2.1.0" - https-proxy-agent "2.2.1" - socks-proxy-agent "4.0.1" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.3" + socks-proxy-agent "^4.0.1" vscode-ripgrep@^1.5.7: version "1.5.7" resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce" integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ== -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== +vscode-textmate@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.3.0.tgz#6e1f0f273d84148cfa1e9c7ed85bd16c974f9f61" + integrity sha512-MhEZ3hvxOVuYGsrRzW/PZLDR2VdtG2+V6TIKPvmE9JT+RAq/OtPlrFd1+ZQwBefoHEhjRNuRJ0OktcFezuxPmg== dependencies: oniguruma "^7.2.0" @@ -479,20 +418,20 @@ vscode-windows-registry@1.0.2: resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a" integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA== -xterm-addon-search@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" - integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== +xterm-addon-search@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0.tgz#fc6843bebab1873eff0c89e31f7b74bb3c4d8947" + integrity sha512-ZvRmkNBSz2dT00w0qJ3Hd5cwYoOfkVZpHou7Xxy1kO34wQglU/8Ec4DNTvU27sS9BUzEg8kUcTTru0DxhJXrTA== -xterm-addon-web-links@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" - integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== +xterm-addon-web-links@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2" + integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ== -xterm@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.0.0.tgz#eac93e08cbe69cf238cbace9185ed9e38873df1a" - integrity sha512-Xbx3vvf9FnrUcI1qU31Jww7/fc/NqpXGqgByTvjj7+g3/yPvt/RvLkP/LLMcof2kLAC3evzZGMiovs7NkjdWDw== +xterm@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0.tgz#b9980b2ae18c64ed31bcc95eace3bcecffebbbd9" + integrity sha512-oNfLqt+LmghLPOt5UcskP5Km1fXpTBHsTZ99nxJKY2N0MNFXBKIVXUcNNhHCa74JGZFMGhLT58A/UN3HcPXSfg== yauzl@^2.9.2: version "2.10.0" diff --git a/resources/linux/bin/code.sh b/resources/linux/bin/code.sh index 564f13ef95c..516c05e4ee0 100755 --- a/resources/linux/bin/code.sh +++ b/resources/linux/bin/code.sh @@ -30,7 +30,7 @@ if [ ! -L $0 ]; then # if path is not a symlink, find relatively VSCODE_PATH="$(dirname $0)/.." else - if which readlink >/dev/null; then + if command -v readlink >/dev/null; then # if readlink exists, follow the symlink and find relatively VSCODE_PATH="$(dirname $(readlink -f $0))/.." else diff --git a/resources/win32/inno-big-125.bmp b/resources/win32/inno-big-125.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-big-150.bmp b/resources/win32/inno-big-150.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-big-175.bmp b/resources/win32/inno-big-175.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-big-200.bmp b/resources/win32/inno-big-200.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-big-225.bmp b/resources/win32/inno-big-225.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-small-100.bmp b/resources/win32/inno-small-100.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-small-125.bmp b/resources/win32/inno-small-125.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-small-150.bmp b/resources/win32/inno-small-150.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-small-175.bmp b/resources/win32/inno-small-175.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-small-200.bmp b/resources/win32/inno-small-200.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-small-225.bmp b/resources/win32/inno-small-225.bmp old mode 100755 new mode 100644 diff --git a/resources/win32/inno-small-250.bmp b/resources/win32/inno-small-250.bmp old mode 100755 new mode 100644 diff --git a/scripts/code-cli.bat b/scripts/code-cli.bat index 6fbf5edd626..56c37567201 100644 --- a/scripts/code-cli.bat +++ b/scripts/code-cli.bat @@ -24,7 +24,7 @@ if "%1"=="--builtin" goto builtin node build\lib\builtInExtensions.js :: Build -if not exist out node .\node_modules\gulp\bin\gulp.js compile +if not exist out yarn compile :: Configuration set ELECTRON_RUN_AS_NODE=1 diff --git a/scripts/code-cli.sh b/scripts/code-cli.sh index a7d61d5a897..e4fa552e642 100755 --- a/scripts/code-cli.sh +++ b/scripts/code-cli.sh @@ -22,8 +22,7 @@ function code() { test -d node_modules || yarn # Get electron - node build/lib/electron.js || ./node_modules/.bin/gulp electron - + yarn electron # Manage built-in extensions if [[ "$1" == "--builtin" ]]; then @@ -35,7 +34,7 @@ function code() { node build/lib/builtInExtensions.js # Build - test -d out || ./node_modules/.bin/gulp compile + test -d out || yarn compile ELECTRON_RUN_AS_NODE=1 \ NODE_ENV=development \ diff --git a/scripts/code-web.js b/scripts/code-web.js new file mode 100755 index 00000000000..33e586d958f --- /dev/null +++ b/scripts/code-web.js @@ -0,0 +1,225 @@ +#!/usr/bin/env node + +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// @ts-check + +const http = require('http'); +const url = require('url'); +const fs = require('fs'); +const path = require('path'); +const util = require('util'); +const opn = require('opn'); +const minimist = require('vscode-minimist'); + +const APP_ROOT = path.dirname(__dirname); +const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench', 'workbench-dev.html'); +const PORT = 8080; + +const args = minimist(process.argv, { + string: [ + 'no-launch' + ] +}); + +const server = http.createServer((req, res) => { + const parsedUrl = url.parse(req.url, true); + const pathname = parsedUrl.pathname; + + try { + if (pathname === '/favicon.ico') { + // favicon + return serveFile(req, res, path.join(APP_ROOT, 'resources', 'win32', 'code.ico')); + } + if (/^\/static\//.test(pathname)) { + // static requests + return handleStatic(req, res, parsedUrl); + } + if (/^\/static-extension\//.test(pathname)) { + // static extension requests + return handleStaticExtension(req, res, parsedUrl); + } + if (pathname === '/') { + // main web + return handleRoot(req, res); + } + + return serveError(req, res, 404, 'Not found.'); + } catch (error) { + console.error(error.toString()); + + return serveError(req, res, 500, 'Internal Server Error.'); + } +}); + +server.listen(PORT, () => { + console.log(`Web UI available at http://localhost:${PORT}`); +}); + +server.on('error', err => { + console.error(`Error occurred in server:`); + console.error(err); +}); + +/** + * @param {import('http').IncomingMessage} req + * @param {import('http').ServerResponse} res + * @param {import('url').UrlWithParsedQuery} parsedUrl + */ +function handleStatic(req, res, parsedUrl) { + + // Strip `/static/` from the path + const relativeFilePath = path.normalize(decodeURIComponent(parsedUrl.pathname.substr('/static/'.length))); + + return serveFile(req, res, path.join(APP_ROOT, relativeFilePath)); +} + +/** + * @param {import('http').IncomingMessage} req + * @param {import('http').ServerResponse} res + * @param {import('url').UrlWithParsedQuery} parsedUrl + */ +function handleStaticExtension(req, res, parsedUrl) { + + // Strip `/static-extension/` from the path + const relativeFilePath = path.normalize(decodeURIComponent(parsedUrl.pathname.substr('/static-extension/'.length))); + + const filePath = path.join(APP_ROOT, 'extensions', relativeFilePath); + + return serveFile(req, res, filePath); +} + +/** + * @param {import('http').IncomingMessage} req + * @param {import('http').ServerResponse} res + */ +async function handleRoot(req, res) { + const extensionFolders = await util.promisify(fs.readdir)(path.join(APP_ROOT, 'extensions')); + const mapExtensionFolderToExtensionPackageJSON = new Map(); + + await Promise.all(extensionFolders.map(async extensionFolder => { + try { + const packageJSON = JSON.parse((await util.promisify(fs.readFile)(path.join(APP_ROOT, 'extensions', extensionFolder, 'package.json'))).toString()); + if (packageJSON.main && packageJSON.name !== 'vscode-api-tests') { + return; // unsupported + } + + if (packageJSON.name === 'scss') { + return; // seems to fail to JSON.parse()?! + } + + packageJSON.extensionKind = 'web'; // enable for Web + + mapExtensionFolderToExtensionPackageJSON.set(extensionFolder, packageJSON); + } catch (error) { + return null; + } + })); + + const staticExtensions = []; + + // Built in extensions + mapExtensionFolderToExtensionPackageJSON.forEach((packageJSON, extensionFolder) => { + staticExtensions.push({ + packageJSON, + extensionLocation: { scheme: 'http', authority: `localhost:${PORT}`, path: `/static-extension/${extensionFolder}` } + }); + }); + + const data = (await util.promisify(fs.readFile)(WEB_MAIN)).toString() + .replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({ + staticExtensions, + folderUri: { scheme: 'memfs', path: `/` } + }))) + .replace('{{WEBVIEW_ENDPOINT}}', '') + .replace('{{REMOTE_USER_DATA_URI}}', ''); + + res.writeHead(200, { 'Content-Type': 'text/html' }); + return res.end(data); +} + +/** + * @param {string} value + */ +function escapeAttribute(value) { + return value.replace(/"/g, '"'); +} + +/** + * @param {import('http').IncomingMessage} req + * @param {import('http').ServerResponse} res + * @param {string} errorMessage + */ +function serveError(req, res, errorCode, errorMessage) { + res.writeHead(errorCode, { 'Content-Type': 'text/plain' }); + res.end(errorMessage); +} + +const textMimeType = { + '.html': 'text/html', + '.js': 'text/javascript', + '.json': 'application/json', + '.css': 'text/css', + '.svg': 'image/svg+xml', +}; + +const mapExtToMediaMimes = { + '.bmp': 'image/bmp', + '.gif': 'image/gif', + '.ico': 'image/x-icon', + '.jpe': 'image/jpg', + '.jpeg': 'image/jpg', + '.jpg': 'image/jpg', + '.png': 'image/png', + '.tga': 'image/x-tga', + '.tif': 'image/tiff', + '.tiff': 'image/tiff', + '.woff': 'application/font-woff' +}; + +/** + * @param {string} forPath + */ +function getMediaMime(forPath) { + const ext = path.extname(forPath); + + return mapExtToMediaMimes[ext.toLowerCase()]; +} + +/** + * @param {import('http').IncomingMessage} req + * @param {import('http').ServerResponse} res + * @param {string} filePath + */ +async function serveFile(req, res, filePath, responseHeaders = Object.create(null)) { + try { + const stat = await util.promisify(fs.stat)(filePath); + + // Check if file modified since + const etag = `W/"${[stat.ino, stat.size, stat.mtime.getTime()].join('-')}"`; // weak validator (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) + if (req.headers['if-none-match'] === etag) { + res.writeHead(304); + return res.end(); + } + + // Headers + responseHeaders['Content-Type'] = textMimeType[path.extname(filePath)] || getMediaMime(filePath) || 'text/plain'; + responseHeaders['Etag'] = etag; + + res.writeHead(200, responseHeaders); + + // Data + fs.createReadStream(filePath).pipe(res); + } catch (error) { + console.error(error.toString()); + res.writeHead(404, { 'Content-Type': 'text/plain' }); + return res.end('Not found'); + } +} + +if (args.launch !== false) { + opn(`http://localhost:${PORT}`); +} diff --git a/scripts/code.bat b/scripts/code.bat index f4689608e4a..0eb0eb0b342 100644 --- a/scripts/code.bat +++ b/scripts/code.bat @@ -24,7 +24,7 @@ if "%1"=="--builtin" goto builtin node build\lib\builtInExtensions.js :: Build -if not exist out node .\node_modules\gulp\bin\gulp.js compile +if not exist out yarn compile :: Configuration set NODE_ENV=development diff --git a/scripts/code.sh b/scripts/code.sh index e82babd818a..4ba1a00b9f7 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -27,7 +27,7 @@ function code() { test -d node_modules || yarn # Get electron - node build/lib/electron.js || ./node_modules/.bin/gulp electron + yarn electron # Manage built-in extensions if [[ "$1" == "--builtin" ]]; then @@ -39,7 +39,7 @@ function code() { node build/lib/builtInExtensions.js # Build - test -d out || ./node_modules/.bin/gulp compile + test -d out || yarn compile # Configuration export NODE_ENV=development diff --git a/scripts/node-electron.sh b/scripts/node-electron.sh index 7216e92a6c6..1c3d894a1d1 100755 --- a/scripts/node-electron.sh +++ b/scripts/node-electron.sh @@ -18,7 +18,7 @@ else fi # Get electron -node build/lib/electron.js || ./node_modules/.bin/gulp electron +yarn electron popd diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index d557a24edaa..0d7b9ee4b37 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -29,16 +29,18 @@ call .\scripts\test.bat --runGlob **\*.integrationTest.js %* if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in the extension host -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% + +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% + if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% . +call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% . if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in commonJS (HTML, CSS, JSON language server tests...) diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 2c3a571ffc7..21652b632cf 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -37,13 +37,14 @@ fi ./scripts/test.sh --runGlob **/*.integrationTest.js "$@" # Tests in the extension host -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR + mkdir -p $ROOT/extensions/emmet/test-fixtures -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR rm -rf $ROOT/extensions/emmet/test-fixtures # Remote Integration Tests diff --git a/scripts/test.sh b/scripts/test.sh index 630af4e53e5..28298993295 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -22,7 +22,7 @@ fi test -d node_modules || yarn # Get electron -node build/lib/electron.js || ./node_modules/.bin/gulp electron +yarn electron # Unit Tests if [[ "$OSTYPE" == "darwin"* ]]; then diff --git a/src/bootstrap-fork.js b/src/bootstrap-fork.js index c49274c99a7..e0c6cf34c56 100644 --- a/src/bootstrap-fork.js +++ b/src/bootstrap-fork.js @@ -20,11 +20,6 @@ if (!!process.send && process.env.PIPE_LOGGING === 'true') { pipeLoggingToParent(); } -// Disable IO if configured -if (!process.env['VSCODE_ALLOW_IO']) { - disableSTDIO(); -} - // Handle Exceptions if (!process.env['VSCODE_HANDLES_UNCAUGHT_ERRORS']) { handleExceptions(); @@ -141,20 +136,6 @@ function pipeLoggingToParent() { console.error = function () { safeSend({ type: '__$console', severity: 'error', arguments: safeToArray(arguments) }); }; } -function disableSTDIO() { - - // const stdout, stderr and stdin be no-op streams. This prevents an issue where we would get an EBADF - // error when we are inside a forked process and this process tries to access those channels. - const stream = require('stream'); - const writable = new stream.Writable({ - write: function () { /* No OP */ } - }); - - process['__defineGetter__']('stdout', function () { return writable; }); - process['__defineGetter__']('stderr', function () { return writable; }); - process['__defineGetter__']('stdin', function () { return writable; }); -} - function handleExceptions() { // Handle uncaught exceptions @@ -198,4 +179,4 @@ function configureCrashReporter() { } } -//#endregion \ No newline at end of file +//#endregion diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 72403b1e413..0336f9eb700 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -21,7 +21,7 @@ exports.assign = function assign(destination, source) { * * @param {string[]} modulePaths * @param {(result, configuration: object) => any} resultCallback - * @param {{ forceEnableDeveloperKeybindings?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean, canModifyDOM?: (config: object) => void, beforeLoaderConfig?: (config: object, loaderConfig: object) => void, beforeRequire?: () => void }=} options + * @param {{ forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean, canModifyDOM?: (config: object) => void, beforeLoaderConfig?: (config: object, loaderConfig: object) => void, beforeRequire?: () => void }=} options */ exports.load = function (modulePaths, resultCallback, options) { @@ -58,7 +58,7 @@ exports.load = function (modulePaths, resultCallback, options) { const enableDeveloperTools = (process.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath) && !configuration.extensionTestsPath; let developerToolsUnbind; if (enableDeveloperTools || (options && options.forceEnableDeveloperKeybindings)) { - developerToolsUnbind = registerDeveloperKeybindings(); + developerToolsUnbind = registerDeveloperKeybindings(options && options.disallowReloadKeybinding); } // Correctly inherit the parent's environment @@ -142,7 +142,7 @@ exports.load = function (modulePaths, resultCallback, options) { } catch (error) { onUnexpectedError(error, enableDeveloperTools); } - }); + }, onUnexpectedError); }; /** @@ -159,9 +159,10 @@ function parseURLQueryArgs() { } /** + * @param {boolean} disallowReloadKeybinding * @returns {() => void} */ -function registerDeveloperKeybindings() { +function registerDeveloperKeybindings(disallowReloadKeybinding) { // @ts-ignore const ipc = require('electron').ipcRenderer; @@ -185,7 +186,7 @@ function registerDeveloperKeybindings() { const key = extractKey(e); if (key === TOGGLE_DEV_TOOLS_KB || key === TOGGLE_DEV_TOOLS_KB_ALT) { ipc.send('vscode:toggleDevTools'); - } else if (key === RELOAD_KB) { + } else if (key === RELOAD_KB && !disallowReloadKeybinding) { ipc.send('vscode:reloadWindow'); } }; diff --git a/src/bootstrap.js b/src/bootstrap.js index bd1aa29cebe..c3815b745cc 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -39,10 +39,12 @@ exports.injectNodeModuleLookupPath = function (injectPath) { // @ts-ignore Module._resolveLookupPaths = function (moduleName, parent) { const paths = originalResolveLookupPaths(moduleName, parent); - for (let i = 0, len = paths.length; i < len; i++) { - if (paths[i] === nodeModulesPath) { - paths.splice(i, 0, injectPath); - break; + if (Array.isArray(paths)) { + for (let i = 0, len = paths.length; i < len; i++) { + if (paths[i] === nodeModulesPath) { + paths.splice(i, 0, injectPath); + break; + } } } @@ -74,10 +76,12 @@ exports.enableASARSupport = function (nodeModulesPath) { // @ts-ignore Module._resolveLookupPaths = function (request, parent) { const paths = originalResolveLookupPaths(request, parent); - for (let i = 0, len = paths.length; i < len; i++) { - if (paths[i] === NODE_MODULES_PATH) { - paths.splice(i, 0, NODE_MODULES_ASAR_PATH); - break; + if (Array.isArray(paths)) { + for (let i = 0, len = paths.length; i < len; i++) { + if (paths[i] === NODE_MODULES_PATH) { + paths.splice(i, 0, NODE_MODULES_ASAR_PATH); + break; + } } } @@ -153,30 +157,10 @@ exports.writeFile = function (file, content) { * @param {string} dir * @returns {Promise} */ -function mkdir(dir) { +exports.mkdirp = function mkdirp(dir) { const fs = require('fs'); - return new Promise((c, e) => fs.mkdir(dir, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); -} - -/** - * @param {string} dir - * @returns {Promise} - */ -exports.mkdirp = function mkdirp(dir) { - const path = require('path'); - - return mkdir(dir).then(null, err => { - if (err && err.code === 'ENOENT') { - const parent = path.dirname(dir); - - if (parent !== dir) { // if not arrived at root - return mkdirp(parent).then(() => mkdir(dir)); - } - } - - throw err; - }); + return new Promise((c, e) => fs.mkdir(dir, { recursive: true }, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); }; //#endregion diff --git a/src/main.js b/src/main.js index ea852b1a406..4c5990f1056 100644 --- a/src/main.js +++ b/src/main.js @@ -12,6 +12,8 @@ const lp = require('./vs/base/node/languagePacks'); perf.mark('main:started'); const path = require('path'); +const fs = require('fs'); +const os = require('os'); const bootstrap = require('./bootstrap'); const paths = require('./paths'); // @ts-ignore @@ -25,11 +27,19 @@ const portable = bootstrap.configurePortable(); // Enable ASAR support bootstrap.enableASARSupport(); -// Set userData path before app 'ready' event and call to process.chdir +// Set userData path before app 'ready' event const args = parseCLIArgs(); const userDataPath = getUserDataPath(args); app.setPath('userData', userDataPath); +// Set logs path before app 'ready' event if running portable +// to ensure that no 'logs' folder is created on disk at a +// location outside of the portable directory +// (https://github.com/microsoft/vscode/issues/56651) +if (portable.isPortable) { + app.setAppLogsPath(path.join(userDataPath, 'logs')); +} + // Update cwd based on environment and platform setCurrentWorkingDirectory(); @@ -41,26 +51,25 @@ protocol.registerSchemesAsPrivileged([ // Global app listeners registerListeners(); -/** - * Support user defined locale - * - * @type {Promise} - */ -let nlsConfiguration = undefined; -const userDefinedLocale = getUserDefinedLocale(); -const metaDataFile = path.join(__dirname, 'nls.metadata.json'); - -userDefinedLocale.then(locale => { - if (locale && !nlsConfiguration) { - nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); - } -}); - // Cached data const nodeCachedDataDir = getNodeCachedDir(); -// Configure command line switches -configureCommandlineSwitches(args); +// Configure static command line arguments +const argvConfig = configureCommandlineSwitchesSync(args); + +/** + * Support user defined locale: load it early before app('ready') + * to have more things running in parallel. + * + * @type {Promise} nlsConfig | undefined + */ +let nlsConfigurationPromise = undefined; + +const metaDataFile = path.join(__dirname, 'nls.metadata.json'); +const locale = getUserDefinedLocale(argvConfig); +if (locale) { + nlsConfigurationPromise = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); +} // Load our code once ready app.once('ready', function () { @@ -79,62 +88,35 @@ app.once('ready', function () { } }); -function onReady() { +/** + * Main startup routine + * + * @param {string | undefined} cachedDataDir + * @param {import('./vs/base/node/languagePacks').NLSConfiguration} nlsConfig + */ +function startup(cachedDataDir, nlsConfig) { + nlsConfig._languagePackSupport = true; + + process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig); + process.env['VSCODE_NODE_CACHED_DATA_DIR'] = cachedDataDir || ''; + + // Load main in AMD + perf.mark('willLoadMainBundle'); + require('./bootstrap-amd').load('vs/code/electron-main/main', () => { + perf.mark('didLoadMainBundle'); + }); +} + +async function onReady() { perf.mark('main:appReady'); - Promise.all([nodeCachedDataDir.ensureExists(), userDefinedLocale]).then(([cachedDataDir, locale]) => { - if (locale && !nlsConfiguration) { - nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); - } + try { + const [cachedDataDir, nlsConfig] = await Promise.all([nodeCachedDataDir.ensureExists(), resolveNlsConfiguration()]); - if (!nlsConfiguration) { - nlsConfiguration = Promise.resolve(undefined); - } - - // First, we need to test a user defined locale. If it fails we try the app locale. - // If that fails we fall back to English. - nlsConfiguration.then(nlsConfig => { - - const startup = nlsConfig => { - nlsConfig._languagePackSupport = true; - process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig); - process.env['VSCODE_NODE_CACHED_DATA_DIR'] = cachedDataDir || ''; - - // Load main in AMD - perf.mark('willLoadMainBundle'); - require('./bootstrap-amd').load('vs/code/electron-main/main', () => { - perf.mark('didLoadMainBundle'); - }); - }; - - // We received a valid nlsConfig from a user defined locale - if (nlsConfig) { - startup(nlsConfig); - } - - // Try to use the app locale. Please note that the app locale is only - // valid after we have received the app ready event. This is why the - // code is here. - else { - let appLocale = app.getLocale(); - if (!appLocale) { - startup({ locale: 'en', availableLanguages: {} }); - } else { - - // See above the comment about the loader and case sensitiviness - appLocale = appLocale.toLowerCase(); - - lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale).then(nlsConfig => { - if (!nlsConfig) { - nlsConfig = { locale: appLocale, availableLanguages: {} }; - } - - startup(nlsConfig); - }); - } - } - }); - }, console.error); + startup(cachedDataDir, nlsConfig); + } catch (error) { + console.error(error); + } } /** @@ -142,16 +124,142 @@ function onReady() { * * @param {ParsedArgs} cliArgs */ -function configureCommandlineSwitches(cliArgs) { +function configureCommandlineSwitchesSync(cliArgs) { + const SUPPORTED_ELECTRON_SWITCHES = [ - // Force pre-Chrome-60 color profile handling (for https://github.com/Microsoft/vscode/issues/51791) - app.commandLine.appendSwitch('disable-color-correct-rendering'); + // alias from us for --disable-gpu + 'disable-hardware-acceleration', + + // provided by Electron + 'disable-color-correct-rendering' + ]; + + // Read argv config + const argvConfig = readArgvConfigSync(); + + // Append each flag to Electron + Object.keys(argvConfig).forEach(argvKey => { + if (SUPPORTED_ELECTRON_SWITCHES.indexOf(argvKey) === -1) { + return; // unsupported argv key + } + + const argvValue = argvConfig[argvKey]; + if (argvValue === true || argvValue === 'true') { + if (argvKey === 'disable-hardware-acceleration') { + app.disableHardwareAcceleration(); // needs to be called explicitly + } else { + app.commandLine.appendArgument(argvKey); + } + } else { + app.commandLine.appendSwitch(argvKey, argvValue); + } + }); // Support JS Flags const jsFlags = getJSFlags(cliArgs); if (jsFlags) { - app.commandLine.appendSwitch('--js-flags', jsFlags); + app.commandLine.appendSwitch('js-flags', jsFlags); } + + return argvConfig; +} + +function readArgvConfigSync() { + + // Read or create the argv.json config file sync before app('ready') + const argvConfigPath = getArgvConfigPath(); + let argvConfig; + try { + argvConfig = JSON.parse(stripComments(fs.readFileSync(argvConfigPath).toString())); + } catch (error) { + if (error && error.code === 'ENOENT') { + createDefaultArgvConfigSync(argvConfigPath); + } else { + console.warn(`Unable to read argv.json configuration file in ${argvConfigPath}, falling back to defaults (${error})`); + } + } + + // Fallback to default + if (!argvConfig) { + argvConfig = { + 'disable-color-correct-rendering': true // Force pre-Chrome-60 color profile handling (for https://github.com/Microsoft/vscode/issues/51791) + }; + } + + return argvConfig; +} + +/** + * @param {string} argvConfigPath + */ +function createDefaultArgvConfigSync(argvConfigPath) { + try { + + // Ensure argv config parent exists + const argvConfigPathDirname = path.dirname(argvConfigPath); + if (!fs.existsSync(argvConfigPathDirname)) { + fs.mkdirSync(argvConfigPathDirname); + } + + // Migrate over legacy locale + const localeConfigPath = path.join(userDataPath, 'User', 'locale.json'); + const legacyLocale = getLegacyUserDefinedLocaleSync(localeConfigPath); + if (legacyLocale) { + try { + fs.unlinkSync(localeConfigPath); + } catch (error) { + //ignore + } + } + + // Default argv content + const defaultArgvConfigContent = [ + '// This configuration file allows you to pass permanent command line arguments to VS Code.', + '// Only a subset of arguments is currently supported to reduce the likelyhood of breaking', + '// the installation.', + '//', + '// PLEASE DO NOT CHANGE WITHOUT UNDERSTANDING THE IMPACT', + '//', + '// NOTE: Changing this file requires a restart of VS Code.', + '{', + ' // Use software rendering instead of hardware accelerated rendering.', + ' // This can help in cases where you see rendering issues in VS Code.', + ' // "disable-hardware-acceleration": true,', + '', + ' // Enabled by default by VS Code to resolve color issues in the renderer', + ' // See https://github.com/Microsoft/vscode/issues/51791 for details', + ' "disable-color-correct-rendering": true' + ]; + + if (legacyLocale) { + defaultArgvConfigContent[defaultArgvConfigContent.length - 1] = `${defaultArgvConfigContent[defaultArgvConfigContent.length - 1]},`; // append trailing "," + + defaultArgvConfigContent.push(''); + defaultArgvConfigContent.push(' // Display language of VS Code'); + defaultArgvConfigContent.push(` "locale": "${legacyLocale}"`); + } + + defaultArgvConfigContent.push('}'); + + // Create initial argv.json with default content + fs.writeFileSync(argvConfigPath, defaultArgvConfigContent.join('\n')); + } catch (error) { + console.error(`Unable to create argv.json configuration file in ${argvConfigPath}, falling back to defaults (${error})`); + } +} + +function getArgvConfigPath() { + const vscodePortable = process.env['VSCODE_PORTABLE']; + if (vscodePortable) { + return path.join(vscodePortable, 'argv.json'); + } + + let dataFolderName = product.dataFolderName; + if (process.env['VSCODE_DEV']) { + dataFolderName = `${dataFolderName}-dev`; + } + + return path.join(os.homedir(), dataFolderName, 'argv.json'); } /** @@ -254,7 +362,7 @@ function registerListeners() { } /** - * @returns {{ ensureExists: () => Promise }} + * @returns {{ ensureExists: () => Promise }} */ function getNodeCachedDir() { return new class { @@ -263,8 +371,14 @@ function getNodeCachedDir() { this.value = this._compute(); } - ensureExists() { - return bootstrap.mkdirp(this.value).then(() => this.value, () => { /*ignore*/ }); + async ensureExists() { + try { + await bootstrap.mkdirp(this.value); + + return this.value; + } catch (error) { + // ignore + } } _compute() { @@ -289,6 +403,41 @@ function getNodeCachedDir() { } //#region NLS Support +/** + * Resolve the NLS configuration + * + * @return {Promise} + */ +async function resolveNlsConfiguration() { + + // First, we need to test a user defined locale. If it fails we try the app locale. + // If that fails we fall back to English. + let nlsConfiguration = nlsConfigurationPromise ? await nlsConfigurationPromise : undefined; + if (!nlsConfiguration) { + + // Try to use the app locale. Please note that the app locale is only + // valid after we have received the app ready event. This is why the + // code is here. + let appLocale = app.getLocale(); + if (!appLocale) { + nlsConfiguration = { locale: 'en', availableLanguages: {} }; + } else { + + // See above the comment about the loader and case sensitiviness + appLocale = appLocale.toLowerCase(); + + nlsConfiguration = await lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale); + if (!nlsConfiguration) { + nlsConfiguration = { locale: appLocale, availableLanguages: {} }; + } + } + } else { + // We received a valid nlsConfig from a user defined locale + } + + return nlsConfiguration; +} + /** * @param {string} content * @returns {string} @@ -317,30 +466,36 @@ function stripComments(content) { }); } -// Language tags are case insensitive however an amd loader is case sensitive -// To make this work on case preserving & insensitive FS we do the following: -// the language bundles have lower case language tags and we always lower case -// the locale we receive from the user or OS. /** - * @returns {Promise} + * Language tags are case insensitive however an amd loader is case sensitive + * To make this work on case preserving & insensitive FS we do the following: + * the language bundles have lower case language tags and we always lower case + * the locale we receive from the user or OS. + * + * @param {{ locale: string | undefined; }} argvConfig + * @returns {string | undefined} */ -function getUserDefinedLocale() { +function getUserDefinedLocale(argvConfig) { const locale = args['locale']; if (locale) { - return Promise.resolve(locale.toLowerCase()); + return locale.toLowerCase(); // a directly provided --locale always wins } - const localeConfig = path.join(userDataPath, 'User', 'locale.json'); - return bootstrap.readFile(localeConfig).then(content => { - content = stripComments(content); - try { - const value = JSON.parse(content).locale; - return value && typeof value === 'string' ? value.toLowerCase() : undefined; - } catch (e) { - return undefined; - } - }, () => { - return undefined; - }); + return argvConfig.locale && typeof argvConfig.locale === 'string' ? argvConfig.locale.toLowerCase() : undefined; +} + +/** + * @param {string} localeConfigPath + * @returns {string | undefined} + */ +function getLegacyUserDefinedLocaleSync(localeConfigPath) { + try { + const content = stripComments(fs.readFileSync(localeConfigPath).toString()); + + const value = JSON.parse(content).locale; + return value && typeof value === 'string' ? value.toLowerCase() : undefined; + } catch (error) { + // ignore + } } //#endregion diff --git a/src/typings/chokidar.d.ts b/src/typings/chokidar.d.ts deleted file mode 100644 index a3b4c20a6a1..00000000000 --- a/src/typings/chokidar.d.ts +++ /dev/null @@ -1,200 +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 'chokidar' { - - // TypeScript Version: 3.0 - - import * as fs from "fs"; - import { EventEmitter } from "events"; - - /** - * 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 interface WatchedPaths { - [directory: string]: string[]; - } - - export class FSWatcher extends EventEmitter implements fs.FSWatcher { - - readonly options?: WatchOptions; - - /** - * Constructs a new FSWatcher instance with optional WatchOptions parameter. - */ - 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 { - /** - * 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; - - /** - * ([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). - */ - ignored?: any; - - /** - * 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; - - /** - * 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. - */ - followSymlinks?: boolean; - - /** - * The base directory from which watch `paths` are to be derived. Paths emitted with events will - * be relative to this. - */ - 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; - - /** - * 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; - - /** - * 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; - - /** - * 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. - */ - alwaysStat?: boolean; - - /** - * If set, limits how many levels of subdirectories will be traversed. - */ - depth?: number; - - /** - * Interval of file system polling. - */ - interval?: number; - - /** - * 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; - - /** - * 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; - - /** - * `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; - - /** - * can be set to an object in order to adjust timing params: - */ - awaitWriteFinish?: AwaitWriteFinishOptions | boolean; - } - - export interface AwaitWriteFinishOptions { - /** - * Amount of time in milliseconds for a file size to remain constant before emitting its event. - */ - stabilityThreshold?: number; - - /** - * File size polling interval. - */ - pollInterval?: number; - } - - /** - * produces an instance of `FSWatcher`. - */ - export function watch( - paths: string | string[], - options?: WatchOptions - ): FSWatcher; -} diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index 3e55cdc4bf1..6d90d8c0b1a 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 6.0.9 +// Type definitions for Electron 6.1.2 // Project: http://electronjs.org/ // Definitions by: The Electron Team // Definitions: https://github.com/electron/electron-typescript-definitions @@ -70,6 +70,7 @@ declare namespace Electron { interface RendererInterface extends CommonInterface { BrowserWindowProxy: typeof BrowserWindowProxy; + contextBridge: ContextBridge; desktopCapturer: DesktopCapturer; ipcRenderer: IpcRenderer; remote: Remote; @@ -83,6 +84,7 @@ declare namespace Electron { const autoUpdater: AutoUpdater; const clipboard: Clipboard; const contentTracing: ContentTracing; + const contextBridge: ContextBridge; const crashReporter: CrashReporter; const desktopCapturer: DesktopCapturer; const dialog: Dialog; @@ -2400,6 +2402,11 @@ declare namespace Electron { */ readBookmark(): ReadBookmark; readBuffer(format: string): Buffer; + /** + * This method uses synchronous IPC when called from the renderer process. The + * cached value is reread from the find pasteboard whenever the application is + * activated. + */ readFindText(): string; readHTML(type?: 'selection' | 'clipboard'): string; readImage(type?: 'selection' | 'clipboard'): NativeImage; @@ -2420,8 +2427,9 @@ declare namespace Electron { */ writeBuffer(format: string, buffer: Buffer, type?: 'selection' | 'clipboard'): void; /** - * Writes the text into the find pasteboard as plain text. This method uses - * synchronous IPC when called from the renderer process. + * Writes the text into the find pasteboard (the pasteboard that holds information + * about the current state of the active application’s find panel) as plain text. + * This method uses synchronous IPC when called from the renderer process. */ writeFindText(text: string): void; /** @@ -2505,6 +2513,13 @@ declare namespace Electron { stopRecording(resultFilePath: string): Promise; } + interface ContextBridge extends EventEmitter { + + // Docs: http://electronjs.org/docs/api/context-bridge + + exposeInMainWorld(apiKey: string, api: Record): void; + } + interface Cookie { // Docs: http://electronjs.org/docs/api/structures/cookie @@ -8460,7 +8475,7 @@ declare namespace Electron { image?: NativeImage; rtf?: string; /** - * The title of the url at text. + * The title of the URL at text. */ bookmark?: string; } @@ -8543,7 +8558,9 @@ declare namespace Electron { * When critical is passed, the dock icon will bounce until either the application * becomes active or the request is canceled. When informational is passed, the * dock icon will bounce for one second. However, the request remains active until - * either the application becomes active or the request is canceled. + * either the application becomes active or the request is canceled. Nota Bene: + * This method can only be used while the app is not focused; when the app is + * focused it will return -1. */ bounce: (type?: 'critical' | 'informational') => number; /** @@ -9444,6 +9461,10 @@ declare namespace Electron { } interface OpenDialogReturnValue { + /** + * whether or not the dialog was canceled. + */ + canceled: boolean; /** * An array of file paths chosen by the user. If the dialog is cancelled this will * be an empty array. diff --git a/src/typings/graceful-fs.d.ts b/src/typings/graceful-fs.d.ts deleted file mode 100644 index fafd71f5632..00000000000 --- a/src/typings/graceful-fs.d.ts +++ /dev/null @@ -1,8 +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 'graceful-fs' { - export function gracefulify(fsModule: any): void; -} \ No newline at end of file diff --git a/src/typings/https-proxy-agent.d.ts b/src/typings/https-proxy-agent.d.ts deleted file mode 100644 index 384bee1d6c5..00000000000 --- a/src/typings/https-proxy-agent.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'https-proxy-agent' { - - import * as tls from 'tls'; - - interface IHttpsProxyAgentOptions extends tls.ConnectionOptions { - host: string; - port: number; - auth?: string; - secureProxy?: boolean; - secureEndpoint?: boolean; - } - - class HttpsProxyAgent { - constructor(proxy: string); - constructor(opts: IHttpsProxyAgentOptions); - } - - export = HttpsProxyAgent; -} \ No newline at end of file diff --git a/src/typings/iconv-lite.d.ts b/src/typings/iconv-lite.d.ts deleted file mode 100644 index 05d432b5299..00000000000 --- a/src/typings/iconv-lite.d.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. - *--------------------------------------------------------------------------------------------*/ - -/// - -declare module 'iconv-lite' { - export function decode(buffer: Buffer, encoding: string): string; - - export function encode(content: string | Buffer, encoding: string, options?: { addBOM?: boolean }): Buffer; - - export function encodingExists(encoding: string): boolean; - - export function decodeStream(encoding: string): NodeJS.ReadWriteStream; - - export function encodeStream(encoding: string, options?: { addBOM?: boolean }): NodeJS.ReadWriteStream; -} \ No newline at end of file diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts index 695f872bcd5..c82bd3c5086 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/xterm.d.ts @@ -82,6 +82,16 @@ declare module 'xterm' { */ drawBoldTextInBrightColors?: boolean; + /** + * The modifier key hold to multiply scroll speed. + */ + fastScrollModifier?: 'alt' | 'ctrl' | 'shift' | undefined; + + /** + * The scroll speed multiplier used for fast scrolling. + */ + fastScrollSensitivity?: number; + /** * The font size used to render text. */ @@ -173,6 +183,11 @@ declare module 'xterm' { */ scrollback?: number; + /** + * The scrolling speed multiplier used for adjusting normal scrolling speed. + */ + scrollSensitivity?: number; + /** * The size of tab stops in the terminal. */ @@ -269,7 +284,7 @@ declare module 'xterm' { /** * A callback that fires when the mouse hovers over a link for a moment. */ - tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; + tooltipCallback?: (event: MouseEvent, uri: string, location: IViewportRange) => boolean | void; /** * A callback that fires when the mouse leaves a link. Note that this can @@ -310,7 +325,8 @@ declare module 'xterm' { /** * Represents a specific line in the terminal that is tracked when scrollback - * is trimmed and lines are added or removed. + * is trimmed and lines are added or removed. This is a single line that may + * be part of a larger wrapped line. */ export interface IMarker extends IDisposable { /** @@ -324,7 +340,8 @@ declare module 'xterm' { readonly isDisposed: boolean; /** - * The actual line index in the buffer at this point in time. + * The actual line index in the buffer at this point in time. This is set to + * -1 if the marker has been disposed. */ readonly line: number; } @@ -352,12 +369,12 @@ declare module 'xterm' { /** * The element containing the terminal. */ - readonly element: HTMLElement; + readonly element: HTMLElement | undefined; /** * The textarea that accepts input for the terminal. */ - readonly textarea: HTMLTextAreaElement; + readonly textarea: HTMLTextAreaElement | undefined; /** * The number of rows in the terminal's viewport. Use @@ -434,7 +451,7 @@ declare module 'xterm' { onLineFeed: IEvent; /** - * Adds an event listener for when a scroll occurs. The event value is the + * 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. */ @@ -650,24 +667,32 @@ declare module 'xterm' { clear(): void; /** - * Writes text to the terminal. - * @param data The text to write to the terminal. + * Write data to the terminal. + * @param data The data to write to the terminal. This can either be raw + * bytes given as Uint8Array from the pty or a string. Raw bytes will always + * be treated as UTF-8 encoded, string data as UTF-16. + * @param callback Optional callback that fires when the data was processed + * by the parser. */ - write(data: string): void; + write(data: string | Uint8Array, callback?: () => void): void; /** - * Writes text to the terminal, followed by a break line character (\n). - * @param data The text to write to the terminal. + * Writes data to the terminal, followed by a break line character (\n). + * @param data The data to write to the terminal. This can either be raw + * bytes given as Uint8Array from the pty or a string. Raw bytes will always + * be treated as UTF-8 encoded, string data as UTF-16. + * @param callback Optional callback that fires when the data was processed + * by the parser. */ - writeln(data: string): void; + writeln(data: string | Uint8Array, callback?: () => void): 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. + * Write UTF8 data to the terminal. * @param data The data to write to the terminal. + * @param callback Optional callback when data was processed. + * @deprecated use `write` instead */ - writeUtf8(data: Uint8Array): void; + writeUtf8(data: Uint8Array, callback?: () => void): void; /** * Writes text to the terminal, performing the necessary transformations for pasted text. @@ -804,7 +829,7 @@ declare module 'xterm' { */ export interface ITerminalAddon extends IDisposable { /** - * (EXPERIMENTAL) This is called when the addon is activated. + * This is called when the addon is activated. */ activate(terminal: Terminal): void; } @@ -834,6 +859,41 @@ declare module 'xterm' { endRow: number; } + /** + * An object representing a range within the viewport of the terminal. + */ + export interface IViewportRange { + /** + * The start of the range. + */ + start: IViewportRangePosition; + + /** + * The end of the range. + */ + end: IViewportRangePosition; + } + + /** + * An object representing a cell position within the viewport of the terminal. + */ + interface IViewportRangePosition { + /** + * The x position of the cell. This is a 0-based index that refers to the + * space in between columns, not the column itself. Index 0 refers to the + * left side of the viewport, index `Terminal.cols` refers to the right side + * of the viewport. This can be thought of as how a cursor is positioned in + * a text editor. + */ + x: number; + + /** + * The y position of the cell. This is a 0-based index that refers to a + * specific row. + */ + y: number; + } + /** * Represents a terminal buffer. */ diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 1641b7304af..af7a3b653fc 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -120,6 +120,7 @@ export const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0); export const isChrome = (userAgent.indexOf('Chrome') >= 0); export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0)); export const isWebkitWebView = (!isChrome && !isSafari && isWebKit); +export const isTouchDevice = 'ontouchstart' in window as any || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0; 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); diff --git a/src/vs/base/browser/contextmenu.ts b/src/vs/base/browser/contextmenu.ts index 54dc4d766ca..caf1d299038 100644 --- a/src/vs/base/browser/contextmenu.ts +++ b/src/vs/base/browser/contextmenu.ts @@ -10,10 +10,10 @@ import { SubmenuAction } from 'vs/base/browser/ui/menu/menu'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; export interface IContextMenuEvent { - shiftKey?: boolean; - ctrlKey?: boolean; - altKey?: boolean; - metaKey?: boolean; + readonly shiftKey?: boolean; + readonly ctrlKey?: boolean; + readonly altKey?: boolean; + readonly metaKey?: boolean; } export class ContextSubMenu extends SubmenuAction { @@ -25,6 +25,7 @@ export class ContextSubMenu extends SubmenuAction { export interface IContextMenuDelegate { getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; }; getActions(): ReadonlyArray; + getCheckedActionsRepresentation?(action: IAction): 'radio' | 'checkbox'; getActionViewItem?(action: IAction): IActionViewItem | undefined; getActionsContext?(event?: IContextMenuEvent): any; getKeyBinding?(action: IAction): ResolvedKeybinding | undefined; diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index d9d424f84e4..db901ed9e5e 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -781,6 +781,12 @@ export function createStyleSheet(container: HTMLElement = document.getElementsBy return style; } +export function createMetaElement(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLMetaElement { + let meta = document.createElement('meta'); + container.appendChild(meta); + return meta; +} + let _sharedStyleSheet: HTMLStyleElement | null = null; function getSharedStyleSheet(): HTMLStyleElement { if (!_sharedStyleSheet) { @@ -1206,3 +1212,18 @@ export function asCSSUrl(uri: URI): string { } return `url('${asDomUri(uri).toString(true).replace(/'/g, '%27')}')`; } + +export function triggerDownload(uri: URI, name: string): void { + // In order to download from the browser, the only way seems + // to be creating a element with download attribute that + // points to the file to download. + // See also https://developers.google.com/web/updates/2011/08/Downloading-resources-in-HTML5-a-download + const anchor = document.createElement('a'); + document.body.appendChild(anchor); + anchor.download = name; + anchor.href = uri.toString(true); + anchor.click(); + + // Ensure to remove the element from DOM eventually + setTimeout(() => document.body.removeChild(anchor)); +} diff --git a/src/vs/base/browser/fastDomNode.ts b/src/vs/base/browser/fastDomNode.ts index cb121546529..6dfec19f492 100644 --- a/src/vs/base/browser/fastDomNode.ts +++ b/src/vs/base/browser/fastDomNode.ts @@ -18,6 +18,7 @@ export class FastDomNode { private _fontFamily: string; private _fontWeight: string; private _fontSize: number; + private _fontFeatureSettings: string; private _lineHeight: number; private _letterSpacing: number; private _className: string; @@ -38,6 +39,7 @@ export class FastDomNode { this._fontFamily = ''; this._fontWeight = ''; this._fontSize = -1; + this._fontFeatureSettings = ''; this._lineHeight = -1; this._letterSpacing = -100; this._className = ''; @@ -135,6 +137,14 @@ export class FastDomNode { this.domNode.style.fontSize = this._fontSize + 'px'; } + public setFontFeatureSettings(fontFeatureSettings: string): void { + if (this._fontFeatureSettings === fontFeatureSettings) { + return; + } + this._fontFeatureSettings = fontFeatureSettings; + this.domNode.style.fontFeatureSettings = this._fontFeatureSettings; + } + public setLineHeight(lineHeight: number): void { if (this._lineHeight === lineHeight) { return; diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 7749f2c1f79..57144d67ea6 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -9,7 +9,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { IMarkdownString, parseHrefAndDimensions, removeMarkdownEscapes } from 'vs/base/common/htmlContent'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import * as marked from 'vs/base/common/marked/marked'; -import * as insane from 'vs/base/common/insane/insane'; +import { insane } from 'vs/base/common/insane/insane'; import { parse } from 'vs/base/common/marshalling'; import { cloneAndChange } from 'vs/base/common/objects'; import { escape } from 'vs/base/common/strings'; @@ -68,7 +68,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende // signal to code-block render that the // element has been created let signalInnerHTML: () => void; - const withInnerHTML = new Promise(c => signalInnerHTML = c); + const withInnerHTML = new Promise(c => signalInnerHTML = c); const renderer = new marked.Renderer(); renderer.image = (href: string, title: string, text: string) => { diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts index 4c7295e3b9b..f3f2089100b 100644 --- a/src/vs/base/browser/mouseEvent.ts +++ b/src/vs/base/browser/mouseEvent.ts @@ -152,6 +152,7 @@ export class StandardWheelEvent { this.deltaX = deltaX; if (e) { + // Old (deprecated) wheel events let e1 = e; let e2 = e; @@ -160,8 +161,17 @@ 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; + } else if (e.type === 'wheel') { + // Modern wheel event + // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent + const ev = e; + + if (ev.deltaMode === ev.DOM_DELTA_LINE) { + // the deltas are expressed in lines + this.deltaY = -e.deltaY; + } else { + this.deltaY = -e.deltaY / 40; + } } // horizontal delta scroll @@ -173,8 +183,17 @@ 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; + } else if (e.type === 'wheel') { + // Modern wheel event + // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent + const ev = e; + + if (ev.deltaMode === ev.DOM_DELTA_LINE) { + // the deltas are expressed in lines + this.deltaX = -e.deltaX; + } else { + this.deltaX = -e.deltaX / 40; + } } // Assume a vertical scroll if nothing else worked diff --git a/src/vs/base/browser/touch.ts b/src/vs/base/browser/touch.ts index f1ea0ee56ca..bef90a94d4d 100644 --- a/src/vs/base/browser/touch.ts +++ b/src/vs/base/browser/touch.ts @@ -67,7 +67,7 @@ export class Gesture extends Disposable { private static readonly SCROLL_FRICTION = -0.005; private static INSTANCE: Gesture; - private static HOLD_DELAY = 700; + private static readonly HOLD_DELAY = 700; private dispatched = false; private targets: HTMLElement[]; @@ -86,15 +86,21 @@ export class Gesture extends Disposable { this._register(DomUtils.addDisposableListener(document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e))); } - public static addTarget(element: HTMLElement): void { + public static addTarget(element: HTMLElement): IDisposable { if (!Gesture.isTouchDevice()) { - return; + return Disposable.None; } if (!Gesture.INSTANCE) { Gesture.INSTANCE = new Gesture(); } Gesture.INSTANCE.targets.push(element); + + return { + dispose: () => { + Gesture.INSTANCE.targets = Gesture.INSTANCE.targets.filter(t => t !== element); + } + }; } @memoize diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index f2eff2c7f66..60979ab095d 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -50,12 +50,6 @@ margin-right: 4px; } -.monaco-action-bar .action-label.octicon { - font-size: 15px; - line-height: 35px; - text-align: center; -} - .monaco-action-bar .action-item.disabled .action-label, .monaco-action-bar .action-item.disabled .action-label:hover { opacity: 0.4; diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 38ec0a60a51..eea40403381 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -33,11 +33,12 @@ export interface IBaseActionViewItemOptions { export class BaseActionViewItem extends Disposable implements IActionViewItem { - element?: HTMLElement; + element: HTMLElement | undefined; + _context: any; _action: IAction; - private _actionRunner!: IActionRunner; + private _actionRunner: IActionRunner | undefined; constructor(context: any, action: IAction, protected options?: IBaseActionViewItemOptions) { super(); @@ -81,12 +82,16 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } } - set actionRunner(actionRunner: IActionRunner) { - this._actionRunner = actionRunner; + get actionRunner(): IActionRunner { + if (!this._actionRunner) { + this._actionRunner = this._register(new ActionRunner()); + } + + return this._actionRunner; } - get actionRunner(): IActionRunner { - return this._actionRunner; + set actionRunner(actionRunner: IActionRunner) { + this._actionRunner = actionRunner; } getAction(): IAction { @@ -102,27 +107,27 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } render(container: HTMLElement): void { - this.element = container; - Gesture.addTarget(container); + const element = this.element = container; + this._register(Gesture.addTarget(container)); const enableDragging = this.options && this.options.draggable; if (enableDragging) { container.draggable = true; } - this._register(DOM.addDisposableListener(this.element, EventType.Tap, e => this.onClick(e))); + this._register(DOM.addDisposableListener(element, EventType.Tap, e => this.onClick(e))); - this._register(DOM.addDisposableListener(this.element, DOM.EventType.MOUSE_DOWN, e => { + this._register(DOM.addDisposableListener(element, DOM.EventType.MOUSE_DOWN, e => { if (!enableDragging) { DOM.EventHelper.stop(e, true); // do not run when dragging is on because that would disable it } - if (this._action.enabled && e.button === 0 && this.element) { - DOM.addClass(this.element, 'active'); + if (this._action.enabled && e.button === 0) { + DOM.addClass(element, 'active'); } })); - this._register(DOM.addDisposableListener(this.element, DOM.EventType.CLICK, e => { + this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, e => { DOM.EventHelper.stop(e, true); // See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard // > Writing to the clipboard @@ -139,14 +144,14 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } })); - this._register(DOM.addDisposableListener(this.element, DOM.EventType.DBLCLICK, e => { + this._register(DOM.addDisposableListener(element, DOM.EventType.DBLCLICK, e => { DOM.EventHelper.stop(e, true); })); [DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT].forEach(event => { - this._register(DOM.addDisposableListener(this.element!, event, e => { + this._register(DOM.addDisposableListener(element, event, e => { DOM.EventHelper.stop(e); - DOM.removeClass(this.element!, 'active'); + DOM.removeClass(element, 'active'); })); }); } @@ -165,7 +170,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } } - this._actionRunner.run(this._action, context); + this.actionRunner.run(this._action, context); } focus(): void { @@ -219,7 +224,6 @@ export class Separator extends Action { constructor(label?: string) { super(Separator.ID, label, label ? 'separator text' : 'separator'); this.checked = false; - this.radio = false; this.enabled = false; } } @@ -232,7 +236,7 @@ export interface IActionViewItemOptions extends IBaseActionViewItemOptions { export class ActionViewItem extends BaseActionViewItem { - protected label!: HTMLElement; + protected label: HTMLElement | undefined; protected options: IActionViewItemOptions; private cssClass?: string; @@ -252,13 +256,17 @@ export class ActionViewItem extends BaseActionViewItem { if (this.element) { this.label = DOM.append(this.element, DOM.$('a.action-label')); } - if (this._action.id === Separator.ID) { - this.label.setAttribute('role', 'presentation'); // A separator is a presentation item - } else { - if (this.options.isMenu) { - this.label.setAttribute('role', 'menuitem'); + + + if (this.label) { + if (this._action.id === Separator.ID) { + this.label.setAttribute('role', 'presentation'); // A separator is a presentation item } else { - this.label.setAttribute('role', 'button'); + if (this.options.isMenu) { + this.label.setAttribute('role', 'menuitem'); + } else { + this.label.setAttribute('role', 'button'); + } } } @@ -276,11 +284,13 @@ export class ActionViewItem extends BaseActionViewItem { focus(): void { super.focus(); - this.label.focus(); + if (this.label) { + this.label.focus(); + } } updateLabel(): void { - if (this.options.label) { + if (this.options.label && this.label) { this.label.textContent = this.getAction().label; } } @@ -299,52 +309,65 @@ export class ActionViewItem extends BaseActionViewItem { } } - if (title) { + if (title && this.label) { this.label.title = title; } } updateClass(): void { - if (this.cssClass) { + if (this.cssClass && this.label) { DOM.removeClasses(this.label, this.cssClass); } if (this.options.icon) { this.cssClass = this.getAction().class; - DOM.addClass(this.label, 'codicon'); - if (this.cssClass) { - DOM.addClasses(this.label, this.cssClass); + + if (this.label) { + DOM.addClass(this.label, 'codicon'); + if (this.cssClass) { + DOM.addClasses(this.label, this.cssClass); + } } this.updateEnabled(); } else { - DOM.removeClass(this.label, 'codicon'); + if (this.label) { + DOM.removeClass(this.label, 'codicon'); + } } } updateEnabled(): void { if (this.getAction().enabled) { - this.label.removeAttribute('aria-disabled'); + if (this.label) { + this.label.removeAttribute('aria-disabled'); + DOM.removeClass(this.label, 'disabled'); + this.label.tabIndex = 0; + } + if (this.element) { DOM.removeClass(this.element, 'disabled'); } - DOM.removeClass(this.label, 'disabled'); - this.label.tabIndex = 0; } else { - this.label.setAttribute('aria-disabled', 'true'); + if (this.label) { + this.label.setAttribute('aria-disabled', 'true'); + DOM.addClass(this.label, 'disabled'); + DOM.removeTabIndexAndUpdateFocus(this.label); + } + if (this.element) { DOM.addClass(this.element, 'disabled'); } - DOM.addClass(this.label, 'disabled'); - DOM.removeTabIndexAndUpdateFocus(this.label); } } updateChecked(): void { - if (this.getAction().checked) { - DOM.addClass(this.label, 'checked'); - } else { - DOM.removeClass(this.label, 'checked'); + if (this.label) { + if (this.getAction().checked) { + DOM.addClass(this.label, 'checked'); + } else { + DOM.removeClass(this.label, 'checked'); + } } } } @@ -745,9 +768,9 @@ export class ActionBar extends Disposable implements IActionRunner { this.updateFocus(true); } - protected updateFocus(fromRight?: boolean): void { + protected updateFocus(fromRight?: boolean, preventScroll?: boolean): void { if (typeof this.focusedItem === 'undefined') { - this.actionsList.focus(); + this.actionsList.focus({ preventScroll }); } for (let i = 0; i < this.viewItems.length; i++) { @@ -759,7 +782,7 @@ export class ActionBar extends Disposable implements IActionRunner { if (actionViewItem.isEnabled() && types.isFunction(actionViewItem.focus)) { actionViewItem.focus(fromRight); } else { - this.actionsList.focus(); + this.actionsList.focus({ preventScroll }); } } } else { diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css index 1e49da134fd..65b207f0b04 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css @@ -5,6 +5,8 @@ .monaco-breadcrumbs { user-select: none; + -webkit-user-select: none; + -ms-user-select: none; display: flex; flex-direction: row; flex-wrap: nowrap; @@ -23,24 +25,10 @@ outline: none; } -.monaco-breadcrumbs .monaco-breadcrumb-item::before { - width: 14px; - height: 16px; - display: inline-block; +.monaco-breadcrumbs .monaco-breadcrumb-item .codicon-chevron-right { + color: inherit; +} + +.monaco-breadcrumbs .monaco-breadcrumb-item:first-of-type::before { content: ' '; } - -.monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before { - 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(./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 2e72938f986..5ce81d72e66 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -328,7 +328,9 @@ export class BreadcrumbsWidget { item.render(container); container.tabIndex = -1; container.setAttribute('role', 'listitem'); - dom.addClass(container, 'monaco-breadcrumb-item'); + dom.addClasses(container, 'monaco-breadcrumb-item'); + const iconContainer = dom.$('.codicon.codicon-chevron-right'); + container.appendChild(iconContainer); } private _onClick(event: IMouseEvent): void { diff --git a/src/vs/base/browser/ui/button/button.css b/src/vs/base/browser/ui/button/button.css index 814e52d0826..69299e332fb 100644 --- a/src/vs/base/browser/ui/button/button.css +++ b/src/vs/base/browser/ui/button/button.css @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ .monaco-text-button { - -moz-box-sizing: border-box; box-sizing: border-box; display: inline-block; width: 100%; @@ -21,4 +20,4 @@ .monaco-button.disabled { opacity: 0.4; cursor: default; -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index eeb7724e5fd..de4d35ef320 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -63,7 +63,7 @@ export class Button extends Disposable { container.appendChild(this._element); - Gesture.addTarget(this._element); + this._register(Gesture.addTarget(this._element)); [DOM.EventType.CLICK, EventType.Tap].forEach(eventType => { this._register(DOM.addDisposableListener(this._element, eventType, e => { @@ -79,7 +79,7 @@ export class Button extends Disposable { this._register(DOM.addDisposableListener(this._element, DOM.EventType.KEY_DOWN, e => { const event = new StandardKeyboardEvent(e); let eventHandled = false; - if (this.enabled && event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { + if (this.enabled && (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) { this._onDidClick.fire(e); eventHandled = true; } else if (event.equals(KeyCode.Escape)) { @@ -128,15 +128,15 @@ export class Button extends Disposable { private applyStyles(): void { if (this._element) { - const background = this.buttonBackground ? this.buttonBackground.toString() : null; + const background = this.buttonBackground ? this.buttonBackground.toString() : ''; const foreground = this.buttonForeground ? this.buttonForeground.toString() : null; - const border = this.buttonBorder ? this.buttonBorder.toString() : null; + const border = this.buttonBorder ? this.buttonBorder.toString() : ''; this._element.style.color = foreground; this._element.style.backgroundColor = background; - this._element.style.borderWidth = border ? '1px' : null; - this._element.style.borderStyle = border ? 'solid' : null; + this._element.style.borderWidth = border ? '1px' : ''; + this._element.style.borderStyle = border ? 'solid' : ''; this._element.style.borderColor = border; } } diff --git a/src/vs/base/browser/ui/checkbox/checkbox.css b/src/vs/base/browser/ui/checkbox/checkbox.css index 26f48b88c02..fa9aa082d39 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.css +++ b/src/vs/base/browser/ui/checkbox/checkbox.css @@ -13,19 +13,10 @@ height: 20px; border: 1px solid transparent; padding: 1px; - - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -o-user-select: none; - -ms-user-select: none; + box-sizing: border-box; user-select: none; + -webkit-user-select: none; + -ms-user-select: none; } .monaco-custom-checkbox:hover, diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 6bc9a8e3d4c..afc9cc616a0 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -38,7 +38,7 @@ const defaultOpts = { export class CheckboxActionViewItem extends BaseActionViewItem { - private checkbox!: Checkbox; + private checkbox: Checkbox | undefined; private readonly disposables = new DisposableStore(); render(container: HTMLElement): void { @@ -51,7 +51,7 @@ export class CheckboxActionViewItem extends BaseActionViewItem { title: this._action.label }); this.disposables.add(this.checkbox); - this.disposables.add(this.checkbox.onChange(() => this._action.checked = this.checkbox!.checked, this)); + this.disposables.add(this.checkbox.onChange(() => this._action.checked = !!this.checkbox && this.checkbox.checked, this)); this.element.appendChild(this.checkbox.domNode); } @@ -219,7 +219,7 @@ export class SimpleCheckbox extends Widget { protected applyStyles(): void { this.domNode.style.color = this.styles.checkboxForeground ? this.styles.checkboxForeground.toString() : null; - this.domNode.style.backgroundColor = this.styles.checkboxBackground ? this.styles.checkboxBackground.toString() : null; - this.domNode.style.borderColor = this.styles.checkboxBorder ? this.styles.checkboxBorder.toString() : null; + this.domNode.style.backgroundColor = this.styles.checkboxBackground ? this.styles.checkboxBackground.toString() : ''; + this.domNode.style.borderColor = this.styles.checkboxBorder ? this.styles.checkboxBorder.toString() : ''; } } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon-animations.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon-animations.css index 86c223674ec..abfde40dede 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon-animations.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon-animations.css @@ -10,5 +10,5 @@ } .codicon-animation-spin { - animation: octicon-spin 1.5s linear infinite; + animation: codicon-spin 1.5s linear infinite; } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index cd87edb95cf..1c899992d0b 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?3b584136fb1f0186a1ee578cdcb5240b") format("truetype"); + src: url("./codicon.ttf?f5d7d29fe5677c620f764a26698d7611") format("truetype"); } .codicon[class*='codicon-'] { @@ -16,10 +16,14 @@ text-align: center; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + + /* Hack to get web rendering to align to pixel grid */ + transform: rotate(0); + -webkit-transform: rotate(0.1deg); + -moz-transform: rotate(0); } @@ -54,6 +58,7 @@ .codicon-star:before { content: "\ea6a" } .codicon-star-add:before { content: "\ea6a" } .codicon-star-delete:before { content: "\ea6a" } +.codicon-star-empty:before { content: "\ea6a" } .codicon-comment:before { content: "\ea6b" } .codicon-comment-add:before { content: "\ea6b" } .codicon-alert:before { content: "\ea6c" } @@ -69,7 +74,6 @@ .codicon-eye-watch:before { content: "\ea70" } .codicon-circle-filled:before { content: "\ea71" } .codicon-primitive-dot:before { content: "\ea71" } -.codicon-stop:before { content: "\ea72" } .codicon-primitive-square:before { content: "\ea72" } .codicon-edit:before { content: "\ea73" } .codicon-pencil:before { content: "\ea73" } @@ -93,6 +97,7 @@ .codicon-file:before { content: "\ea7b" } .codicon-file-text:before { content: "\ea7b" } .codicon-more:before { content: "\ea7c" } +.codicon-ellipsis:before { content: "\ea7c" } .codicon-kebab-horizontal:before { content: "\ea7c" } .codicon-mail-reply:before { content: "\ea7d" } .codicon-reply:before { content: "\ea7d" } @@ -103,253 +108,283 @@ .codicon-file-add:before { content: "\ea7f" } .codicon-new-folder:before { content: "\ea80" } .codicon-file-directory-create:before { content: "\ea80" } -.codicon-Vector:before { content: "\f101" } -.codicon-activate-breakpoints:before { content: "\f102" } -.codicon-archive:before { content: "\f103" } -.codicon-array:before { content: "\f104" } -.codicon-arrow-both:before { content: "\f105" } -.codicon-arrow-down:before { content: "\f106" } -.codicon-arrow-left:before { content: "\f107" } -.codicon-arrow-right:before { content: "\f108" } -.codicon-arrow-small-down:before { content: "\f109" } -.codicon-arrow-small-left:before { content: "\f10a" } -.codicon-arrow-small-right:before { content: "\f10b" } -.codicon-arrow-small-up:before { content: "\f10c" } -.codicon-arrow-up:before { content: "\f10d" } -.codicon-bell:before { content: "\f10e" } -.codicon-bold:before { content: "\f10f" } -.codicon-book:before { content: "\f110" } -.codicon-bookmark:before { content: "\f111" } -.codicon-boolean:before { content: "\f112" } -.codicon-breakpoint-conditional-unverified:before { content: "\f113" } -.codicon-breakpoint-conditional:before { content: "\f114" } -.codicon-breakpoint-data-unverified:before { content: "\f115" } -.codicon-breakpoint-data:before { content: "\f116" } -.codicon-breakpoint-log-unverified:before { content: "\f117" } -.codicon-breakpoint-log:before { content: "\f118" } -.codicon-briefcase:before { content: "\f119" } -.codicon-broadcast:before { content: "\f11a" } -.codicon-browser:before { content: "\f11b" } -.codicon-bug:before { content: "\f11c" } -.codicon-calendar:before { content: "\f11d" } -.codicon-case-sensitive:before { content: "\f11e" } -.codicon-check:before { content: "\f11f" } -.codicon-checklist:before { content: "\f120" } -.codicon-chevron-down:before { content: "\f121" } -.codicon-chevron-left:before { content: "\f122" } -.codicon-chevron-right:before { content: "\f123" } -.codicon-chevron-up:before { content: "\f124" } -.codicon-circle-outline:before { content: "\f125" } -.codicon-circle-slash:before { content: "\f126" } -.codicon-circuit-board:before { content: "\f127" } -.codicon-class:before { content: "\f128" } -.codicon-clear-all:before { content: "\f129" } -.codicon-clippy:before { content: "\f12a" } -.codicon-close-all:before { content: "\f12b" } -.codicon-cloud-download:before { content: "\f12c" } -.codicon-cloud-upload:before { content: "\f12d" } -.codicon-code:before { content: "\f12e" } -.codicon-collapse-all:before { content: "\f12f" } -.codicon-color-mode:before { content: "\f130" } -.codicon-color:before { content: "\f131" } -.codicon-comment-discussion:before { content: "\f132" } -.codicon-compare-changes:before { content: "\f133" } -.codicon-console:before { content: "\f134" } -.codicon-constant:before { content: "\f135" } -.codicon-continue:before { content: "\f136" } -.codicon-credit-card:before { content: "\f137" } -.codicon-current-and-breakpoint:before { content: "\f138" } -.codicon-current:before { content: "\f139" } -.codicon-dash:before { content: "\f13a" } -.codicon-dashboard:before { content: "\f13b" } -.codicon-database:before { content: "\f13c" } -.codicon-debug:before { content: "\f13d" } -.codicon-device-camera-video:before { content: "\f13e" } -.codicon-device-camera:before { content: "\f13f" } -.codicon-device-mobile:before { content: "\f140" } -.codicon-diff-added:before { content: "\f141" } -.codicon-diff-ignored:before { content: "\f142" } -.codicon-diff-modified:before { content: "\f143" } -.codicon-diff-removed:before { content: "\f144" } -.codicon-diff-renamed:before { content: "\f145" } -.codicon-diff:before { content: "\f146" } -.codicon-discard:before { content: "\f147" } -.codicon-disconnect-:before { content: "\f148" } -.codicon-editor-layout:before { content: "\f149" } -.codicon-ellipsis:before { content: "\f14a" } -.codicon-empty-window:before { content: "\f14b" } -.codicon-enumerator-member:before { content: "\f14c" } -.codicon-enumerator:before { content: "\f14d" } -.codicon-error:before { content: "\f14e" } -.codicon-event:before { content: "\f14f" } -.codicon-exclude:before { content: "\f150" } -.codicon-extensions:before { content: "\f151" } -.codicon-eye-closed:before { content: "\f152" } -.codicon-field:before { content: "\f153" } -.codicon-file-binary:before { content: "\f154" } -.codicon-file-code:before { content: "\f155" } -.codicon-file-media:before { content: "\f156" } -.codicon-file-pdf:before { content: "\f157" } -.codicon-file-submodule:before { content: "\f158" } -.codicon-file-symlink-directory:before { content: "\f159" } -.codicon-file-symlink-file:before { content: "\f15a" } -.codicon-file-zip:before { content: "\f15b" } -.codicon-files:before { content: "\f15c" } -.codicon-filter:before { content: "\f15d" } -.codicon-flame:before { content: "\f15e" } -.codicon-fold-down:before { content: "\f15f" } -.codicon-fold-up:before { content: "\f160" } -.codicon-fold:before { content: "\f161" } -.codicon-folder-active:before { content: "\f162" } -.codicon-folder-opened:before { content: "\f163" } -.codicon-folder:before { content: "\f164" } -.codicon-gear:before { content: "\f165" } -.codicon-gift:before { content: "\f166" } -.codicon-gist-secret:before { content: "\f167" } -.codicon-gist:before { content: "\f168" } -.codicon-git-commit:before { content: "\f169" } -.codicon-git-compare:before { content: "\f16a" } -.codicon-git-merge:before { content: "\f16b" } -.codicon-github-action:before { content: "\f16c" } -.codicon-github-alt:before { content: "\f16d" } -.codicon-github:before { content: "\f16e" } -.codicon-globe:before { content: "\f16f" } -.codicon-go-to-file:before { content: "\f170" } -.codicon-grabber:before { content: "\f171" } -.codicon-graph:before { content: "\f172" } -.codicon-gripper:before { content: "\f173" } -.codicon-heart:before { content: "\f174" } -.codicon-history:before { content: "\f175" } -.codicon-home:before { content: "\f176" } -.codicon-horizontal-rule:before { content: "\f177" } -.codicon-hubot:before { content: "\f178" } -.codicon-inbox:before { content: "\f179" } -.codicon-interface:before { content: "\f17a" } -.codicon-issue-closed:before { content: "\f17b" } -.codicon-issue-reopened:before { content: "\f17c" } -.codicon-issues:before { content: "\f17d" } -.codicon-italic:before { content: "\f17e" } -.codicon-jersey:before { content: "\f17f" } -.codicon-json:before { content: "\f180" } -.codicon-kebab-vertical:before { content: "\f181" } -.codicon-key:before { content: "\f182" } -.codicon-keyword:before { content: "\f183" } -.codicon-law:before { content: "\f184" } -.codicon-lightbulb-autofix:before { content: "\f185" } -.codicon-link-external:before { content: "\f186" } -.codicon-link:before { content: "\f187" } -.codicon-list-ordered:before { content: "\f188" } -.codicon-list-unordered:before { content: "\f189" } -.codicon-live-share:before { content: "\f18a" } -.codicon-loading:before { content: "\f18b" } -.codicon-location:before { content: "\f18c" } -.codicon-mail-read:before { content: "\f18d" } -.codicon-mail:before { content: "\f18e" } -.codicon-markdown:before { content: "\f18f" } -.codicon-megaphone:before { content: "\f190" } -.codicon-mention:before { content: "\f191" } -.codicon-method:before { content: "\f192" } -.codicon-milestone:before { content: "\f193" } -.codicon-misc:before { content: "\f194" } -.codicon-mortar-board:before { content: "\f195" } -.codicon-move:before { content: "\f196" } -.codicon-multiple-windows:before { content: "\f197" } -.codicon-mute:before { content: "\f198" } -.codicon-namespace:before { content: "\f199" } -.codicon-no-newline:before { content: "\f19a" } -.codicon-note:before { content: "\f19b" } -.codicon-numeric:before { content: "\f19c" } -.codicon-octoface:before { content: "\f19d" } -.codicon-open-preview:before { content: "\f19e" } -.codicon-operator:before { content: "\f19f" } -.codicon-package:before { content: "\f1a0" } -.codicon-paintcan:before { content: "\f1a1" } -.codicon-parameter:before { content: "\f1a2" } -.codicon-pause:before { content: "\f1a3" } -.codicon-pin:before { content: "\f1a4" } -.codicon-play:before { content: "\f1a5" } -.codicon-plug:before { content: "\f1a6" } -.codicon-preserve-case:before { content: "\f1a7" } -.codicon-preview:before { content: "\f1a8" } -.codicon-project:before { content: "\f1a9" } -.codicon-property:before { content: "\f1aa" } -.codicon-pulse:before { content: "\f1ab" } -.codicon-question:before { content: "\f1ac" } -.codicon-quote:before { content: "\f1ad" } -.codicon-radio-tower:before { content: "\f1ae" } -.codicon-reactions:before { content: "\f1af" } -.codicon-references:before { content: "\f1b0" } -.codicon-refresh:before { content: "\f1b1" } -.codicon-regex:before { content: "\f1b2" } -.codicon-remote:before { content: "\f1b3" } -.codicon-remove:before { content: "\f1b4" } -.codicon-replace-all:before { content: "\f1b5" } -.codicon-replace:before { content: "\f1b6" } -.codicon-repo-clone:before { content: "\f1b7" } -.codicon-repo-force-push:before { content: "\f1b8" } -.codicon-repo-pull:before { content: "\f1b9" } -.codicon-repo-push:before { content: "\f1ba" } -.codicon-report:before { content: "\f1bb" } -.codicon-request-changes:before { content: "\f1bc" } -.codicon-restart:before { content: "\f1bd" } -.codicon-rocket:before { content: "\f1be" } -.codicon-root-folder-opened:before { content: "\f1bf" } -.codicon-root-folder:before { content: "\f1c0" } -.codicon-rss:before { content: "\f1c1" } -.codicon-ruby:before { content: "\f1c2" } -.codicon-ruler:before { content: "\f1c3" } -.codicon-save-all:before { content: "\f1c4" } -.codicon-save-as:before { content: "\f1c5" } -.codicon-save:before { content: "\f1c6" } -.codicon-screen-full:before { content: "\f1c7" } -.codicon-screen-normal:before { content: "\f1c8" } -.codicon-search-stop:before { content: "\f1c9" } -.codicon-selection:before { content: "\f1ca" } -.codicon-server:before { content: "\f1cb" } -.codicon-settings:before { content: "\f1cc" } -.codicon-shield:before { content: "\f1cd" } -.codicon-smiley:before { content: "\f1ce" } -.codicon-snippet:before { content: "\f1cf" } -.codicon-sort-precedence:before { content: "\f1d0" } -.codicon-split-horizontal:before { content: "\f1d1" } -.codicon-split-vertical:before { content: "\f1d2" } -.codicon-squirrel:before { content: "\f1d3" } -.codicon-star-empty:before { content: "\f1d4" } -.codicon-star-full:before { content: "\f1d5" } -.codicon-star-half:before { content: "\f1d6" } -.codicon-start:before { content: "\f1d7" } -.codicon-step-into:before { content: "\f1d8" } -.codicon-step-out:before { content: "\f1d9" } -.codicon-step-over:before { content: "\f1da" } -.codicon-string:before { content: "\f1db" } -.codicon-structure:before { content: "\f1dc" } -.codicon-tasklist:before { content: "\f1dd" } -.codicon-telescope:before { content: "\f1de" } -.codicon-text-size:before { content: "\f1df" } -.codicon-three-bars:before { content: "\f1e0" } -.codicon-thumbsdown:before { content: "\f1e1" } -.codicon-thumbsup:before { content: "\f1e2" } -.codicon-tools:before { content: "\f1e3" } -.codicon-trash:before { content: "\f1e4" } -.codicon-triangle-down:before { content: "\f1e5" } -.codicon-triangle-left:before { content: "\f1e6" } -.codicon-triangle-right:before { content: "\f1e7" } -.codicon-triangle-up:before { content: "\f1e8" } -.codicon-twitter:before { content: "\f1e9" } -.codicon-unfold:before { content: "\f1ea" } -.codicon-unlock:before { content: "\f1eb" } -.codicon-unmute:before { content: "\f1ec" } -.codicon-unverified:before { content: "\f1ed" } -.codicon-variable:before { content: "\f1ee" } -.codicon-verified:before { content: "\f1ef" } -.codicon-versions:before { content: "\f1f0" } -.codicon-vm-active:before { content: "\f1f1" } -.codicon-vm-outline:before { content: "\f1f2" } -.codicon-vm-running:before { content: "\f1f3" } -.codicon-watch:before { content: "\f1f4" } -.codicon-whitespace:before { content: "\f1f5" } -.codicon-whole-word:before { content: "\f1f6" } -.codicon-window:before { content: "\f1f7" } -.codicon-word-wrap:before { content: "\f1f8" } -.codicon-zoom-in:before { content: "\f1f9" } -.codicon-zoom-out:before { content: "\f1fa" } +.codicon-trash:before { content: "\ea81" } +.codicon-trashcan:before { content: "\ea81" } +.codicon-history:before { content: "\ea82" } +.codicon-clock:before { content: "\ea82" } +.codicon-folder:before { content: "\ea83" } +.codicon-file-directory:before { content: "\ea83" } +.codicon-symbol-folder:before { content: "\ea83" } +.codicon-logo-github:before { content: "\ea84" } +.codicon-mark-github:before { content: "\ea84" } +.codicon-github:before { content: "\ea84" } +.codicon-terminal:before { content: "\ea85" } +.codicon-console:before { content: "\ea85" } +.codicon-zap:before { content: "\ea86" } +.codicon-symbol-event:before { content: "\ea86" } +.codicon-error:before { content: "\ea87" } +.codicon-stop:before { content: "\ea87" } +.codicon-variable:before { content: "\ea88" } +.codicon-symbol-variable:before { content: "\ea88" } +.codicon-array:before { content: "\ea8a" } +.codicon-symbol-array:before { content: "\ea8a" } +.codicon-symbol-module:before { content: "\ea8b" } +.codicon-symbol-package:before { content: "\ea8b" } +.codicon-symbol-namespace:before { content: "\ea8b" } +.codicon-symbol-object:before { content: "\ea8b" } +.codicon-symbol-method:before { content: "\ea8c" } +.codicon-symbol-function:before { content: "\ea8c" } +.codicon-symbol-constructor:before { content: "\ea8c" } +.codicon-symbol-boolean:before { content: "\ea8f" } +.codicon-symbol-null:before { content: "\ea8f" } +.codicon-symbol-numeric:before { content: "\ea90" } +.codicon-symbol-number:before { content: "\ea90" } +.codicon-symbol-structure:before { content: "\ea91" } +.codicon-symbol-struct:before { content: "\ea91" } +.codicon-symbol-parameter:before { content: "\ea92" } +.codicon-symbol-type-parameter:before { content: "\ea92" } +.codicon-symbol-key:before { content: "\ea93" } +.codicon-symbol-string:before { content: "\ea93" } +.codicon-symbol-text:before { content: "\ea93" } +.codicon-symbol-reference:before { content: "\ea94" } +.codicon-go-to-file:before { content: "\ea94" } +.codicon-symbol-enum:before { content: "\ea95" } +.codicon-symbol-value:before { content: "\ea95" } +.codicon-symbol-ruler:before { content: "\ea96" } +.codicon-symbol-unit:before { content: "\ea96" } +.codicon-activate-breakpoints:before { content: "\ea97" } +.codicon-archive:before { content: "\ea98" } +.codicon-arrow-both:before { content: "\ea99" } +.codicon-arrow-down:before { content: "\ea9a" } +.codicon-arrow-left:before { content: "\ea9b" } +.codicon-arrow-right:before { content: "\ea9c" } +.codicon-arrow-small-down:before { content: "\ea9d" } +.codicon-arrow-small-left:before { content: "\ea9e" } +.codicon-arrow-small-right:before { content: "\ea9f" } +.codicon-arrow-small-up:before { content: "\eaa0" } +.codicon-arrow-up:before { content: "\eaa1" } +.codicon-bell:before { content: "\eaa2" } +.codicon-bold:before { content: "\eaa3" } +.codicon-book:before { content: "\eaa4" } +.codicon-bookmark:before { content: "\eaa5" } +.codicon-breakpoint-conditional-unverified:before { content: "\eaa6" } +.codicon-breakpoint-conditional:before { content: "\eaa7" } +.codicon-breakpoint-data-unverified:before { content: "\eaa8" } +.codicon-breakpoint-data:before { content: "\eaa9" } +.codicon-breakpoint-log-unverified:before { content: "\eaaa" } +.codicon-breakpoint-log:before { content: "\eaab" } +.codicon-briefcase:before { content: "\eaac" } +.codicon-broadcast:before { content: "\eaad" } +.codicon-browser:before { content: "\eaae" } +.codicon-bug:before { content: "\eaaf" } +.codicon-calendar:before { content: "\eab0" } +.codicon-case-sensitive:before { content: "\eab1" } +.codicon-check:before { content: "\eab2" } +.codicon-checklist:before { content: "\eab3" } +.codicon-chevron-down:before { content: "\eab4" } +.codicon-chevron-left:before { content: "\eab5" } +.codicon-chevron-right:before { content: "\eab6" } +.codicon-chevron-up:before { content: "\eab7" } +.codicon-chrome-close:before { content: "\eab8" } +.codicon-chrome-maximize:before { content: "\eab9" } +.codicon-chrome-minimize:before { content: "\eaba" } +.codicon-chrome-restore:before { content: "\eabb" } +.codicon-circle-outline:before { content: "\eabc" } +.codicon-circle-slash:before { content: "\eabd" } +.codicon-circuit-board:before { content: "\eabe" } +.codicon-clear-all:before { content: "\eabf" } +.codicon-clippy:before { content: "\eac0" } +.codicon-close-all:before { content: "\eac1" } +.codicon-cloud-download:before { content: "\eac2" } +.codicon-cloud-upload:before { content: "\eac3" } +.codicon-code:before { content: "\eac4" } +.codicon-collapse-all:before { content: "\eac5" } +.codicon-color-mode:before { content: "\eac6" } +.codicon-comment-discussion:before { content: "\eac7" } +.codicon-compare-changes:before { content: "\eac8" } +.codicon-credit-card:before { content: "\eac9" } +.codicon-current-and-breakpoint:before { content: "\eaca" } +.codicon-current:before { content: "\eacb" } +.codicon-dash:before { content: "\eacc" } +.codicon-dashboard:before { content: "\eacd" } +.codicon-database:before { content: "\eace" } +.codicon-debug-continue:before { content: "\eacf" } +.codicon-debug-disconnect:before { content: "\ead0" } +.codicon-debug-pause:before { content: "\ead1" } +.codicon-debug-restart:before { content: "\ead2" } +.codicon-debug-start:before { content: "\ead3" } +.codicon-debug-step-into:before { content: "\ead4" } +.codicon-debug-step-out:before { content: "\ead5" } +.codicon-debug-step-over:before { content: "\ead6" } +.codicon-debug-stop:before { content: "\ead7" } +.codicon-debug:before { content: "\ead8" } +.codicon-device-camera-video:before { content: "\ead9" } +.codicon-device-camera:before { content: "\eada" } +.codicon-device-mobile:before { content: "\eadb" } +.codicon-diff-added:before { content: "\eadc" } +.codicon-diff-ignored:before { content: "\eadd" } +.codicon-diff-modified:before { content: "\eade" } +.codicon-diff-removed:before { content: "\eadf" } +.codicon-diff-renamed:before { content: "\eae0" } +.codicon-diff:before { content: "\eae1" } +.codicon-discard:before { content: "\eae2" } +.codicon-editor-layout:before { content: "\eae3" } +.codicon-empty-window:before { content: "\eae4" } +.codicon-exclude:before { content: "\eae5" } +.codicon-extensions:before { content: "\eae6" } +.codicon-eye-closed:before { content: "\eae7" } +.codicon-file-binary:before { content: "\eae8" } +.codicon-file-code:before { content: "\eae9" } +.codicon-file-media:before { content: "\eaea" } +.codicon-file-pdf:before { content: "\eaeb" } +.codicon-file-submodule:before { content: "\eaec" } +.codicon-file-symlink-directory:before { content: "\eaed" } +.codicon-file-symlink-file:before { content: "\eaee" } +.codicon-file-zip:before { content: "\eaef" } +.codicon-files:before { content: "\eaf0" } +.codicon-filter:before { content: "\eaf1" } +.codicon-flame:before { content: "\eaf2" } +.codicon-fold-down:before { content: "\eaf3" } +.codicon-fold-up:before { content: "\eaf4" } +.codicon-fold:before { content: "\eaf5" } +.codicon-folder-active:before { content: "\eaf6" } +.codicon-folder-opened:before { content: "\eaf7" } +.codicon-gear:before { content: "\eaf8" } +.codicon-gift:before { content: "\eaf9" } +.codicon-gist-secret:before { content: "\eafa" } +.codicon-gist:before { content: "\eafb" } +.codicon-git-commit:before { content: "\eafc" } +.codicon-git-compare:before { content: "\eafd" } +.codicon-git-merge:before { content: "\eafe" } +.codicon-github-action:before { content: "\eaff" } +.codicon-github-alt:before { content: "\eb00" } +.codicon-globe:before { content: "\eb01" } +.codicon-grabber:before { content: "\eb02" } +.codicon-graph:before { content: "\eb03" } +.codicon-gripper:before { content: "\eb04" } +.codicon-heart:before { content: "\eb05" } +.codicon-home:before { content: "\eb06" } +.codicon-horizontal-rule:before { content: "\eb07" } +.codicon-hubot:before { content: "\eb08" } +.codicon-inbox:before { content: "\eb09" } +.codicon-issue-closed:before { content: "\eb0a" } +.codicon-issue-reopened:before { content: "\eb0b" } +.codicon-issues:before { content: "\eb0c" } +.codicon-italic:before { content: "\eb0d" } +.codicon-jersey:before { content: "\eb0e" } +.codicon-json:before { content: "\eb0f" } +.codicon-kebab-vertical:before { content: "\eb10" } +.codicon-key:before { content: "\eb11" } +.codicon-law:before { content: "\eb12" } +.codicon-lightbulb-autofix:before { content: "\eb13" } +.codicon-link-external:before { content: "\eb14" } +.codicon-link:before { content: "\eb15" } +.codicon-list-ordered:before { content: "\eb16" } +.codicon-list-unordered:before { content: "\eb17" } +.codicon-live-share:before { content: "\eb18" } +.codicon-loading:before { content: "\eb19" } +.codicon-location:before { content: "\eb1a" } +.codicon-mail-read:before { content: "\eb1b" } +.codicon-mail:before { content: "\eb1c" } +.codicon-markdown:before { content: "\eb1d" } +.codicon-megaphone:before { content: "\eb1e" } +.codicon-mention:before { content: "\eb1f" } +.codicon-milestone:before { content: "\eb20" } +.codicon-mortar-board:before { content: "\eb21" } +.codicon-move:before { content: "\eb22" } +.codicon-multiple-windows:before { content: "\eb23" } +.codicon-mute:before { content: "\eb24" } +.codicon-no-newline:before { content: "\eb25" } +.codicon-note:before { content: "\eb26" } +.codicon-octoface:before { content: "\eb27" } +.codicon-open-preview:before { content: "\eb28" } +.codicon-package:before { content: "\eb29" } +.codicon-paintcan:before { content: "\eb2a" } +.codicon-pin:before { content: "\eb2b" } +.codicon-play:before { content: "\eb2c" } +.codicon-plug:before { content: "\eb2d" } +.codicon-preserve-case:before { content: "\eb2e" } +.codicon-preview:before { content: "\eb2f" } +.codicon-project:before { content: "\eb30" } +.codicon-pulse:before { content: "\eb31" } +.codicon-question:before { content: "\eb32" } +.codicon-quote:before { content: "\eb33" } +.codicon-radio-tower:before { content: "\eb34" } +.codicon-reactions:before { content: "\eb35" } +.codicon-references:before { content: "\eb36" } +.codicon-refresh:before { content: "\eb37" } +.codicon-regex:before { content: "\eb38" } +.codicon-remote-explorer:before { content: "\eb39" } +.codicon-remote:before { content: "\eb3a" } +.codicon-remove:before { content: "\eb3b" } +.codicon-replace-all:before { content: "\eb3c" } +.codicon-replace:before { content: "\eb3d" } +.codicon-repo-clone:before { content: "\eb3e" } +.codicon-repo-force-push:before { content: "\eb3f" } +.codicon-repo-pull:before { content: "\eb40" } +.codicon-repo-push:before { content: "\eb41" } +.codicon-report:before { content: "\eb42" } +.codicon-request-changes:before { content: "\eb43" } +.codicon-rocket:before { content: "\eb44" } +.codicon-root-folder-opened:before { content: "\eb45" } +.codicon-root-folder:before { content: "\eb46" } +.codicon-rss:before { content: "\eb47" } +.codicon-ruby:before { content: "\eb48" } +.codicon-save-all:before { content: "\eb49" } +.codicon-save-as:before { content: "\eb4a" } +.codicon-save:before { content: "\eb4b" } +.codicon-screen-full:before { content: "\eb4c" } +.codicon-screen-normal:before { content: "\eb4d" } +.codicon-search-stop:before { content: "\eb4e" } +.codicon-selection:before { content: "\eb4f" } +.codicon-server:before { content: "\eb50" } +.codicon-settings-gear:before { content: "\eb51" } +.codicon-settings:before { content: "\eb52" } +.codicon-shield:before { content: "\eb53" } +.codicon-smiley:before { content: "\eb54" } +.codicon-sort-precedence:before { content: "\eb55" } +.codicon-split-horizontal:before { content: "\eb56" } +.codicon-split-vertical:before { content: "\eb57" } +.codicon-squirrel:before { content: "\eb58" } +.codicon-star-full:before { content: "\eb59" } +.codicon-star-half:before { content: "\eb5a" } +.codicon-symbol-class:before { content: "\eb5b" } +.codicon-symbol-color:before { content: "\eb5c" } +.codicon-symbol-constant:before { content: "\eb5d" } +.codicon-symbol-enum-member:before { content: "\eb5e" } +.codicon-symbol-field:before { content: "\eb5f" } +.codicon-symbol-file:before { content: "\eb60" } +.codicon-symbol-interface:before { content: "\eb61" } +.codicon-symbol-keyword:before { content: "\eb62" } +.codicon-symbol-misc:before { content: "\eb63" } +.codicon-symbol-operator:before { content: "\eb64" } +.codicon-symbol-property:before { content: "\eb65" } +.codicon-symbol-snippet:before { content: "\eb66" } +.codicon-tasklist:before { content: "\eb67" } +.codicon-telescope:before { content: "\eb68" } +.codicon-text-size:before { content: "\eb69" } +.codicon-three-bars:before { content: "\eb6a" } +.codicon-thumbsdown:before { content: "\eb6b" } +.codicon-thumbsup:before { content: "\eb6c" } +.codicon-tools:before { content: "\eb6d" } +.codicon-triangle-down:before { content: "\eb6e" } +.codicon-triangle-left:before { content: "\eb6f" } +.codicon-triangle-right:before { content: "\eb70" } +.codicon-triangle-up:before { content: "\eb71" } +.codicon-twitter:before { content: "\eb72" } +.codicon-unfold:before { content: "\eb73" } +.codicon-unlock:before { content: "\eb74" } +.codicon-unmute:before { content: "\eb75" } +.codicon-unverified:before { content: "\eb76" } +.codicon-verified:before { content: "\eb77" } +.codicon-versions:before { content: "\eb78" } +.codicon-vm-active:before { content: "\eb79" } +.codicon-vm-outline:before { content: "\eb7a" } +.codicon-vm-running:before { content: "\eb7b" } +.codicon-watch:before { content: "\eb7c" } +.codicon-whitespace:before { content: "\eb7d" } +.codicon-whole-word:before { content: "\eb7e" } +.codicon-window:before { content: "\eb7f" } +.codicon-word-wrap:before { content: "\eb80" } +.codicon-zoom-in:before { content: "\eb81" } +.codicon-zoom-out:before { content: "\f101" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index fff7ab51978..9726457a235 100644 Binary files a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf and b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf differ diff --git a/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts b/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts index 42d38948e88..e496fd3a164 100644 --- a/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts +++ b/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts @@ -8,7 +8,7 @@ import 'vs/css!./codicon/codicon-animations'; import { escape } from 'vs/base/common/strings'; function expand(text: string): string { - return text.replace(/\$\(((.+?)(~(.*?))?)\)/g, (_match, _g1, name, _g3, animation) => { + return text.replace(/\$\((([a-z0-9\-]+?)(~([a-z0-9\-]*?))?)\)/gi, (_match, _g1, name, _g3, animation) => { return ``; }); } diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 8b8bb3b16eb..098e8b03182 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -263,7 +263,7 @@ export class ContextView extends Disposable { const delegate = this.delegate; this.delegate = null; - if (delegate && delegate.onHide) { + if (delegate?.onHide) { delegate.onHide(data); } diff --git a/src/vs/base/browser/ui/countBadge/countBadge.ts b/src/vs/base/browser/ui/countBadge/countBadge.ts index e4b1f68568f..cb04c5099f3 100644 --- a/src/vs/base/browser/ui/countBadge/countBadge.ts +++ b/src/vs/base/browser/ui/countBadge/countBadge.ts @@ -85,15 +85,15 @@ export class CountBadge { private applyStyles(): void { if (this.element) { - const background = this.badgeBackground ? this.badgeBackground.toString() : null; - const foreground = this.badgeForeground ? this.badgeForeground.toString() : null; - const border = this.badgeBorder ? this.badgeBorder.toString() : null; + const background = this.badgeBackground ? this.badgeBackground.toString() : ''; + const foreground = this.badgeForeground ? this.badgeForeground.toString() : ''; + const border = this.badgeBorder ? this.badgeBorder.toString() : ''; this.element.style.backgroundColor = background; this.element.style.color = foreground; - this.element.style.borderWidth = border ? '1px' : null; - this.element.style.borderStyle = border ? 'solid' : null; + this.element.style.borderWidth = border ? '1px' : ''; + this.element.style.borderStyle = border ? 'solid' : ''; this.element.style.borderColor = border; } } diff --git a/src/vs/base/browser/ui/dialog/dialog.css b/src/vs/base/browser/ui/dialog/dialog.css index 83d8d7eca66..1ee1c9860cc 100644 --- a/src/vs/base/browser/ui/dialog/dialog.css +++ b/src/vs/base/browser/ui/dialog/dialog.css @@ -123,6 +123,8 @@ text-overflow: ellipsis; padding-left: 20px; user-select: text; + -webkit-user-select: text; + -ms-user-select: text; word-wrap: break-word; /* never overflow long words, but break to next line */ white-space: normal; } @@ -154,6 +156,13 @@ display: flex; } +.monaco-workbench .dialog-box .dialog-message-row .dialog-message-container .dialog-checkbox-row .dialog-checkbox-message { + cursor: pointer; + user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} + /** Dialog: Buttons Row */ .monaco-workbench .dialog-box > .dialog-buttons-row { display: flex; @@ -175,7 +184,8 @@ } .monaco-workbench .dialog-box > .dialog-buttons-row > .dialog-buttons > .monaco-button { - max-width: fit-content; + width: fit-content; + width: -moz-fit-content; padding: 5px 10px; margin: 4px 5px; /* allows button focus outline to be visible */ overflow: hidden; diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index b3c43c0794c..cc3e823d5c4 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -6,7 +6,7 @@ import 'vs/css!./dialog'; import * as nls from 'vs/nls'; import { Disposable } from 'vs/base/common/lifecycle'; -import { $, hide, show, EventHelper, clearNode, removeClasses, addClass, removeNode, isAncestor } from 'vs/base/browser/dom'; +import { $, hide, show, EventHelper, clearNode, removeClasses, addClass, removeNode, isAncestor, addDisposableListener, EventType } from 'vs/base/browser/dom'; import { domEvent } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; @@ -84,12 +84,13 @@ export class Dialog extends Disposable { if (this.options.checkboxLabel) { const checkboxRowElement = messageContainer.appendChild($('.dialog-checkbox-row')); - this.checkbox = this._register(new SimpleCheckbox(this.options.checkboxLabel, !!this.options.checkboxChecked)); + const checkbox = this.checkbox = this._register(new SimpleCheckbox(this.options.checkboxLabel, !!this.options.checkboxChecked)); - checkboxRowElement.appendChild(this.checkbox.domNode); + checkboxRowElement.appendChild(checkbox.domNode); const checkboxMessageElement = checkboxRowElement.appendChild($('.dialog-checkbox-message')); checkboxMessageElement.innerText = this.options.checkboxLabel; + this._register(addDisposableListener(checkboxMessageElement, EventType.CLICK, () => checkbox.checked = !checkbox.checked)); } const toolbarRowElement = this.element.appendChild($('.dialog-toolbar-row')); @@ -142,7 +143,9 @@ export class Dialog extends Disposable { let eventHandled = false; if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) { if (!this.checkboxHasFocus && focusedButton === 0) { - this.checkbox!.domNode.focus(); + if (this.checkbox) { + this.checkbox.domNode.focus(); + } this.checkboxHasFocus = true; } else { focusedButton = (this.checkboxHasFocus ? 0 : focusedButton) + buttonGroup.buttons.length - 1; @@ -154,7 +157,9 @@ export class Dialog extends Disposable { eventHandled = true; } else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) { if (!this.checkboxHasFocus && focusedButton === buttonGroup.buttons.length - 1) { - this.checkbox!.domNode.focus(); + if (this.checkbox) { + this.checkbox.domNode.focus(); + } this.checkboxHasFocus = true; } else { focusedButton = this.checkboxHasFocus ? 0 : focusedButton + 1; @@ -237,10 +242,10 @@ export class Dialog extends Disposable { if (this.styles) { const style = this.styles; - const fgColor = style.dialogForeground ? `${style.dialogForeground}` : null; - const bgColor = style.dialogBackground ? `${style.dialogBackground}` : null; - const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : null; - const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : null; + const fgColor = style.dialogForeground ? `${style.dialogForeground}` : ''; + const bgColor = style.dialogBackground ? `${style.dialogBackground}` : ''; + const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : ''; + const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : ''; if (this.element) { this.element.style.color = fgColor; diff --git a/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts index 4390ad2ff27..c36015f710b 100644 --- a/src/vs/base/browser/ui/dropdown/dropdown.ts +++ b/src/vs/base/browser/ui/dropdown/dropdown.ts @@ -83,7 +83,7 @@ export class BaseDropdown extends ActionRunner { this._register(cleanupFn); } - Gesture.addTarget(this._label); + this._register(Gesture.addTarget(this._label)); } get element(): HTMLElement { @@ -208,8 +208,8 @@ export interface IDropdownMenuOptions extends IBaseDropdownOptions { export class DropdownMenu extends BaseDropdown { private _contextMenuProvider: IContextMenuProvider; - private _menuOptions: IMenuOptions; - private _actions: ReadonlyArray; + private _menuOptions: IMenuOptions | undefined; + private _actions: ReadonlyArray = []; private actionProvider?: IActionProvider; private menuClassName: string; @@ -222,11 +222,11 @@ export class DropdownMenu extends BaseDropdown { this.menuClassName = options.menuClassName || ''; } - set menuOptions(options: IMenuOptions) { + set menuOptions(options: IMenuOptions | undefined) { this._menuOptions = options; } - get menuOptions(): IMenuOptions { + get menuOptions(): IMenuOptions | undefined { return this._menuOptions; } @@ -256,7 +256,7 @@ export class DropdownMenu extends BaseDropdown { getMenuClassName: () => this.menuClassName, onHide: () => this.onHide(), actionRunner: this.menuOptions ? this.menuOptions.actionRunner : undefined, - anchorAlignment: this.menuOptions.anchorAlignment + anchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : AnchorAlignment.LEFT }); } @@ -345,7 +345,11 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { super.setActionContext(newContext); if (this.dropdownMenu) { - this.dropdownMenu.menuOptions.context = newContext; + if (this.dropdownMenu.menuOptions) { + this.dropdownMenu.menuOptions.context = newContext; + } else { + this.dropdownMenu.menuOptions = { context: newContext }; + } } } diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts index fcc27e402a7..4c5392c87dc 100644 --- a/src/vs/base/browser/ui/findinput/findInput.ts +++ b/src/vs/base/browser/ui/findinput/findInput.ts @@ -396,30 +396,18 @@ export class FindInput extends Widget { } public validate(): void { - if (this.inputBox) { - this.inputBox.validate(); - } + this.inputBox.validate(); } public showMessage(message: InputBoxMessage): void { - if (this.inputBox) { - this.inputBox.showMessage(message); - } + this.inputBox.showMessage(message); } public clearMessage(): void { - if (this.inputBox) { - this.inputBox.hideMessage(); - } + this.inputBox.hideMessage(); } private clearValidation(): void { - if (this.inputBox) { - this.inputBox.hideMessage(); - } - } - - public dispose(): void { - super.dispose(); + this.inputBox.hideMessage(); } } diff --git a/src/vs/base/browser/ui/findinput/replaceInput.ts b/src/vs/base/browser/ui/findinput/replaceInput.ts index de448b6a484..5950e261de4 100644 --- a/src/vs/base/browser/ui/findinput/replaceInput.ts +++ b/src/vs/base/browser/ui/findinput/replaceInput.ts @@ -123,11 +123,96 @@ export class ReplaceInput extends Widget { this.inputValidationErrorBackground = options.inputValidationErrorBackground; this.inputValidationErrorForeground = options.inputValidationErrorForeground; + const history = options.history || []; const flexibleHeight = !!options.flexibleHeight; const flexibleWidth = !!options.flexibleWidth; const flexibleMaxHeight = options.flexibleMaxHeight; - this.buildDomNode(options.history || [], flexibleHeight, flexibleWidth, flexibleMaxHeight); + this.domNode = document.createElement('div'); + dom.addClass(this.domNode, 'monaco-findInput'); + + this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, { + ariaLabel: this.label || '', + placeholder: this.placeholder || '', + validationOptions: { + validation: this.validation + }, + inputBackground: this.inputBackground, + inputForeground: this.inputForeground, + inputBorder: this.inputBorder, + inputValidationInfoBackground: this.inputValidationInfoBackground, + inputValidationInfoForeground: this.inputValidationInfoForeground, + inputValidationInfoBorder: this.inputValidationInfoBorder, + inputValidationWarningBackground: this.inputValidationWarningBackground, + inputValidationWarningForeground: this.inputValidationWarningForeground, + inputValidationWarningBorder: this.inputValidationWarningBorder, + inputValidationErrorBackground: this.inputValidationErrorBackground, + inputValidationErrorForeground: this.inputValidationErrorForeground, + inputValidationErrorBorder: this.inputValidationErrorBorder, + history, + flexibleHeight, + flexibleWidth, + flexibleMaxHeight + })); + + this.preserveCase = this._register(new PreserveCaseCheckbox({ + appendTitle: '', + isChecked: false, + inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground, + })); + this._register(this.preserveCase.onChange(viaKeyboard => { + this._onDidOptionChange.fire(viaKeyboard); + if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) { + this.inputBox.focus(); + } + this.validate(); + })); + this._register(this.preserveCase.onKeyDown(e => { + this._onPreserveCaseKeyDown.fire(e); + })); + + if (this._showOptionButtons) { + this.cachedOptionsWidth = this.preserveCase.width(); + } else { + this.cachedOptionsWidth = 0; + } + + // Arrow-Key support to navigate between options + let indexes = [this.preserveCase.domNode]; + this.onkeydown(this.domNode, (event: IKeyboardEvent) => { + if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) { + let index = indexes.indexOf(document.activeElement); + if (index >= 0) { + let newIndex: number = -1; + if (event.equals(KeyCode.RightArrow)) { + newIndex = (index + 1) % indexes.length; + } else if (event.equals(KeyCode.LeftArrow)) { + if (index === 0) { + newIndex = indexes.length - 1; + } else { + newIndex = index - 1; + } + } + + if (event.equals(KeyCode.Escape)) { + indexes[index].blur(); + } else if (newIndex >= 0) { + indexes[newIndex].focus(); + } + + dom.EventHelper.stop(event, true); + } + } + }); + + + let controls = document.createElement('div'); + controls.className = 'controls'; + controls.style.display = this._showOptionButtons ? 'block' : 'none'; + controls.appendChild(this.preserveCase.domNode); + + this.domNode.appendChild(controls); if (parent) { parent.appendChild(this.domNode); @@ -256,94 +341,6 @@ export class ReplaceInput extends Widget { dom.addClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions)); } - private buildDomNode(history: string[], flexibleHeight: boolean, flexibleWidth: boolean, flexibleMaxHeight: number | undefined): void { - this.domNode = document.createElement('div'); - dom.addClass(this.domNode, 'monaco-findInput'); - - this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, { - ariaLabel: this.label || '', - placeholder: this.placeholder || '', - validationOptions: { - validation: this.validation - }, - inputBackground: this.inputBackground, - inputForeground: this.inputForeground, - inputBorder: this.inputBorder, - inputValidationInfoBackground: this.inputValidationInfoBackground, - inputValidationInfoForeground: this.inputValidationInfoForeground, - inputValidationInfoBorder: this.inputValidationInfoBorder, - inputValidationWarningBackground: this.inputValidationWarningBackground, - inputValidationWarningForeground: this.inputValidationWarningForeground, - inputValidationWarningBorder: this.inputValidationWarningBorder, - inputValidationErrorBackground: this.inputValidationErrorBackground, - inputValidationErrorForeground: this.inputValidationErrorForeground, - inputValidationErrorBorder: this.inputValidationErrorBorder, - history, - flexibleHeight, - flexibleWidth, - flexibleMaxHeight - })); - - this.preserveCase = this._register(new PreserveCaseCheckbox({ - appendTitle: '', - isChecked: false, - inputActiveOptionBorder: this.inputActiveOptionBorder, - inputActiveOptionBackground: this.inputActiveOptionBackground, - })); - this._register(this.preserveCase.onChange(viaKeyboard => { - this._onDidOptionChange.fire(viaKeyboard); - if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) { - this.inputBox.focus(); - } - this.validate(); - })); - this._register(this.preserveCase.onKeyDown(e => { - this._onPreserveCaseKeyDown.fire(e); - })); - - if (this._showOptionButtons) { - this.cachedOptionsWidth = this.preserveCase.width(); - } else { - this.cachedOptionsWidth = 0; - } - - // Arrow-Key support to navigate between options - let indexes = [this.preserveCase.domNode]; - this.onkeydown(this.domNode, (event: IKeyboardEvent) => { - if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) { - let index = indexes.indexOf(document.activeElement); - if (index >= 0) { - let newIndex: number = -1; - if (event.equals(KeyCode.RightArrow)) { - newIndex = (index + 1) % indexes.length; - } else if (event.equals(KeyCode.LeftArrow)) { - if (index === 0) { - newIndex = indexes.length - 1; - } else { - newIndex = index - 1; - } - } - - if (event.equals(KeyCode.Escape)) { - indexes[index].blur(); - } else if (newIndex >= 0) { - indexes[newIndex].focus(); - } - - dom.EventHelper.stop(event, true); - } - } - }); - - - let controls = document.createElement('div'); - controls.className = 'controls'; - controls.style.display = this._showOptionButtons ? 'block' : 'none'; - controls.appendChild(this.preserveCase.domNode); - - this.domNode.appendChild(controls); - } - public validate(): void { if (this.inputBox) { this.inputBox.validate(); diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 28b184f76d9..c2448a2fbff 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -9,7 +9,6 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { tail2 as tail, equals } from 'vs/base/common/arrays'; import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, IGridViewOptions } from './gridview'; import { Event } from 'vs/base/common/event'; -import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview'; export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview'; diff --git a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts index e7dcf431b0d..701d3a6a785 100644 --- a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts +++ b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts @@ -15,15 +15,15 @@ export interface IHighlight { export class HighlightedLabel { private domNode: HTMLElement; - private text: string; - private title: string; - private highlights: IHighlight[]; - private didEverRender: boolean; + private text: string = ''; + private title: string = ''; + private highlights: IHighlight[] = []; + private didEverRender: boolean = false; - constructor(container: HTMLElement, private supportOcticons: boolean) { + constructor(container: HTMLElement, private supportCodicons: boolean) { this.domNode = document.createElement('span'); this.domNode.className = 'monaco-highlighted-label'; - this.didEverRender = false; + container.appendChild(this.domNode); } @@ -65,13 +65,13 @@ export class HighlightedLabel { if (pos < highlight.start) { htmlContent += ''; const substring = this.text.substring(pos, highlight.start); - htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring); + htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring); htmlContent += ''; pos = highlight.end; } htmlContent += ''; const substring = this.text.substring(highlight.start, highlight.end); - htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring); + htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring); htmlContent += ''; pos = highlight.end; } @@ -79,7 +79,7 @@ export class HighlightedLabel { if (pos < this.text.length) { htmlContent += ''; const substring = this.text.substring(pos); - htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring); + htmlContent += this.supportCodicons ? renderCodicons(substring) : escape(substring); htmlContent += ''; } diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index b9fc4154234..69315ea919a 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -12,7 +12,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; export interface IIconLabelCreationOptions { supportHighlights?: boolean; supportDescriptionHighlights?: boolean; - supportOcticons?: boolean; + supportCodicons?: boolean; } export interface IIconLabelValueOptions { @@ -77,7 +77,7 @@ class FastLabelNode { } this._empty = empty; - this._element.style.marginLeft = empty ? '0' : null; + this._element.style.marginLeft = empty ? '0' : ''; } dispose(): void { @@ -99,14 +99,14 @@ export class IconLabel extends Disposable { this.labelDescriptionContainer = this._register(new FastLabelNode(dom.append(this.domNode.element, dom.$('.monaco-icon-label-description-container')))); - if (options && options.supportHighlights) { - this.labelNode = new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name')), !!options.supportOcticons); + if (options?.supportHighlights) { + this.labelNode = new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name')), !!options.supportCodicons); } else { this.labelNode = this._register(new FastLabelNode(dom.append(this.labelDescriptionContainer.element, dom.$('a.label-name')))); } - if (options && options.supportDescriptionHighlights) { - this.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description')), !!options.supportOcticons); + if (options?.supportDescriptionHighlights) { + this.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description')), !!options.supportCodicons); } else { this.descriptionNodeFactory = () => this._register(new FastLabelNode(dom.append(this.labelDescriptionContainer.element, dom.$('span.label-description')))); } @@ -129,10 +129,10 @@ export class IconLabel extends Disposable { } this.domNode.className = classes.join(' '); - this.domNode.title = options && options.title ? options.title : ''; + this.domNode.title = options?.title || ''; if (this.labelNode instanceof HighlightedLabel) { - this.labelNode.set(label || '', options ? options.matches : undefined, options && options.title ? options.title : undefined, options && options.labelEscapeNewLines); + this.labelNode.set(label || '', options?.matches, options?.title, options?.labelEscapeNewLines); } else { this.labelNode.textContent = label || ''; } @@ -144,14 +144,14 @@ export class IconLabel extends Disposable { if (this.descriptionNode instanceof HighlightedLabel) { this.descriptionNode.set(description || '', options ? options.descriptionMatches : undefined); - if (options && options.descriptionTitle) { + if (options?.descriptionTitle) { this.descriptionNode.element.title = options.descriptionTitle; } else { this.descriptionNode.element.removeAttribute('title'); } } else { this.descriptionNode.textContent = description || ''; - this.descriptionNode.title = options && options.descriptionTitle ? options.descriptionTitle : ''; + this.descriptionNode.title = options?.descriptionTitle || ''; this.descriptionNode.empty = !description; } } diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index 651843fcc93..ad21f0ae1e4 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -20,10 +20,12 @@ padding-right: 6px; width: 16px; height: 22px; + line-height: inherit !important; display: inline-block; /* fonts icons */ -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; vertical-align: top; flex-shrink: 0; /* fix for https://github.com/Microsoft/vscode/issues/13787 */ @@ -55,7 +57,7 @@ opacity: 0.75; font-size: 90%; font-weight: 600; - padding: 0 12px 0 5px; + padding: 0 16px 0 5px; margin-left: auto; text-align: center; } @@ -74,4 +76,4 @@ .monaco-list-row.focused.selected .label-description, .monaco-list-row.selected .label-description { opacity: .8; -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/inputbox/inputBox.css b/src/vs/base/browser/ui/inputbox/inputBox.css index 939d0cb5f01..83410d453cb 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.css +++ b/src/vs/base/browser/ui/inputbox/inputBox.css @@ -7,12 +7,7 @@ position: relative; display: block; padding: 0; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - line-height: auto !important; + box-sizing: border-box; /* Customizable */ font-size: inherit; @@ -37,11 +32,7 @@ .monaco-inputbox > .wrapper > .input { display: inline-block; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; width: 100%; height: 100%; line-height: inherit; @@ -78,11 +69,7 @@ width: 100%; top: 0; left: 0; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; white-space: pre-wrap; visibility: hidden; word-wrap: break-word; @@ -99,11 +86,7 @@ overflow: hidden; text-align: left; width: 100%; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; padding: 0.4em; font-size: 12px; line-height: 17px; diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index d7d3b1217b0..59dd50015d8 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -189,7 +189,7 @@ export class InputBox extends Widget { const onSelectionChange = Event.filter(domEvent(document, 'selectionchange'), () => { const selection = document.getSelection(); - return !!selection && selection.anchorNode === wrapper; + return selection?.anchorNode === wrapper; }); // from DOM to ScrollableElement @@ -351,7 +351,7 @@ export class InputBox extends Widget { } private updateScrollDimensions(): void { - if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number') { + if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number' || !this.scrollableElement) { return; } @@ -359,8 +359,8 @@ export class InputBox extends Widget { const height = this.cachedHeight; const scrollTop = this.input.scrollTop; - this.scrollableElement!.setScrollDimensions({ scrollHeight, height }); - this.scrollableElement!.setScrollPosition({ scrollTop }); + this.scrollableElement.setScrollDimensions({ scrollHeight, height }); + this.scrollableElement.setScrollPosition({ scrollTop }); } public showMessage(message: IMessage, force?: boolean): void { @@ -373,7 +373,7 @@ export class InputBox extends Widget { dom.addClass(this.element, this.classForType(message.type)); const styles = this.stylesForType(this.message.type); - this.element.style.border = styles.border ? `1px solid ${styles.border}` : null; + this.element.style.border = styles.border ? `1px solid ${styles.border}` : ''; // ARIA Support let alertText: string; @@ -473,9 +473,9 @@ export class InputBox extends Widget { dom.addClass(spanElement, this.classForType(this.message.type)); const styles = this.stylesForType(this.message.type); - spanElement.style.backgroundColor = styles.background ? styles.background.toString() : null; + spanElement.style.backgroundColor = styles.background ? styles.background.toString() : ''; spanElement.style.color = styles.foreground ? styles.foreground.toString() : null; - spanElement.style.border = styles.border ? `1px solid ${styles.border}` : null; + spanElement.style.border = styles.border ? `1px solid ${styles.border}` : ''; dom.append(div, spanElement); @@ -552,17 +552,17 @@ export class InputBox extends Widget { } protected applyStyles(): void { - const background = this.inputBackground ? this.inputBackground.toString() : null; - const foreground = this.inputForeground ? this.inputForeground.toString() : null; - const border = this.inputBorder ? this.inputBorder.toString() : null; + const background = this.inputBackground ? this.inputBackground.toString() : ''; + const foreground = this.inputForeground ? this.inputForeground.toString() : ''; + const border = this.inputBorder ? this.inputBorder.toString() : ''; this.element.style.backgroundColor = background; this.element.style.color = foreground; this.input.style.backgroundColor = background; this.input.style.color = foreground; - this.element.style.borderWidth = border ? '1px' : null; - this.element.style.borderStyle = border ? 'solid' : null; + this.element.style.borderWidth = border ? '1px' : ''; + this.element.style.borderStyle = border ? 'solid' : ''; this.element.style.borderColor = border; } diff --git a/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts b/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts index e9fdc86be15..13abc51d992 100644 --- a/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts +++ b/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts @@ -80,20 +80,20 @@ export class KeybindingLabel { private renderPart(parent: HTMLElement, part: ResolvedKeybindingPart, match: PartMatches | null) { const modifierLabels = UILabelProvider.modifierLabels[this.os]; if (part.ctrlKey) { - this.renderKey(parent, modifierLabels.ctrlKey, Boolean(match && match.ctrlKey), modifierLabels.separator); + this.renderKey(parent, modifierLabels.ctrlKey, Boolean(match?.ctrlKey), modifierLabels.separator); } if (part.shiftKey) { - this.renderKey(parent, modifierLabels.shiftKey, Boolean(match && match.shiftKey), modifierLabels.separator); + this.renderKey(parent, modifierLabels.shiftKey, Boolean(match?.shiftKey), modifierLabels.separator); } if (part.altKey) { - this.renderKey(parent, modifierLabels.altKey, Boolean(match && match.altKey), modifierLabels.separator); + this.renderKey(parent, modifierLabels.altKey, Boolean(match?.altKey), modifierLabels.separator); } if (part.metaKey) { - this.renderKey(parent, modifierLabels.metaKey, Boolean(match && match.metaKey), modifierLabels.separator); + this.renderKey(parent, modifierLabels.metaKey, Boolean(match?.metaKey), modifierLabels.separator); } const keyLabel = part.keyLabel; if (keyLabel) { - this.renderKey(parent, keyLabel, Boolean(match && match.keyCode), ''); + this.renderKey(parent, keyLabel, Boolean(match?.keyCode), ''); } } diff --git a/src/vs/base/browser/ui/list/list.css b/src/vs/base/browser/ui/list/list.css index 1c1fa4c8223..1bf13b4ce11 100644 --- a/src/vs/base/browser/ui/list/list.css +++ b/src/vs/base/browser/ui/list/list.css @@ -11,12 +11,9 @@ } .monaco-list.mouse-support { - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: -moz-none; - -ms-user-select: none; - -o-user-select: none; user-select: none; + -webkit-user-select: none; + -ms-user-select: none; } .monaco-list > .monaco-scrollable-element { @@ -36,10 +33,7 @@ .monaco-list-row { position: absolute; - -moz-box-sizing: border-box; - -o-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; overflow: hidden; width: 100%; } @@ -59,6 +53,10 @@ outline: 0 !important; } +.monaco-list:focus .monaco-list-row.selected .codicon { + color: inherit; +} + /* Dnd */ .monaco-drag-image { display: inline-block; @@ -124,6 +122,7 @@ .monaco-list-type-filter > .controls > .filter { -webkit-appearance: none; + -moz-appearance: none; width: 16px; height: 16px; background: url("media/no-filter-light.svg"); @@ -191,4 +190,4 @@ .monaco-list-type-filter.dragging { 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 bb60cd87193..076d78d7725 100644 --- a/src/vs/base/browser/ui/list/list.ts +++ b/src/vs/base/browser/ui/list/list.ts @@ -115,3 +115,19 @@ export class ListError extends Error { super(`ListError [${user}] ${message}`); } } + +export abstract class CachedListVirtualDelegate implements IListVirtualDelegate { + + private cache = new WeakMap(); + + getHeight(element: T): number { + return this.cache.get(element) ?? this.estimateHeight(element); + } + + protected abstract estimateHeight(element: T): number; + abstract getTemplateId(element: T): string; + + setDynamicHeight(element: T, height: number): void { + this.cache.set(element, height); + } +} diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 6f0ea59ff10..352dd6b8e34 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -155,6 +155,14 @@ export class PagedList implements IDisposable { this.list.scrollTop = scrollTop; } + get scrollLeft(): number { + return this.list.scrollLeft; + } + + set scrollLeft(scrollLeft: number) { + this.list.scrollLeft = scrollLeft; + } + open(indexes: number[], browserEvent?: UIEvent): void { this.list.open(indexes, browserEvent); } diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 0d2404422c8..620974cd757 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -14,14 +14,13 @@ import { ScrollEvent, ScrollbarVisibility, INewScrollDimensions } from 'vs/base/ import { RangeMap, shift } from './rangeMap'; import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListTouchEvent, IListGestureEvent, IListDragEvent, IListDragAndDrop, ListDragOverEffect } from './list'; import { RowCache, IRow } from './rowCache'; -import { isWindows } from 'vs/base/common/platform'; -import * as browser from 'vs/base/browser/browser'; import { ISpliceable } from 'vs/base/common/sequence'; import { memoize } from 'vs/base/common/decorators'; import { Range, IRange } from 'vs/base/common/range'; import { equals, distinct } from 'vs/base/common/arrays'; import { DataTransfers, StaticDND, IDragAndDropData } from 'vs/base/browser/dnd'; import { disposableTimeout, Delayer } from 'vs/base/common/async'; +import { isFirefox } from 'vs/base/browser/browser'; interface IItem { readonly id: string; @@ -179,7 +178,6 @@ export class ListView implements ISpliceable, IDisposable { private additionalScrollHeight: number; private ariaProvider: IAriaProvider; private scrollWidth: number | undefined; - private canUseTranslate3d: boolean | undefined = undefined; private dnd: IListViewDragAndDrop; private canDrop: boolean = false; @@ -236,7 +234,8 @@ export class ListView implements ISpliceable, IDisposable { this.rowsContainer = document.createElement('div'); this.rowsContainer.className = 'monaco-list-rows'; - Gesture.addTarget(this.rowsContainer); + this.rowsContainer.style.willChange = 'transform'; + this.disposables.add(Gesture.addTarget(this.rowsContainer)); this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, { alwaysConsumeMouseWheel: true, @@ -531,33 +530,13 @@ export class ListView implements ISpliceable, IDisposable { } } - const canUseTranslate3d = !isWindows && !browser.isFirefox && browser.getZoomLevel() === 0; - - if (canUseTranslate3d) { - const transform = `translate3d(-${renderLeft}px, -${renderTop}px, 0px)`; - this.rowsContainer.style.transform = transform; - this.rowsContainer.style.webkitTransform = transform; - - if (canUseTranslate3d !== this.canUseTranslate3d) { - this.rowsContainer.style.left = '0'; - this.rowsContainer.style.top = '0'; - } - } else { - this.rowsContainer.style.left = `-${renderLeft}px`; - this.rowsContainer.style.top = `-${renderTop}px`; - - if (canUseTranslate3d !== this.canUseTranslate3d) { - this.rowsContainer.style.transform = ''; - this.rowsContainer.style.webkitTransform = ''; - } - } + this.rowsContainer.style.left = `-${renderLeft}px`; + this.rowsContainer.style.top = `-${renderTop}px`; if (this.horizontalScrolling) { this.rowsContainer.style.width = `${Math.max(scrollWidth, this.renderWidth)}px`; } - this.canUseTranslate3d = canUseTranslate3d; - this.lastRenderTop = renderTop; this.lastRenderHeight = renderHeight; } @@ -617,7 +596,7 @@ export class ListView implements ISpliceable, IDisposable { return; } - item.row.domNode.style.width = 'fit-content'; + item.row.domNode.style.width = isFirefox ? '-moz-fit-content' : 'fit-content'; item.width = DOM.getContentWidth(item.row.domNode); const style = window.getComputedStyle(item.row.domNode); @@ -686,7 +665,7 @@ export class ListView implements ISpliceable, IDisposable { return scrollPosition.scrollLeft; } - setScrollLeftt(scrollLeft: number): void { + setScrollLeft(scrollLeft: number): void { if (this.scrollableElementUpdateDisposable) { this.scrollableElementUpdateDisposable.dispose(); this.scrollableElementUpdateDisposable = null; diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 51d1b8b0732..48a5214a0d2 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -542,7 +542,7 @@ export class MouseController implements IDisposable { list.onContextMenu(this.onContextMenu, this, this.disposables); list.onMouseDblClick(this.onDoubleClick, this, this.disposables); list.onTouchStart(this.onMouseDown, this, this.disposables); - Gesture.addTarget(list.getHTMLElement()); + this.disposables.add(Gesture.addTarget(list.getHTMLElement())); } list.onMouseClick(this.onPointer, this, this.disposables); @@ -822,7 +822,7 @@ export interface IListOptions extends IListStyles { readonly automaticKeyboardNavigation?: boolean; readonly keyboardNavigationLabelProvider?: IKeyboardNavigationLabelProvider; readonly keyboardNavigationDelegate?: IKeyboardNavigationDelegate; - readonly ariaRole?: ListAriaRootRole; + readonly ariaRole?: ListAriaRootRole | string; readonly ariaLabel?: string; readonly keyboardSupport?: boolean; readonly multipleSelectionSupport?: boolean; @@ -1198,11 +1198,7 @@ export class List implements ISpliceable, IDisposable { this.view = new ListView(container, virtualDelegate, renderers, viewOptions); - if (typeof _options.ariaRole !== 'string') { - this.view.domNode.setAttribute('role', ListAriaRootRole.TREE); - } else { - this.view.domNode.setAttribute('role', _options.ariaRole); - } + this.updateAriaRole(); this.styleElement = DOM.createStyleSheet(this.view.domNode); @@ -1316,7 +1312,7 @@ export class List implements ISpliceable, IDisposable { } set scrollLeft(scrollLeft: number) { - this.view.setScrollLeftt(scrollLeft); + this.view.setScrollLeft(scrollLeft); } get scrollHeight(): number { @@ -1537,7 +1533,9 @@ export class List implements ISpliceable, IDisposable { const viewItemBottom = elementTop + elementHeight; const wrapperBottom = scrollTop + this.view.renderHeight; - if (elementTop < scrollTop) { + if (elementTop < scrollTop && viewItemBottom >= wrapperBottom) { + // The element is already overflowing the viewport, no-op + } else if (elementTop < scrollTop) { this.view.setScrollTop(elementTop); } else if (viewItemBottom >= wrapperBottom) { this.view.setScrollTop(viewItemBottom - this.view.renderHeight); @@ -1612,10 +1610,19 @@ export class List implements ISpliceable, IDisposable { this.view.domNode.removeAttribute('aria-activedescendant'); } - this.view.domNode.setAttribute('role', 'tree'); + this.updateAriaRole(); + DOM.toggleClass(this.view.domNode, 'element-focused', focus.length > 0); } + private updateAriaRole(): void { + if (typeof this.options.ariaRole !== 'string') { + this.view.domNode.setAttribute('role', ListAriaRootRole.TREE); + } else { + this.view.domNode.setAttribute('role', this.options.ariaRole); + } + } + private _onSelectionChange(): void { const selection = this.selection.get(); diff --git a/src/vs/base/browser/ui/menu/menu.css b/src/vs/base/browser/ui/menu/menu.css index cbd6ce1a92e..77ed4987228 100644 --- a/src/vs/base/browser/ui/menu/menu.css +++ b/src/vs/base/browser/ui/menu/menu.css @@ -15,7 +15,6 @@ .monaco-menu .monaco-action-bar.vertical .action-item { padding: 0; transform: none; - display: -ms-flexbox; display: flex; } @@ -24,9 +23,7 @@ } .monaco-menu .monaco-action-bar.vertical .action-menu-item { - -ms-flex: 1 1 auto; flex: 1 1 auto; - display: -ms-flexbox; display: flex; height: 2em; align-items: center; @@ -34,7 +31,6 @@ } .monaco-menu .monaco-action-bar.vertical .action-label { - -ms-flex: 1 1 auto; flex: 1 1 auto; text-decoration: none; padding: 0 1em; @@ -46,7 +42,6 @@ .monaco-menu .monaco-action-bar.vertical .keybinding, .monaco-menu .monaco-action-bar.vertical .submenu-indicator { display: inline-block; - -ms-flex: 2 1 auto; flex: 2 1 auto; padding: 0 1em; text-align: right; @@ -56,8 +51,8 @@ .monaco-menu .monaco-action-bar.vertical .submenu-indicator { height: 100%; - -webkit-mask: url('submenu.svg') no-repeat 90% 50%/13px 13px; mask: url('submenu.svg') no-repeat 90% 50%/13px 13px; + -webkit-mask: url('submenu.svg') no-repeat 90% 50%/13px 13px; } .monaco-menu .monaco-action-bar.vertical .action-item.disabled .keybinding, @@ -67,11 +62,7 @@ .monaco-menu .monaco-action-bar.vertical .action-label:not(.separator) { display: inline-block; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; margin: 0; } @@ -80,7 +71,6 @@ overflow: visible; } - .monaco-menu .monaco-action-bar.vertical .action-item .monaco-submenu { position: absolute; } @@ -104,8 +94,8 @@ .monaco-menu .monaco-action-bar.vertical .menu-item-check { position: absolute; visibility: hidden; - -webkit-mask: url('check.svg') no-repeat 50% 56%/15px 15px; mask: url('check.svg') no-repeat 50% 56%/15px 15px; + -webkit-mask: url('check.svg') no-repeat 50% 56%/15px 15px; width: 1em; height: 100%; } @@ -119,10 +109,6 @@ .context-view.monaco-menu-container { outline: 0; border: none; - -webkit-animation: fadeIn 0.083s linear; - -o-animation: fadeIn 0.083s linear; - -moz-animation: fadeIn 0.083s linear; - -ms-animation: fadeIn 0.083s linear; animation: fadeIn 0.083s linear; } @@ -157,7 +143,7 @@ flex-wrap: wrap; } -.fullscreen .menubar { +.fullscreen .menubar:not(.compact) { margin: 0px; padding: 0px 5px; } @@ -173,6 +159,12 @@ outline: 0; } +.menubar.compact > .menubar-menu-button { + width: 100%; + height: 100%; + padding: 0px; +} + .menubar .menubar-menu-items-holder { position: absolute; left: 0px; @@ -197,9 +189,23 @@ height: 100%; } +.menubar.compact .toolbar-toggle-more { + background-position: center; + background-repeat: no-repeat; + background-size: 16px; + cursor: pointer; + width: 100%; + height: 100%; +} + .menubar .toolbar-toggle-more { display: inline-block; padding: 0; - -webkit-mask: url('ellipsis.svg') no-repeat 50% 55%/14px 14px; mask: url('ellipsis.svg') no-repeat 50% 55%/14px 14px; -} \ No newline at end of file + -webkit-mask: url('ellipsis.svg') no-repeat 50% 55%/14px 14px; +} + +.menubar.compact .toolbar-toggle-more { + mask: url('menu.svg') no-repeat 50% 55%/16px 16px; + -webkit-mask: url('menu.svg') no-repeat 50% 55%/16px 16px; +} diff --git a/src/vs/base/browser/ui/menu/menu.svg b/src/vs/base/browser/ui/menu/menu.svg new file mode 100644 index 00000000000..1b61c978229 --- /dev/null +++ b/src/vs/base/browser/ui/menu/menu.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 49d35fd57a8..affb18ccbe1 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -16,13 +16,18 @@ 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 { Event } from 'vs/base/common/event'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { isLinux, isMacintosh } from 'vs/base/common/platform'; export const MENU_MNEMONIC_REGEX = /\(&([^\s&])\)|(^|[^&])&([^\s&])/; export const MENU_ESCAPED_MNEMONIC_REGEX = /(&)?(&)([^\s&])/g; +export enum Direction { + Right, + Left +} + export interface IMenuOptions { context?: any; actionViewItemProvider?: IActionViewItemProvider; @@ -31,6 +36,7 @@ export interface IMenuOptions { ariaLabel?: string; enableMnemonics?: boolean; anchorAlignment?: AnchorAlignment; + expandDirection?: Direction; } export interface IMenuStyles { @@ -60,9 +66,6 @@ export class Menu extends ActionBar { private readonly menuDisposables: DisposableStore; private scrollableElement: DomScrollableElement; private menuElement: HTMLElement; - private scrollTopHold: number | undefined; - - private readonly _onScroll: Emitter; constructor(container: HTMLElement, actions: ReadonlyArray, options: IMenuOptions = {}) { addClass(container, 'monaco-menu-container'); @@ -82,8 +85,6 @@ export class Menu extends ActionBar { this.menuElement = menuElement; - this._onScroll = this._register(new Emitter()); - this.actionsList.setAttribute('role', 'menu'); this.actionsList.tabIndex = 0; @@ -107,7 +108,7 @@ export class Menu extends ActionBar { const actions = this.mnemonics.get(key)!; if (actions.length === 1) { - if (actions[0] instanceof SubmenuMenuActionViewItem) { + if (actions[0] instanceof SubmenuMenuActionViewItem && actions[0].container) { this.focusItemByElement(actions[0].container); } @@ -116,7 +117,7 @@ export class Menu extends ActionBar { if (actions.length > 1) { const action = actions.shift(); - if (action) { + if (action && action.container) { this.focusItemByElement(action.container); actions.push(action); } @@ -147,17 +148,11 @@ export class Menu extends ActionBar { let relatedTarget = e.relatedTarget as HTMLElement; if (!isAncestor(relatedTarget, this.domNode)) { this.focusedItem = undefined; - this.scrollTopHold = this.menuElement.scrollTop; this.updateFocus(); e.stopPropagation(); } })); - this._register(addDisposableListener(this.domNode, EventType.MOUSE_UP, e => { - // Absorb clicks in menu dead space https://github.com/Microsoft/vscode/issues/63575 - EventHelper.stop(e, true); - })); - this._register(addDisposableListener(this.actionsList, EventType.MOUSE_OVER, e => { let target = e.target as HTMLElement; if (!target || !isAncestor(target, this.actionsList) || target === this.actionsList) { @@ -170,7 +165,6 @@ export class Menu extends ActionBar { if (hasClass(target, 'action-item')) { const lastFocusedItem = this.focusedItem; - this.scrollTopHold = this.menuElement.scrollTop; this.setFocusedItem(target); if (lastFocusedItem !== this.focusedItem) { @@ -185,8 +179,6 @@ export class Menu extends ActionBar { this.mnemonics = new Map>(); - this.push(actions, { icon: true, label: true, isMenu: true }); - // Scroll Logic this.scrollableElement = this._register(new DomScrollableElement(menuElement, { alwaysConsumeMouseWheel: true, @@ -198,21 +190,17 @@ export class Menu extends ActionBar { })); const scrollElement = this.scrollableElement.getDomNode(); - scrollElement.style.position = null; + scrollElement.style.position = ''; + + this._register(addDisposableListener(scrollElement, EventType.MOUSE_UP, e => { + // Absorb clicks in menu dead space https://github.com/Microsoft/vscode/issues/63575 + // We do this on the scroll element so the scroll bar doesn't dismiss the menu either + e.preventDefault(); + })); menuElement.style.maxHeight = `${Math.max(10, window.innerHeight - container.getBoundingClientRect().top - 30)}px`; - this.menuDisposables.add(this.scrollableElement.onScroll(() => { - this._onScroll.fire(); - }, this)); - - this._register(addDisposableListener(this.menuElement, EventType.SCROLL, (e: ScrollEvent) => { - if (this.scrollTopHold !== undefined) { - this.menuElement.scrollTop = this.scrollTopHold; - this.scrollTopHold = undefined; - } - this.scrollableElement.scanDomNode(); - })); + this.push(actions, { icon: true, label: true, isMenu: true }); container.appendChild(this.scrollableElement.getDomNode()); this.scrollableElement.scanDomNode(); @@ -225,10 +213,10 @@ export class Menu extends ActionBar { style(style: IMenuStyles): void { const container = this.getContainer(); - const fgColor = style.foregroundColor ? `${style.foregroundColor}` : null; - const bgColor = style.backgroundColor ? `${style.backgroundColor}` : null; - const border = style.borderColor ? `2px solid ${style.borderColor}` : null; - const shadow = style.shadowColor ? `0 2px 4px ${style.shadowColor}` : null; + const fgColor = style.foregroundColor ? `${style.foregroundColor}` : ''; + const bgColor = style.backgroundColor ? `${style.backgroundColor}` : ''; + const border = style.borderColor ? `1px solid ${style.borderColor}` : ''; + const shadow = style.shadowColor ? `0 2px 4px ${style.shadowColor}` : ''; container.style.border = border; this.domNode.style.color = fgColor; @@ -248,8 +236,8 @@ export class Menu extends ActionBar { return this.scrollableElement.getDomNode(); } - get onScroll(): Event { - return this._onScroll.event; + get onScroll(): Event { + return this.scrollableElement.onScroll; } get scrollOffset(): number { @@ -289,6 +277,19 @@ export class Menu extends ActionBar { } } + protected updateFocus(fromRight?: boolean): void { + super.updateFocus(fromRight, true); + + if (typeof this.focusedItem !== 'undefined') { + // Workaround for #80047 caused by an issue in chromium + // https://bugs.chromium.org/p/chromium/issues/detail?id=414283 + // When that's fixed, just call this.scrollableElement.scanDomNode() + this.scrollableElement.setScrollPosition({ + scrollTop: Math.round(this.menuElement.scrollTop) + }); + } + } + private doGetActionViewItem(action: IAction, options: IMenuOptions, parentData: ISubMenuData): BaseActionViewItem { if (action instanceof Separator) { return new MenuSeparatorActionViewItem(options.context, action, { icon: true }); @@ -350,17 +351,17 @@ interface IMenuItemOptions extends IActionViewItemOptions { class BaseMenuActionViewItem extends BaseActionViewItem { - public container: HTMLElement; + public container: HTMLElement | undefined; protected options: IMenuItemOptions; - protected item: HTMLElement; + protected item: HTMLElement | undefined; private runOnceToEnableMouseUp: RunOnceScheduler; - private label: HTMLElement; - private check: HTMLElement; - private mnemonic: string; + private label: HTMLElement | undefined; + private check: HTMLElement | undefined; + private mnemonic: string | undefined; private cssClass: string; - protected menuStyle: IMenuStyles; + protected menuStyle: IMenuStyles | undefined; constructor(ctx: any, action: IAction, options: IMenuItemOptions = {}) { options.isMenu = true; @@ -389,10 +390,14 @@ class BaseMenuActionViewItem extends BaseActionViewItem { } this._register(addDisposableListener(this.element, EventType.MOUSE_UP, e => { + if (e.defaultPrevented) { + return; + } + EventHelper.stop(e, true); this.onClick(e); })); - }, 50); + }, 100); this._register(this.runOnceToEnableMouseUp); } @@ -443,13 +448,19 @@ class BaseMenuActionViewItem extends BaseActionViewItem { focus(): void { super.focus(); - this.item.focus(); + + if (this.item) { + this.item.focus(); + } + this.applyStyle(); } updatePositionInSet(pos: number, setSize: number): void { - this.item.setAttribute('aria-posinset', `${pos}`); - this.item.setAttribute('aria-setsize', `${setSize}`); + if (this.item) { + this.item.setAttribute('aria-posinset', `${pos}`); + this.item.setAttribute('aria-setsize', `${setSize}`); + } } updateLabel(): void { @@ -461,7 +472,9 @@ class BaseMenuActionViewItem extends BaseActionViewItem { label = cleanLabel; } - this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&')); + if (this.label) { + this.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&')); + } const matches = MENU_MNEMONIC_REGEX.exec(label); @@ -482,13 +495,17 @@ class BaseMenuActionViewItem extends BaseActionViewItem { } label = label.replace(/&&/g, '&'); - this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase()); + if (this.item) { + this.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase()); + } } else { label = label.replace(/&&/g, '&'); } } - this.label.innerHTML = label.trim(); + if (this.label) { + this.label.innerHTML = label.trim(); + } } } @@ -506,23 +523,23 @@ class BaseMenuActionViewItem extends BaseActionViewItem { } } - if (title) { + if (title && this.item) { this.item.title = title; } } updateClass(): void { - if (this.cssClass) { + if (this.cssClass && this.item) { removeClasses(this.item, this.cssClass); } - if (this.options.icon) { + if (this.options.icon && this.label) { this.cssClass = this.getAction().class || ''; addClass(this.label, 'icon'); if (this.cssClass) { addClasses(this.label, this.cssClass); } this.updateEnabled(); - } else { + } else if (this.label) { removeClass(this.label, 'icon'); } } @@ -533,19 +550,27 @@ class BaseMenuActionViewItem extends BaseActionViewItem { removeClass(this.element, 'disabled'); } - removeClass(this.item, 'disabled'); - this.item.tabIndex = 0; + if (this.item) { + removeClass(this.item, 'disabled'); + this.item.tabIndex = 0; + } } else { if (this.element) { addClass(this.element, 'disabled'); } - addClass(this.item, 'disabled'); - removeTabIndexAndUpdateFocus(this.item); + if (this.item) { + addClass(this.item, 'disabled'); + removeTabIndexAndUpdateFocus(this.item); + } } } updateChecked(): void { + if (!this.item) { + return; + } + if (this.getAction().checked) { addClass(this.item, 'checked'); this.item.setAttribute('role', 'menuitemcheckbox'); @@ -557,7 +582,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { } } - getMnemonic(): string { + getMnemonic(): string | undefined { return this.mnemonic; } @@ -569,12 +594,20 @@ class BaseMenuActionViewItem extends BaseActionViewItem { 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 ? `thin solid ${this.menuStyle.selectionBorderColor}` : null; + const border = isSelected && this.menuStyle.selectionBorderColor ? `thin solid ${this.menuStyle.selectionBorderColor}` : ''; - this.item.style.color = fgColor ? `${fgColor}` : null; - this.check.style.backgroundColor = fgColor ? `${fgColor}` : null; - this.item.style.backgroundColor = bgColor ? `${bgColor}` : null; - this.container.style.border = border; + if (this.item) { + this.item.style.color = fgColor ? `${fgColor}` : null; + this.item.style.backgroundColor = bgColor ? `${bgColor}` : ''; + } + + if (this.check) { + this.check.style.backgroundColor = fgColor ? `${fgColor}` : ''; + } + + if (this.container) { + this.container.style.border = border; + } } style(style: IMenuStyles): void { @@ -584,13 +617,14 @@ class BaseMenuActionViewItem extends BaseActionViewItem { } class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { - private mysubmenu: Menu | null; + private mysubmenu: Menu | null = null; private submenuContainer: HTMLElement | undefined; - private submenuIndicator: HTMLElement; + private submenuIndicator: HTMLElement | undefined; private readonly submenuDisposables = this._register(new DisposableStore()); - private mouseOver: boolean; + private mouseOver: boolean = false; private showScheduler: RunOnceScheduler; private hideScheduler: RunOnceScheduler; + private expandDirection: Direction; constructor( action: IAction, @@ -600,6 +634,8 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { ) { super(action, action, submenuOptions); + this.expandDirection = submenuOptions && submenuOptions.expandDirection !== undefined ? submenuOptions.expandDirection : Direction.Right; + this.showScheduler = new RunOnceScheduler(() => { if (this.mouseOver) { this.cleanupExistingSubmenu(false); @@ -622,11 +658,13 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { return; } - addClass(this.item, 'monaco-submenu-item'); - this.item.setAttribute('aria-haspopup', 'true'); + if (this.item) { + addClass(this.item, 'monaco-submenu-item'); + this.item.setAttribute('aria-haspopup', 'true'); - this.submenuIndicator = append(this.item, $('span.submenu-indicator')); - this.submenuIndicator.setAttribute('aria-hidden', 'true'); + this.submenuIndicator = append(this.item, $('span.submenu-indicator')); + this.submenuIndicator.setAttribute('aria-hidden', 'true'); + } this._register(addDisposableListener(this.element, EventType.KEY_UP, e => { let event = new StandardKeyboardEvent(e); @@ -681,7 +719,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { EventHelper.stop(e, true); this.cleanupExistingSubmenu(false); - this.createSubmenu(false); + this.createSubmenu(true); } private cleanupExistingSubmenu(force: boolean): void { @@ -705,6 +743,12 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { this.submenuContainer = append(this.element, $('div.monaco-submenu')); addClasses(this.submenuContainer, 'menubar-menu-items-holder', 'context-view'); + // Set the top value of the menu container before construction + // This allows the menu constructor to calculate the proper max height + const computedStyles = getComputedStyle(this.parentData.parent.domNode); + const paddingTop = parseFloat(computedStyles.paddingTop || '0') || 0; + this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`; + this.parentData.submenu = new Menu(this.submenuContainer, this.submenuActions, this.submenuOptions); if (this.menuStyle) { this.parentData.submenu.style(this.menuStyle); @@ -712,14 +756,18 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { const boundingRect = this.element.getBoundingClientRect(); const childBoundingRect = this.submenuContainer.getBoundingClientRect(); - const computedStyles = getComputedStyle(this.parentData.parent.domNode); - const paddingTop = parseFloat(computedStyles.paddingTop || '0') || 0; - if (window.innerWidth <= boundingRect.right + childBoundingRect.width) { - this.submenuContainer.style.left = '10px'; - this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset + boundingRect.height}px`; - } else { - this.submenuContainer.style.left = `${this.element.offsetWidth}px`; + if (this.expandDirection === Direction.Right) { + if (window.innerWidth <= boundingRect.right + childBoundingRect.width) { + this.submenuContainer.style.left = '10px'; + this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset + boundingRect.height}px`; + } else { + this.submenuContainer.style.left = `${this.element.offsetWidth}px`; + this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`; + } + } else if (this.expandDirection === Direction.Left) { + this.submenuContainer.style.right = `${this.element.offsetWidth}px`; + this.submenuContainer.style.left = 'auto'; this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`; } @@ -778,7 +826,9 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { const isSelected = this.element && hasClass(this.element, 'focused'); const fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor; - this.submenuIndicator.style.backgroundColor = fgColor ? `${fgColor}` : null; + if (this.submenuIndicator) { + this.submenuIndicator.style.backgroundColor = fgColor ? `${fgColor}` : ''; + } if (this.parentData.submenu) { this.parentData.submenu.style(this.menuStyle); @@ -803,7 +853,9 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { class MenuSeparatorActionViewItem extends ActionViewItem { style(style: IMenuStyles): void { - this.label.style.borderBottomColor = style.separatorColor ? `${style.separatorColor}` : null; + if (this.label) { + this.label.style.borderBottomColor = style.separatorColor ? `${style.separatorColor}` : ''; + } } } diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index 960dc57e267..925ebc3a53b 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -10,7 +10,7 @@ import * as nls from 'vs/nls'; import { domEvent } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch'; -import { cleanMnemonic, IMenuOptions, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MNEMONIC_REGEX, SubmenuAction, IMenuStyles } from 'vs/base/browser/ui/menu/menu'; +import { cleanMnemonic, IMenuOptions, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MNEMONIC_REGEX, SubmenuAction, IMenuStyles, Direction } from 'vs/base/browser/ui/menu/menu'; import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions'; import { RunOnceScheduler } from 'vs/base/common/async'; import { Event, Emitter } from 'vs/base/common/event'; @@ -20,6 +20,7 @@ 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'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; const $ = DOM.$; @@ -29,6 +30,7 @@ export interface IMenuBarOptions { visibility?: string; getKeybinding?: (action: IAction) => ResolvedKeybinding | undefined; alwaysOnMnemonics?: boolean; + compactMode?: Direction; } export interface MenuBarMenu { @@ -54,7 +56,7 @@ export class MenuBar extends Disposable { actions?: ReadonlyArray; }[]; - private overflowMenu: { + private overflowMenu!: { buttonElement: HTMLElement; titleElement: HTMLElement; label: string; @@ -71,27 +73,30 @@ export class MenuBar extends Disposable { private menuUpdater: RunOnceScheduler; // Input-related - private _mnemonicsInUse: boolean; - private openedViaKeyboard: boolean; - private awaitingAltRelease: boolean; - private ignoreNextMouseUp: boolean; + private _mnemonicsInUse: boolean = false; + private openedViaKeyboard: boolean = false; + private awaitingAltRelease: boolean = false; + private ignoreNextMouseUp: boolean = false; private mnemonics: Map; - private updatePending: boolean; + private updatePending: boolean = false; private _focusState: MenubarState; private actionRunner: IActionRunner; private readonly _onVisibilityChange: Emitter; private readonly _onFocusStateChange: Emitter; - private numMenusShown: number; - private menuStyle: IMenuStyles; - private overflowLayoutScheduled: IDisposable | null; + private numMenusShown: number = 0; + private menuStyle: IMenuStyles | undefined; + private overflowLayoutScheduled: IDisposable | null = null; constructor(private container: HTMLElement, private options: IMenuBarOptions = {}) { super(); this.container.setAttribute('role', 'menubar'); + if (this.options.compactMode !== undefined) { + DOM.addClass(this.container, 'compact'); + } this.menuCache = []; this.mnemonics = new Map(); @@ -234,7 +239,7 @@ export class MenuBar extends Disposable { } })); - Gesture.addTarget(buttonElement); + this._register(Gesture.addTarget(buttonElement)); this._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => { // Ignore this touch if the menu is touched if (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) { @@ -248,7 +253,14 @@ export class MenuBar extends Disposable { e.stopPropagation(); })); - this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_DOWN, (e) => { + this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { + // Ignore non-left-click + const mouseEvent = new StandardMouseEvent(e); + if (!mouseEvent.leftButton) { + e.preventDefault(); + return; + } + if (!this.isOpen) { // Open the menu with mouse down and ignore the following mouse up event this.ignoreNextMouseUp = true; @@ -262,6 +274,10 @@ export class MenuBar extends Disposable { })); this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_UP, (e) => { + if (e.defaultPrevented) { + return; + } + if (!this.ignoreNextMouseUp) { if (this.isFocused) { this.onMenuTriggered(menuIndex, true); @@ -292,8 +308,8 @@ export class MenuBar extends Disposable { } createOverflowMenu(): void { - const label = nls.localize('mMore', "..."); - const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': -1, 'aria-label': label, 'aria-haspopup': true }); + const label = this.options.compactMode !== undefined ? nls.localize('mAppMenu', 'Application Menu') : nls.localize('mMore', "..."); + const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': -1, 'aria-label': label, 'title': label, 'aria-haspopup': true }); const titleElement = $('div.menubar-menu-title.toolbar-toggle-more', { 'role': 'none', 'aria-hidden': true }); buttonElement.appendChild(titleElement); @@ -318,7 +334,7 @@ export class MenuBar extends Disposable { } })); - Gesture.addTarget(buttonElement); + this._register(Gesture.addTarget(buttonElement)); this._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => { // Ignore this touch if the menu is touched if (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) { @@ -333,6 +349,13 @@ export class MenuBar extends Disposable { })); this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_DOWN, (e) => { + // Ignore non-left-click + const mouseEvent = new StandardMouseEvent(e); + if (!mouseEvent.leftButton) { + e.preventDefault(); + return; + } + if (!this.isOpen) { // Open the menu with mouse down and ignore the following mouse up event this.ignoreNextMouseUp = true; @@ -346,6 +369,10 @@ export class MenuBar extends Disposable { })); this._register(DOM.addDisposableListener(buttonElement, DOM.EventType.MOUSE_UP, (e) => { + if (e.defaultPrevented) { + return; + } + if (!this.ignoreNextMouseUp) { if (this.isFocused) { this.onMenuTriggered(MenuBar.OVERFLOW_INDEX, true); @@ -421,7 +448,7 @@ export class MenuBar extends Disposable { const sizeAvailable = this.container.offsetWidth; let currentSize = 0; - let full = false; + let full = this.options.compactMode !== undefined; const prevNumMenusShown = this.numMenusShown; this.numMenusShown = 0; for (let menuBarMenu of this.menuCache) { @@ -458,9 +485,11 @@ export class MenuBar extends Disposable { this.overflowMenu.actions.push(new SubmenuAction(this.menuCache[idx].label, this.menuCache[idx].actions || [])); } - DOM.removeNode(this.overflowMenu.buttonElement); - this.container.insertBefore(this.overflowMenu.buttonElement, this.menuCache[this.numMenusShown].buttonElement); - this.overflowMenu.buttonElement.style.visibility = 'visible'; + if (this.overflowMenu.buttonElement.nextElementSibling !== this.menuCache[this.numMenusShown].buttonElement) { + DOM.removeNode(this.overflowMenu.buttonElement); + this.container.insertBefore(this.overflowMenu.buttonElement, this.menuCache[this.numMenusShown].buttonElement); + this.overflowMenu.buttonElement.style.visibility = 'visible'; + } } else { DOM.removeNode(this.overflowMenu.buttonElement); this.container.appendChild(this.overflowMenu.buttonElement); @@ -694,7 +723,7 @@ export class MenuBar extends Disposable { private focusPrevious(): void { - if (!this.focusedMenu) { + if (!this.focusedMenu || this.numMenusShown === 0) { return; } @@ -724,7 +753,7 @@ export class MenuBar extends Disposable { } private focusNext(): void { - if (!this.focusedMenu) { + if (!this.focusedMenu || this.numMenusShown === 0) { return; } @@ -884,8 +913,19 @@ export class MenuBar extends Disposable { const menuHolder = $('div.menubar-menu-items-holder'); DOM.addClass(customMenu.buttonElement, 'open'); - menuHolder.style.top = `${this.container.clientHeight}px`; - menuHolder.style.left = `${customMenu.buttonElement.getBoundingClientRect().left}px`; + + if (this.options.compactMode === Direction.Right) { + menuHolder.style.top = `0px`; + menuHolder.style.left = `${customMenu.buttonElement.getBoundingClientRect().left + this.container.clientWidth}px`; + } else if (this.options.compactMode === Direction.Left) { + menuHolder.style.top = `0px`; + menuHolder.style.right = `${this.container.clientWidth}px`; + menuHolder.style.left = 'auto'; + console.log(customMenu.buttonElement.getBoundingClientRect().right - this.container.clientWidth); + } else { + menuHolder.style.top = `${this.container.clientHeight}px`; + menuHolder.style.left = `${customMenu.buttonElement.getBoundingClientRect().left}px`; + } customMenu.buttonElement.appendChild(menuHolder); @@ -893,11 +933,14 @@ export class MenuBar extends Disposable { getKeyBinding: this.options.getKeybinding, actionRunner: this.actionRunner, enableMnemonics: this.options.alwaysOnMnemonics || (this.mnemonicsInUse && this.options.enableMnemonics), - ariaLabel: withNullAsUndefined(customMenu.buttonElement.getAttribute('aria-label')) + ariaLabel: withNullAsUndefined(customMenu.buttonElement.getAttribute('aria-label')), + expandDirection: this.options.compactMode !== undefined ? this.options.compactMode : Direction.Right }; let menuWidget = this._register(new Menu(menuHolder, customMenu.actions, menuOptions)); - menuWidget.style(this.menuStyle); + if (this.menuStyle) { + menuWidget.style(this.menuStyle); + } this._register(menuWidget.onDidCancel(() => { this.focusState = MenubarState.FOCUSED; diff --git a/src/vs/base/browser/ui/octiconLabel/octiconLabel.mock.ts b/src/vs/base/browser/ui/octiconLabel/octiconLabel.mock.ts deleted file mode 100644 index 7fb29670d64..00000000000 --- a/src/vs/base/browser/ui/octiconLabel/octiconLabel.mock.ts +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { escape } from 'vs/base/common/strings'; - -export function renderOcticons(text: string): string { - return escape(text); -} - -export class OcticonLabel { - - private _container: HTMLElement; - - constructor(container: HTMLElement) { - this._container = container; - } - - set text(text: string) { - this._container.innerHTML = renderOcticons(text || ''); - } - -} diff --git a/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts b/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts deleted file mode 100644 index 75b3ba027dd..00000000000 --- a/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts +++ /dev/null @@ -1,35 +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!./octicons/octicons'; -import 'vs/css!./octicons/octicons2'; -import 'vs/css!./octicons/octicons-main'; -import 'vs/css!./octicons/octicons-animations'; -import { escape } from 'vs/base/common/strings'; - -function expand(text: string): string { - return text.replace(/\$\(((.+?)(~(.*?))?)\)/g, (_match, _g1, name, _g3, animation) => { - return ``; - }); -} - -export function renderOcticons(label: string): string { - return expand(escape(label)); -} - -export class OcticonLabel { - - constructor( - private readonly _container: HTMLElement - ) { } - - set text(text: string) { - this._container.innerHTML = renderOcticons(text || ''); - } - - set title(title: string) { - this._container.title = title; - } -} diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-animations.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons-animations.css deleted file mode 100644 index 0176b2f6be7..00000000000 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-animations.css +++ /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. - *--------------------------------------------------------------------------------------------*/ - -@keyframes octicon-spin { - 100% { - transform:rotate(360deg); - } -} - -.octicon-animation-spin { - animation: octicon-spin 1.5s linear infinite; -} diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css deleted file mode 100644 index 46349b9f194..00000000000 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css +++ /dev/null @@ -1,17 +0,0 @@ -body[data-octicons-update="enabled"] { - --version: octicons2; -} - -body { - --version: octicons; -} - -.octicon, .mega-octicon { - font-family: var(--version) !important; -} - -body[data-octicons-update="enabled"] .monaco-workbench .part.statusbar > .items-container > .statusbar-item > a { - display: flex; - align-items: center; - justify-content: center; -} diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css deleted file mode 100644 index d9cc1b7a4fa..00000000000 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css +++ /dev/null @@ -1,248 +0,0 @@ -@font-face { - font-family: "octicons"; - src: url("./octicons.ttf?1b0f2a9535896866c74dd24eedeb4374") format("truetype"), -url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg"); -} - -.octicon, .mega-octicon { - font: normal normal normal 16px/1 octicons; - display: inline-block; - text-decoration: none; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.mega-octicon { font-size: 32px; } - - - -.octicon-alert:before { content: "\f02d" } -.octicon-arrow-down:before { content: "\f03f" } -.octicon-arrow-left:before { content: "\f040" } -.octicon-arrow-right:before { content: "\f03e" } -.octicon-arrow-small-down:before { content: "\f0a0" } -.octicon-arrow-small-left:before { content: "\f0a1" } -.octicon-arrow-small-right:before { content: "\f071" } -.octicon-arrow-small-up:before { content: "\f09f" } -.octicon-arrow-up:before { content: "\f03d" } -.octicon-beaker:before { content: "\f0dd" } -.octicon-bell:before { content: "\f0de" } -.octicon-bold:before { content: "\f282" } -.octicon-book:before { content: "\f007" } -.octicon-bookmark:before { content: "\f07b" } -.octicon-briefcase:before { content: "\f0d3" } -.octicon-broadcast:before { content: "\f048" } -.octicon-browser:before { content: "\f0c5" } -.octicon-bug:before { content: "\f091" } -.octicon-calendar:before { content: "\f068" } -.octicon-check:before { content: "\f03a" } -.octicon-checklist:before { content: "\f076" } -.octicon-chevron-down:before { content: "\f0a3" } -.octicon-chevron-left:before { content: "\f0a4" } -.octicon-chevron-right:before { content: "\f078" } -.octicon-chevron-up:before { content: "\f0a2" } -.octicon-circle-slash:before { content: "\f084" } -.octicon-circuit-board:before { content: "\f0d6" } -.octicon-clippy:before { content: "\f035" } -.octicon-clock:before { content: "\f046" } -.octicon-clone:before { content: "\f0dc" } -.octicon-cloud-download:before { content: "\f00b" } -.octicon-cloud-upload:before { content: "\f00c" } -.octicon-code:before { content: "\f05f" } -.octicon-color-mode:before { content: "\f065" } -.octicon-comment-add:before { content: "\f02b" } -.octicon-comment-discussion:before { content: "\f04f" } -.octicon-comment:before { content: "\f02b" } -.octicon-credit-card:before { content: "\f045" } -.octicon-dash:before { content: "\f0ca" } -.octicon-dashboard:before { content: "\f07d" } -.octicon-database:before { content: "\f096" } -.octicon-desktop-download:before { content: "\f0dc" } -.octicon-device-camera-video:before { content: "\f057" } -.octicon-device-camera:before { content: "\f056" } -.octicon-device-desktop:before { content: "\f27c" } -.octicon-device-mobile:before { content: "\f038" } -.octicon-diff-added:before { content: "\f06b" } -.octicon-diff-ignored:before { content: "\f099" } -.octicon-diff-modified:before { content: "\f06d" } -.octicon-diff-removed:before { content: "\f06c" } -.octicon-diff-renamed:before { content: "\f06e" } -.octicon-diff:before { content: "\f04d" } -.octicon-ellipsis:before { content: "\f09a" } -.octicon-eye-unwatch:before { content: "\f04e" } -.octicon-eye-watch:before { content: "\f04e" } -.octicon-eye:before { content: "\f04e" } -.octicon-file-add:before { content: "\f05d" } -.octicon-file-binary:before { content: "\f094" } -.octicon-file-code:before { content: "\f010" } -.octicon-file-directory-create:before { content: "\f05d" } -.octicon-file-directory:before { content: "\f016" } -.octicon-file-media:before { content: "\f012" } -.octicon-file-pdf:before { content: "\f014" } -.octicon-file-submodule:before { content: "\f017" } -.octicon-file-symlink-directory:before { content: "\f0b1" } -.octicon-file-symlink-file:before { content: "\f0b0" } -.octicon-file-text:before { content: "\f283" } -.octicon-file-zip:before { content: "\f013" } -.octicon-file:before { content: "\f283" } -.octicon-flame:before { content: "\f0d2" } -.octicon-fold:before { content: "\f0cc" } -.octicon-gear:before { content: "\f02f" } -.octicon-gift:before { content: "\f042" } -.octicon-gist-fork:before { content: "\f002" } -.octicon-gist-new:before { content: "\f05d" } -.octicon-gist-private:before { content: "\f06a" } -.octicon-gist-secret:before { content: "\f08c" } -.octicon-gist:before { content: "\f00e" } -.octicon-git-branch-create:before { content: "\f020" } -.octicon-git-branch-delete:before { content: "\f020" } -.octicon-git-branch:before { content: "\f020" } -.octicon-git-commit:before { content: "\f01f" } -.octicon-git-compare:before { content: "\f0ac" } -.octicon-git-fork-private:before { content: "\f06a" } -.octicon-git-merge:before { content: "\f023" } -.octicon-git-pull-request-abandoned:before { content: "\f009" } -.octicon-git-pull-request:before { content: "\f009" } -.octicon-globe:before { content: "\f0b6" } -.octicon-grabber:before { content: "\f284" } -.octicon-graph:before { content: "\f043" } -.octicon-heart:before { content: "\2665" } -.octicon-history:before { content: "\f07e" } -.octicon-home:before { content: "\f08d" } -.octicon-horizontal-rule:before { content: "\f070" } -.octicon-hubot:before { content: "\f09d" } -.octicon-inbox:before { content: "\f0cf" } -.octicon-info:before { content: "\f059" } -.octicon-issue-closed:before { content: "\f028" } -.octicon-issue-opened:before { content: "\f026" } -.octicon-issue-reopened:before { content: "\f027" } -.octicon-italic:before { content: "\f285" } -.octicon-jersey:before { content: "\f019" } -.octicon-kebab-horizontal:before { content: "\f286" } -.octicon-kebab-vertical:before { content: "\f287" } -.octicon-key:before { content: "\f049" } -.octicon-keyboard:before { content: "\f00d" } -.octicon-law:before { content: "\f0d8" } -.octicon-light-bulb:before { content: "\f000" } -.octicon-link-external:before { content: "\f07f" } -.octicon-link:before { content: "\f05c" } -.octicon-list-ordered:before { content: "\f062" } -.octicon-list-unordered:before { content: "\f061" } -.octicon-location:before { content: "\f060" } -.octicon-lock:before { content: "\f06a" } -.octicon-log-in:before { content: "\f036" } -.octicon-log-out:before { content: "\f032" } -.octicon-logo-gist:before { content: "\f288" } -.octicon-logo-github:before { content: "\f092" } -.octicon-mail-read:before { content: "\f03c" } -.octicon-mail-reply:before { content: "\f28c" } -.octicon-mail:before { content: "\f03b" } -.octicon-mark-github:before { content: "\f00a" } -.octicon-markdown:before { content: "\f0c9" } -.octicon-megaphone:before { content: "\f077" } -.octicon-mention:before { content: "\f0be" } -.octicon-microscope:before { content: "\f0dd" } -.octicon-milestone:before { content: "\f075" } -.octicon-mirror-private:before { content: "\f06a" } -.octicon-mirror-public:before { content: "\f024" } -.octicon-mirror:before { content: "\f024" } -.octicon-mortar-board:before { content: "\f0d7" } -.octicon-mute:before { content: "\f080" } -.octicon-no-newline:before { content: "\f09c" } -.octicon-note:before { content: "\f289" } -.octicon-octoface:before { content: "\f008" } -.octicon-organization:before { content: "\f037" } -.octicon-organization-filled:before { content: "\26a2" } -.octicon-organization-outline:before { content: "\f037" } -.octicon-package:before { content: "\f0c4" } -.octicon-paintcan:before { content: "\f0d1" } -.octicon-pencil:before { content: "\f058" } -.octicon-person-add:before { content: "\f018" } -.octicon-person-follow:before { content: "\f018" } -.octicon-person:before { content: "\f018" } -.octicon-person-filled:before { content: "\26a3" } -.octicon-person-outline:before { content: "\f018" } -.octicon-pin:before { content: "\f041" } -.octicon-plug:before { content: "\f0d4" } -.octicon-plus-small:before { content: "\f28a" } -.octicon-plus:before { content: "\f05d" } -.octicon-primitive-dot:before { content: "\f052" } -.octicon-primitive-square:before { content: "\f053" } -.octicon-project:before { content: "\f28b" } -.octicon-pulse:before { content: "\f085" } -.octicon-question:before { content: "\f02c" } -.octicon-quote:before { content: "\f063" } -.octicon-radio-tower:before { content: "\f030" } -.octicon-remove-close:before { content: "\f081" } -.octicon-reply:before { content: "\f28c" } -.octicon-repo-clone:before { content: "\f04c" } -.octicon-repo-create:before { content: "\f05d" } -.octicon-repo-delete:before { content: "\f001" } -.octicon-repo-force-push:before { content: "\f04a" } -.octicon-repo-forked:before { content: "\f002" } -.octicon-repo-pull:before { content: "\f006" } -.octicon-repo-push:before { content: "\f005" } -.octicon-repo-sync:before { content: "\f087" } -.octicon-repo:before { content: "\f001" } -.octicon-report:before { content: "\f28d" } -.octicon-rocket:before { content: "\f033" } -.octicon-rss:before { content: "\f034" } -.octicon-ruby:before { content: "\f047" } -.octicon-screen-full:before { content: "\f066" } -.octicon-screen-normal:before { content: "\f067" } -.octicon-search-save:before { content: "\f02e" } -.octicon-search:before { content: "\f02e" } -.octicon-server:before { content: "\f097" } -.octicon-settings:before { content: "\f07c" } -.octicon-shield:before { content: "\f0e1" } -.octicon-sign-in:before { content: "\f036" } -.octicon-sign-out:before { content: "\f032" } -.octicon-smiley:before { content: "\f27d" } -.octicon-squirrel:before { content: "\f0b2" } -.octicon-star-add:before { content: "\f02a" } -.octicon-star-delete:before { content: "\f02a" } -.octicon-star:before { content: "\f02a" } -.octicon-stop:before { content: "\f08f" } -.octicon-sync:before { content: "\f087" } -.octicon-tag-add:before { content: "\f015" } -.octicon-tag-remove:before { content: "\f015" } -.octicon-tag:before { content: "\f015" } -.octicon-tasklist:before { content: "\f27e" } -.octicon-telescope:before { content: "\f088" } -.octicon-terminal:before { content: "\f0c8" } -.octicon-text-size:before { content: "\f27f" } -.octicon-three-bars:before { content: "\f05e" } -.octicon-thumbsdown:before { content: "\f0db" } -.octicon-thumbsup:before { content: "\f0da" } -.octicon-tools:before { content: "\f031" } -.octicon-trashcan:before { content: "\f0d0" } -.octicon-triangle-down:before { content: "\f05b" } -.octicon-triangle-left:before { content: "\f044" } -.octicon-triangle-right:before { content: "\f05a" } -.octicon-triangle-up:before { content: "\f0aa" } -.octicon-unfold:before { content: "\f039" } -.octicon-unmute:before { content: "\f0ba" } -.octicon-unverified:before { content: "\f280" } -.octicon-verified:before { content: "\f281" } -.octicon-versions:before { content: "\f064" } -.octicon-watch:before { content: "\f0e0" } -.octicon-x:before { content: "\f081" } -.octicon-zap:before { content: "\26a1" } -.octicon-archive:before { content: "\f101" } -.octicon-arrow-both:before { content: "\f102" } -.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 deleted file mode 100644 index 3f4ab4f1807..00000000000 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg +++ /dev/null @@ -1,582 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf deleted file mode 100644 index 087e8706c81..00000000000 Binary files a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf and /dev/null differ diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css deleted file mode 100644 index 69e7dac4e6c..00000000000 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css +++ /dev/null @@ -1,251 +0,0 @@ -@font-face { - font-family: "octicons2"; - src: url("./octicons2.ttf?aa78025ff36faa0aebb5b864685c6dc4") format("truetype"); -} - -.octicon, .mega-octicon { - font: normal normal normal 16px/1 octicons2; - display: inline-block; - text-decoration: none; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.mega-octicon { font-size: 32px; } - - - -body[data-octicons-update="enabled"] .octicon-alert:before { content: "\f02d" } -body[data-octicons-update="enabled"] .octicon-arrow-down:before { content: "\f03f" } -body[data-octicons-update="enabled"] .octicon-arrow-left:before { content: "\f040" } -body[data-octicons-update="enabled"] .octicon-arrow-right:before { content: "\f03e" } -body[data-octicons-update="enabled"] .octicon-arrow-small-down:before { content: "\f0a0" } -body[data-octicons-update="enabled"] .octicon-arrow-small-left:before { content: "\f0a1" } -body[data-octicons-update="enabled"] .octicon-arrow-small-right:before { content: "\f071" } -body[data-octicons-update="enabled"] .octicon-arrow-small-up:before { content: "\f09f" } -body[data-octicons-update="enabled"] .octicon-arrow-up:before { content: "\f03d" } -body[data-octicons-update="enabled"] .octicon-beaker:before { content: "\f0dd" } -body[data-octicons-update="enabled"] .octicon-bell:before { content: "\f0de" } -body[data-octicons-update="enabled"] .octicon-bold:before { content: "\f282" } -body[data-octicons-update="enabled"] .octicon-book:before { content: "\f007" } -body[data-octicons-update="enabled"] .octicon-bookmark:before { content: "\f07b" } -body[data-octicons-update="enabled"] .octicon-briefcase:before { content: "\f0d3" } -body[data-octicons-update="enabled"] .octicon-broadcast:before { content: "\f048" } -body[data-octicons-update="enabled"] .octicon-browser:before { content: "\f0c5" } -body[data-octicons-update="enabled"] .octicon-bug:before { content: "\f091" } -body[data-octicons-update="enabled"] .octicon-calendar:before { content: "\f068" } -body[data-octicons-update="enabled"] .octicon-check:before { content: "\f03a" } -body[data-octicons-update="enabled"] .octicon-checklist:before { content: "\f076" } -body[data-octicons-update="enabled"] .octicon-chevron-down:before { content: "\f0a3" } -body[data-octicons-update="enabled"] .octicon-chevron-left:before { content: "\f0a4" } -body[data-octicons-update="enabled"] .octicon-chevron-right:before { content: "\f078" } -body[data-octicons-update="enabled"] .octicon-chevron-up:before { content: "\f0a2" } -body[data-octicons-update="enabled"] .octicon-circle-slash:before { content: "\f084" } -body[data-octicons-update="enabled"] .octicon-circuit-board:before { content: "\f0d6" } -body[data-octicons-update="enabled"] .octicon-clippy:before { content: "\f035" } -body[data-octicons-update="enabled"] .octicon-clock:before { content: "\f046" } -body[data-octicons-update="enabled"] .octicon-clone:before { content: "\f0dc" } -body[data-octicons-update="enabled"] .octicon-cloud-download:before { content: "\f00b" } -body[data-octicons-update="enabled"] .octicon-cloud-upload:before { content: "\f00c" } -body[data-octicons-update="enabled"] .octicon-code:before { content: "\f05f" } -body[data-octicons-update="enabled"] .octicon-color-mode:before { content: "\f065" } -body[data-octicons-update="enabled"] .octicon-comment-add:before { content: "\f02b" } -body[data-octicons-update="enabled"] .octicon-comment-discussion:before { content: "\f04f" } -body[data-octicons-update="enabled"] .octicon-comment:before { content: "\f02b" } -body[data-octicons-update="enabled"] .octicon-credit-card:before { content: "\f045" } -body[data-octicons-update="enabled"] .octicon-dash:before { content: "\f0ca" } -body[data-octicons-update="enabled"] .octicon-dashboard:before { content: "\f07d" } -body[data-octicons-update="enabled"] .octicon-database:before { content: "\f096" } -body[data-octicons-update="enabled"] .octicon-desktop-download:before { content: "\f0dc" } -body[data-octicons-update="enabled"] .octicon-device-camera-video:before { content: "\f057" } -body[data-octicons-update="enabled"] .octicon-device-camera:before { content: "\f056" } -body[data-octicons-update="enabled"] .octicon-device-desktop:before { content: "\f27c" } -body[data-octicons-update="enabled"] .octicon-device-mobile:before { content: "\f038" } -body[data-octicons-update="enabled"] .octicon-diff-added:before { content: "\f06b" } -body[data-octicons-update="enabled"] .octicon-diff-ignored:before { content: "\f099" } -body[data-octicons-update="enabled"] .octicon-diff-modified:before { content: "\f06d" } -body[data-octicons-update="enabled"] .octicon-diff-removed:before { content: "\f06c" } -body[data-octicons-update="enabled"] .octicon-diff-renamed:before { content: "\f06e" } -body[data-octicons-update="enabled"] .octicon-diff:before { content: "\f04d" } -body[data-octicons-update="enabled"] .octicon-ellipsis:before { content: "\f09a" } -body[data-octicons-update="enabled"] .octicon-eye-unwatch:before { content: "\f04e" } -body[data-octicons-update="enabled"] .octicon-eye-watch:before { content: "\f04e" } -body[data-octicons-update="enabled"] .octicon-eye:before { content: "\f04e" } -body[data-octicons-update="enabled"] .octicon-file-add:before { content: "\f05d" } -body[data-octicons-update="enabled"] .octicon-file-binary:before { content: "\f094" } -body[data-octicons-update="enabled"] .octicon-file-code:before { content: "\f010" } -body[data-octicons-update="enabled"] .octicon-file-directory-create:before { content: "\f05d" } -body[data-octicons-update="enabled"] .octicon-file-directory:before { content: "\f016" } -body[data-octicons-update="enabled"] .octicon-file-media:before { content: "\f012" } -body[data-octicons-update="enabled"] .octicon-file-pdf:before { content: "\f014" } -body[data-octicons-update="enabled"] .octicon-file-submodule:before { content: "\f017" } -body[data-octicons-update="enabled"] .octicon-file-symlink-directory:before { content: "\f0b1" } -body[data-octicons-update="enabled"] .octicon-file-symlink-file:before { content: "\f0b0" } -body[data-octicons-update="enabled"] .octicon-file-text:before { content: "\f283" } -body[data-octicons-update="enabled"] .octicon-file-zip:before { content: "\f013" } -body[data-octicons-update="enabled"] .octicon-file:before { content: "\f283" } -body[data-octicons-update="enabled"] .octicon-flame:before { content: "\f0d2" } -body[data-octicons-update="enabled"] .octicon-fold:before { content: "\f0cc" } -body[data-octicons-update="enabled"] .octicon-gear:before { content: "\f02f" } -body[data-octicons-update="enabled"] .octicon-gift:before { content: "\f042" } -body[data-octicons-update="enabled"] .octicon-gist-fork:before { content: "\f002" } -body[data-octicons-update="enabled"] .octicon-gist-new:before { content: "\f05d" } -body[data-octicons-update="enabled"] .octicon-gist-private:before { content: "\f06a" } -body[data-octicons-update="enabled"] .octicon-gist-secret:before { content: "\f08c" } -body[data-octicons-update="enabled"] .octicon-gist:before { content: "\f00e" } -body[data-octicons-update="enabled"] .octicon-git-branch-create:before { content: "\f020" } -body[data-octicons-update="enabled"] .octicon-git-branch-delete:before { content: "\f020" } -body[data-octicons-update="enabled"] .octicon-git-branch:before { content: "\f020" } -body[data-octicons-update="enabled"] .octicon-git-commit:before { content: "\f01f" } -body[data-octicons-update="enabled"] .octicon-git-compare:before { content: "\f0ac" } -body[data-octicons-update="enabled"] .octicon-git-fork-private:before { content: "\f06a" } -body[data-octicons-update="enabled"] .octicon-git-merge:before { content: "\f023" } -body[data-octicons-update="enabled"] .octicon-git-pull-request-abandoned:before { content: "\f009" } -body[data-octicons-update="enabled"] .octicon-git-pull-request:before { content: "\f009" } -body[data-octicons-update="enabled"] .octicon-globe:before { content: "\f0b6" } -body[data-octicons-update="enabled"] .octicon-grabber:before { content: "\f284" } -body[data-octicons-update="enabled"] .octicon-graph:before { content: "\f043" } -body[data-octicons-update="enabled"] .octicon-heart:before { content: "\2665" } -body[data-octicons-update="enabled"] .octicon-history:before { content: "\f07e" } -body[data-octicons-update="enabled"] .octicon-home:before { content: "\f08d" } -body[data-octicons-update="enabled"] .octicon-horizontal-rule:before { content: "\f070" } -body[data-octicons-update="enabled"] .octicon-hubot:before { content: "\f09d" } -body[data-octicons-update="enabled"] .octicon-inbox:before { content: "\f0cf" } -body[data-octicons-update="enabled"] .octicon-info:before { content: "\f059" } -body[data-octicons-update="enabled"] .octicon-issue-closed:before { content: "\f028" } -body[data-octicons-update="enabled"] .octicon-issue-opened:before { content: "\f026" } -body[data-octicons-update="enabled"] .octicon-issue-reopened:before { content: "\f027" } -body[data-octicons-update="enabled"] .octicon-italic:before { content: "\f285" } -body[data-octicons-update="enabled"] .octicon-jersey:before { content: "\f019" } -body[data-octicons-update="enabled"] .octicon-kebab-horizontal:before { content: "\f286" } -body[data-octicons-update="enabled"] .octicon-kebab-vertical:before { content: "\f287" } -body[data-octicons-update="enabled"] .octicon-key:before { content: "\f049" } -body[data-octicons-update="enabled"] .octicon-keyboard:before { content: "\f00d" } -body[data-octicons-update="enabled"] .octicon-law:before { content: "\f0d8" } -body[data-octicons-update="enabled"] .octicon-light-bulb:before { content: "\f000" } -body[data-octicons-update="enabled"] .octicon-link-external:before { content: "\f07f" } -body[data-octicons-update="enabled"] .octicon-link:before { content: "\f05c" } -body[data-octicons-update="enabled"] .octicon-list-ordered:before { content: "\f062" } -body[data-octicons-update="enabled"] .octicon-list-unordered:before { content: "\f061" } -body[data-octicons-update="enabled"] .octicon-location:before { content: "\f060" } -body[data-octicons-update="enabled"] .octicon-lock:before { content: "\f06a" } -body[data-octicons-update="enabled"] .octicon-log-in:before { content: "\f036" } -body[data-octicons-update="enabled"] .octicon-log-out:before { content: "\f032" } -body[data-octicons-update="enabled"] .octicon-logo-gist:before { content: "\f288" } -body[data-octicons-update="enabled"] .octicon-logo-github:before { content: "\f092" } -body[data-octicons-update="enabled"] .octicon-mail-read:before { content: "\f03c" } -body[data-octicons-update="enabled"] .octicon-mail-reply:before { content: "\f28c" } -body[data-octicons-update="enabled"] .octicon-mail:before { content: "\f03b" } -body[data-octicons-update="enabled"] .octicon-mark-github:before { content: "\f00a" } -body[data-octicons-update="enabled"] .octicon-markdown:before { content: "\f0c9" } -body[data-octicons-update="enabled"] .octicon-megaphone:before { content: "\f077" } -body[data-octicons-update="enabled"] .octicon-mention:before { content: "\f0be" } -body[data-octicons-update="enabled"] .octicon-microscope:before { content: "\f0dd" } -body[data-octicons-update="enabled"] .octicon-milestone:before { content: "\f075" } -body[data-octicons-update="enabled"] .octicon-mirror-private:before { content: "\f06a" } -body[data-octicons-update="enabled"] .octicon-mirror-public:before { content: "\f024" } -body[data-octicons-update="enabled"] .octicon-mirror:before { content: "\f024" } -body[data-octicons-update="enabled"] .octicon-mortar-board:before { content: "\f0d7" } -body[data-octicons-update="enabled"] .octicon-mute:before { content: "\f080" } -body[data-octicons-update="enabled"] .octicon-no-newline:before { content: "\f09c" } -body[data-octicons-update="enabled"] .octicon-note:before { content: "\f289" } -body[data-octicons-update="enabled"] .octicon-octoface:before { content: "\f008" } -body[data-octicons-update="enabled"] .octicon-organization:before { content: "\f037" } -body[data-octicons-update="enabled"] .octicon-organization-filled:before { content: "\f037" } -body[data-octicons-update="enabled"] .octicon-organization-outline:before { content: "\f037" } -body[data-octicons-update="enabled"] .octicon-package:before { content: "\f0c4" } -body[data-octicons-update="enabled"] .octicon-paintcan:before { content: "\f0d1" } -body[data-octicons-update="enabled"] .octicon-pencil:before { content: "\f058" } -body[data-octicons-update="enabled"] .octicon-person-add:before { content: "\f018" } -body[data-octicons-update="enabled"] .octicon-person-follow:before { content: "\f018" } -body[data-octicons-update="enabled"] .octicon-person:before { content: "\f018" } -body[data-octicons-update="enabled"] .octicon-person-filled:before { content: "\f018" } -body[data-octicons-update="enabled"] .octicon-person-outline:before { content: "\f018" } -body[data-octicons-update="enabled"] .octicon-pin:before { content: "\f041" } -body[data-octicons-update="enabled"] .octicon-plug:before { content: "\f0d4" } -body[data-octicons-update="enabled"] .octicon-plus-small:before { content: "\f28a" } -body[data-octicons-update="enabled"] .octicon-plus:before { content: "\f05d" } -body[data-octicons-update="enabled"] .octicon-primitive-dot:before { content: "\f052" } -body[data-octicons-update="enabled"] .octicon-primitive-square:before { content: "\f053" } -body[data-octicons-update="enabled"] .octicon-project:before { content: "\f28b" } -body[data-octicons-update="enabled"] .octicon-pulse:before { content: "\f085" } -body[data-octicons-update="enabled"] .octicon-question:before { content: "\f02c" } -body[data-octicons-update="enabled"] .octicon-quote:before { content: "\f063" } -body[data-octicons-update="enabled"] .octicon-radio-tower:before { content: "\f030" } -body[data-octicons-update="enabled"] .octicon-remove-close:before { content: "\f081" } -body[data-octicons-update="enabled"] .octicon-reply:before { content: "\f28c" } -body[data-octicons-update="enabled"] .octicon-repo-clone:before { content: "\f04c" } -body[data-octicons-update="enabled"] .octicon-repo-create:before { content: "\f05d" } -body[data-octicons-update="enabled"] .octicon-repo-delete:before { content: "\f001" } -body[data-octicons-update="enabled"] .octicon-repo-force-push:before { content: "\f04a" } -body[data-octicons-update="enabled"] .octicon-repo-forked:before { content: "\f002" } -body[data-octicons-update="enabled"] .octicon-repo-pull:before { content: "\f006" } -body[data-octicons-update="enabled"] .octicon-repo-push:before { content: "\f005" } -body[data-octicons-update="enabled"] .octicon-repo-sync:before { content: "\f087" } -body[data-octicons-update="enabled"] .octicon-repo:before { content: "\f001" } -body[data-octicons-update="enabled"] .octicon-report:before { content: "\f28d" } -body[data-octicons-update="enabled"] .octicon-rocket:before { content: "\f033" } -body[data-octicons-update="enabled"] .octicon-rss:before { content: "\f034" } -body[data-octicons-update="enabled"] .octicon-ruby:before { content: "\f047" } -body[data-octicons-update="enabled"] .octicon-screen-full:before { content: "\f066" } -body[data-octicons-update="enabled"] .octicon-screen-normal:before { content: "\f067" } -body[data-octicons-update="enabled"] .octicon-search-save:before { content: "\f02e" } -body[data-octicons-update="enabled"] .octicon-search:before { content: "\f02e" } -body[data-octicons-update="enabled"] .octicon-server:before { content: "\f097" } -body[data-octicons-update="enabled"] .octicon-settings:before { content: "\f07c" } -body[data-octicons-update="enabled"] .octicon-shield:before { content: "\f0e1" } -body[data-octicons-update="enabled"] .octicon-sign-in:before { content: "\f036" } -body[data-octicons-update="enabled"] .octicon-sign-out:before { content: "\f032" } -body[data-octicons-update="enabled"] .octicon-smiley:before { content: "\26b2" } -body[data-octicons-update="enabled"] .octicon-squirrel:before { content: "\f0b2" } -body[data-octicons-update="enabled"] .octicon-star-add:before { content: "\f02a" } -body[data-octicons-update="enabled"] .octicon-star-delete:before { content: "\f02a" } -body[data-octicons-update="enabled"] .octicon-star:before { content: "\f02a" } -body[data-octicons-update="enabled"] .octicon-stop:before { content: "\f08f" } -body[data-octicons-update="enabled"] .octicon-sync:before { content: "\f087" } -body[data-octicons-update="enabled"] .octicon-tag-add:before { content: "\f015" } -body[data-octicons-update="enabled"] .octicon-tag-remove:before { content: "\f015" } -body[data-octicons-update="enabled"] .octicon-tag:before { content: "\f015" } -body[data-octicons-update="enabled"] .octicon-tasklist:before { content: "\f27e" } -body[data-octicons-update="enabled"] .octicon-telescope:before { content: "\f088" } -body[data-octicons-update="enabled"] .octicon-terminal:before { content: "\f0c8" } -body[data-octicons-update="enabled"] .octicon-text-size:before { content: "\f27f" } -body[data-octicons-update="enabled"] .octicon-three-bars:before { content: "\f05e" } -body[data-octicons-update="enabled"] .octicon-thumbsdown:before { content: "\f0db" } -body[data-octicons-update="enabled"] .octicon-thumbsup:before { content: "\f0da" } -body[data-octicons-update="enabled"] .octicon-tools:before { content: "\f031" } -body[data-octicons-update="enabled"] .octicon-trashcan:before { content: "\f0d0" } -body[data-octicons-update="enabled"] .octicon-triangle-down:before { content: "\f05b" } -body[data-octicons-update="enabled"] .octicon-triangle-left:before { content: "\f044" } -body[data-octicons-update="enabled"] .octicon-triangle-right:before { content: "\f05a" } -body[data-octicons-update="enabled"] .octicon-triangle-up:before { content: "\f0aa" } -body[data-octicons-update="enabled"] .octicon-unfold:before { content: "\f039" } -body[data-octicons-update="enabled"] .octicon-unmute:before { content: "\f0ba" } -body[data-octicons-update="enabled"] .octicon-unverified:before { content: "\f280" } -body[data-octicons-update="enabled"] .octicon-verified:before { content: "\f281" } -body[data-octicons-update="enabled"] .octicon-versions:before { content: "\f064" } -body[data-octicons-update="enabled"] .octicon-watch:before { content: "\f0e0" } -body[data-octicons-update="enabled"] .octicon-x:before { content: "\f081" } -body[data-octicons-update="enabled"] .octicon-zap:before { content: "\26a1" } -body[data-octicons-update="enabled"] .octicon-error:before { content: "\26b1" } -body[data-octicons-update="enabled"] .octicon-eye-closed:before { content: "\26a3" } -body[data-octicons-update="enabled"] .octicon-fold-down:before { content: "\26a4" } -body[data-octicons-update="enabled"] .octicon-fold-up:before { content: "\26a5" } -body[data-octicons-update="enabled"] .octicon-github-action:before { content: "\26a6" } -body[data-octicons-update="enabled"] .octicon-info-outline:before { content: "\26a7" } -body[data-octicons-update="enabled"] .octicon-play:before { content: "\26a8" } -body[data-octicons-update="enabled"] .octicon-remote:before { content: "\26a9" } -body[data-octicons-update="enabled"] .octicon-request-changes:before { content: "\26aa" } -body[data-octicons-update="enabled"] .octicon-smiley-outline:before { content: "\26b2" } -body[data-octicons-update="enabled"] .octicon-warning:before { content: "\f02d" } -body[data-octicons-update="enabled"] .octicon-controls:before { content: "\26ad" } -body[data-octicons-update="enabled"] .octicon-event:before { content: "\26ae" } -body[data-octicons-update="enabled"] .octicon-record-keys:before { content: "\26af" } -body[data-octicons-update="enabled"] .octicon-Vector:before { content: "\f101" } -body[data-octicons-update="enabled"] .octicon-archive:before { content: "\f102" } -body[data-octicons-update="enabled"] .octicon-arrow-both:before { content: "\f103" } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf deleted file mode 100644 index 19f3d6e11ce..00000000000 Binary files a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf and /dev/null differ diff --git a/src/vs/base/browser/ui/progressbar/progressbar.css b/src/vs/base/browser/ui/progressbar/progressbar.css index f926530cec4..5d1e8b3f762 100644 --- a/src/vs/base/browser/ui/progressbar/progressbar.css +++ b/src/vs/base/browser/ui/progressbar/progressbar.css @@ -35,18 +35,6 @@ animation-duration: 4s; animation-iteration-count: infinite; animation-timing-function: linear; - -ms-animation-name: progress; - -ms-animation-duration: 4s; - -ms-animation-iteration-count: infinite; - -ms-animation-timing-function: linear; - -webkit-animation-name: progress; - -webkit-animation-duration: 4s; - -webkit-animation-iteration-count: infinite; - -webkit-animation-timing-function: linear; - -moz-animation-name: progress; - -moz-animation-duration: 4s; - -moz-animation-iteration-count: infinite; - -moz-animation-timing-function: linear; will-change: transform; } @@ -58,6 +46,3 @@ * 100%: 50 * 100 - 50 (do not overflow): 4950% */ @keyframes progress { from { transform: translateX(0%) scaleX(1) } 50% { transform: translateX(2500%) scaleX(3) } to { transform: translateX(4950%) scaleX(1) } } -@-ms-keyframes progress { from { transform: translateX(0%) scaleX(1) } 50% { transform: translateX(2500%) scaleX(3) } to { transform: translateX(4950%) scaleX(1) } } -@-webkit-keyframes progress { from { transform: translateX(0%) scaleX(1) } 50% { transform: translateX(2500%) scaleX(3) } to { transform: translateX(4950%) scaleX(1) } } -@-moz-keyframes progress { from { transform: translateX(0%) scaleX(1) } 50% { transform: translateX(2500%) scaleX(3) } to { transform: translateX(4950%) scaleX(1) } } \ No newline at end of file diff --git a/src/vs/base/browser/ui/progressbar/progressbar.ts b/src/vs/base/browser/ui/progressbar/progressbar.ts index 405bfe80c05..198d8e2310e 100644 --- a/src/vs/base/browser/ui/progressbar/progressbar.ts +++ b/src/vs/base/browser/ui/progressbar/progressbar.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./progressbar'; -import * as assert from 'vs/base/common/assert'; import { Disposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; @@ -154,9 +153,7 @@ export class ProgressBar extends Disposable { * Tells the progress bar that an increment of work has been completed. */ worked(value: number): ProgressBar { - value = Number(value); - assert.ok(!isNaN(value), 'Value is not a number'); - value = Math.max(1, value); + value = Math.max(1, Number(value)); return this.doSetWorked(this.workedVal + value); } @@ -165,16 +162,13 @@ export class ProgressBar extends Disposable { * Tells the progress bar the total amount of work that has been completed. */ setWorked(value: number): ProgressBar { - value = Number(value); - assert.ok(!isNaN(value), 'Value is not a number'); - value = Math.max(1, value); + value = Math.max(1, Number(value)); return this.doSetWorked(value); } private doSetWorked(value: number): ProgressBar { - assert.ok(isNumber(this.totalWork), 'Total work not set'); - const totalWork = this.totalWork!; + const totalWork = this.totalWork || 100; this.workedVal = value; this.workedVal = Math.min(totalWork, this.workedVal); @@ -227,7 +221,7 @@ export class ProgressBar extends Disposable { protected applyStyles(): void { if (this.bit) { - const background = this.progressBarBackground ? this.progressBarBackground.toString() : null; + const background = this.progressBarBackground ? this.progressBarBackground.toString() : ''; this.bit.style.backgroundColor = background; } diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 16279b74af9..7c2a52a89bf 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -139,7 +139,7 @@ export class Sash extends Disposable { this._register(domEvent(this.el, 'mousedown')(this.onMouseDown, this)); this._register(domEvent(this.el, 'dblclick')(this.onMouseDoubleClick, this)); - Gesture.addTarget(this.el); + this._register(Gesture.addTarget(this.el)); this._register(domEvent(this.el, EventType.Start)(this.onTouchStart, this)); if (isIPad) { diff --git a/src/vs/base/browser/ui/selectBox/selectBox.ts b/src/vs/base/browser/ui/selectBox/selectBox.ts index d450f76d360..c92601b96ba 100644 --- a/src/vs/base/browser/ui/selectBox/selectBox.ts +++ b/src/vs/base/browser/ui/selectBox/selectBox.ts @@ -78,7 +78,7 @@ export class SelectBox extends Widget implements ISelectBoxDelegate { super(); // Default to native SelectBox for OSX unless overridden - if (isMacintosh && !(selectBoxOptions && selectBoxOptions.useCustomDrawn)) { + if (isMacintosh && !selectBoxOptions?.useCustomDrawn) { this.selectBoxDelegate = new SelectBoxNative(options, selected, styles, selectBoxOptions); } else { this.selectBoxDelegate = new SelectBoxList(options, selected, contextViewProvider, styles, selectBoxOptions); diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.css b/src/vs/base/browser/ui/selectBox/selectBoxCustom.css index 7bc3f55b13e..b717cde73f6 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.css +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.css @@ -16,11 +16,7 @@ .monaco-select-box-dropdown-container { display: none; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; } .monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown * { @@ -55,11 +51,7 @@ padding-right: 1px; width: 100%; overflow: hidden; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; } .monaco-select-box-dropdown-container > .select-box-details-pane { diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index b5f2fe57c72..7e6ee0f7f6a 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -374,9 +374,9 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi // Style parent select if (this.selectElement) { - const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : null; - const foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : null; - const border = this.styles.selectBorder ? this.styles.selectBorder.toString() : null; + const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : ''; + const foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : ''; + const border = this.styles.selectBorder ? this.styles.selectBorder.toString() : ''; this.selectElement.style.backgroundColor = background; this.selectElement.style.color = foreground; @@ -392,10 +392,10 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi private styleList() { if (this.selectList) { - let background = this.styles.selectBackground ? this.styles.selectBackground.toString() : null; + const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : ''; this.selectList.style({}); - let listBackground = this.styles.selectListBackground ? this.styles.selectListBackground.toString() : background; + const listBackground = this.styles.selectListBackground ? this.styles.selectListBackground.toString() : background; this.selectDropDownListContainer.style.backgroundColor = listBackground; this.selectionDetailsPane.style.backgroundColor = listBackground; const optionsBorder = this.styles.focusBorder ? this.styles.focusBorder.toString() : ''; diff --git a/src/vs/base/browser/ui/selectBox/selectBoxNative.ts b/src/vs/base/browser/ui/selectBox/selectBoxNative.ts index afaed056d4c..8c50b057fb5 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxNative.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxNative.ts @@ -147,9 +147,9 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate { // Style native select if (this.selectElement) { - const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : null; - const foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : null; - const border = this.styles.selectBorder ? this.styles.selectBorder.toString() : null; + const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : ''; + const foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : ''; + const border = this.styles.selectBorder ? this.styles.selectBorder.toString() : ''; this.selectElement.style.backgroundColor = background; this.selectElement.style.color = foreground; diff --git a/src/vs/base/browser/ui/splitview/panelview.css b/src/vs/base/browser/ui/splitview/panelview.css index ed2f2e87b32..ff3554c4227 100644 --- a/src/vs/base/browser/ui/splitview/panelview.css +++ b/src/vs/base/browser/ui/splitview/panelview.css @@ -20,38 +20,24 @@ font-size: 11px; font-weight: bold; text-transform: uppercase; - padding-left: 20px; overflow: hidden; display: flex; cursor: pointer; + align-items: center; } -.monaco-panel-view .panel > .panel-header { - background-image: url('tree-collapsed-light.svg'); - background-position: 2px center; - background-repeat: no-repeat; +.monaco-panel-view .panel > .panel-header > .twisties { + width: 20px; + display: flex; + align-items: center; + justify-content: center; + transform-origin: center; + color: inherit; + flex-shrink: 0; } -.monaco-panel-view .panel > .panel-header.expanded { - 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('tree-collapsed-dark.svg'); -} - -.vs-dark .monaco-panel-view .panel > .panel-header.expanded { - 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'); +.monaco-panel-view .panel > .panel-header.expanded > .twisties::before { + transform: rotate(90deg); } /* TODO: actions should be part of the panel, but they aren't yet */ @@ -79,6 +65,7 @@ display: flex; align-items: center; justify-content: center; + color: inherit; } /* Bold font style does not go well with CJK fonts */ diff --git a/src/vs/base/browser/ui/splitview/panelview.ts b/src/vs/base/browser/ui/splitview/panelview.ts index 7c337dc62da..f7c63a466c6 100644 --- a/src/vs/base/browser/ui/splitview/panelview.ts +++ b/src/vs/base/browser/ui/splitview/panelview.ts @@ -9,7 +9,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { $, append, addClass, removeClass, toggleClass, trackFocus, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; +import { $, append, addClass, removeClass, toggleClass, trackFocus } from 'vs/base/browser/dom'; import { firstIndex } from 'vs/base/common/arrays'; import { Color, RGBA } from 'vs/base/common/color'; import { SplitView, IView } from './splitview'; @@ -58,6 +58,9 @@ export abstract class Panel extends Disposable implements IView { private readonly _onDidChange = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChangeExpansionState = this._register(new Emitter()); + readonly onDidChangeExpansionState: Event = this._onDidChangeExpansionState.event; + get draggableElement(): HTMLElement { return this.header; } @@ -144,6 +147,7 @@ export abstract class Panel extends Disposable implements IView { }, 200); } + this._onDidChangeExpansionState.fire(expanded); this._onDidChange.fire(expanded ? this.expandedSize : undefined); return true; } @@ -225,8 +229,8 @@ export abstract class Panel extends Disposable implements IView { this.header.setAttribute('aria-expanded', String(expanded)); this.header.style.color = this.styles.headerForeground ? this.styles.headerForeground.toString() : null; - this.header.style.backgroundColor = this.styles.headerBackground ? this.styles.headerBackground.toString() : null; - this.header.style.borderTop = this.styles.headerBorder ? `1px solid ${this.styles.headerBorder}` : null; + this.header.style.backgroundColor = this.styles.headerBackground ? this.styles.headerBackground.toString() : ''; + this.header.style.borderTop = this.styles.headerBorder ? `1px solid ${this.styles.headerBorder}` : ''; this._dropBackground = this.styles.dropBackground; } @@ -336,7 +340,7 @@ class PanelDraggable extends Disposable { backgroundColor = (this.panel.dropBackground || PanelDraggable.DefaultDragOverBackgroundColor).toString(); } - this.panel.dropTargetElement.style.backgroundColor = backgroundColor; + this.panel.dropTargetElement.style.backgroundColor = backgroundColor || ''; } } @@ -391,13 +395,7 @@ export class PanelView extends Disposable { addPanel(panel: Panel, size: number, index = this.splitview.length): void { const disposables = new DisposableStore(); - - // https://github.com/Microsoft/vscode/issues/59950 - let shouldAnimate = false; - disposables.add(scheduleAtNextAnimationFrame(() => shouldAnimate = true)); - - disposables.add(Event.filter(panel.onDidChange, () => shouldAnimate) - (this.setupAnimation, this)); + panel.onDidChangeExpansionState(this.setupAnimation, this, disposables); const panelItem = { panel, disposable: disposables }; this.panelItems.splice(index, 0, panelItem); diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 93b50dbcb4b..8b933378266 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -54,10 +54,10 @@ export interface IView { } interface ISashEvent { - sash: Sash; - start: number; - current: number; - alt: boolean; + readonly sash: Sash; + readonly start: number; + readonly current: number; + readonly alt: boolean; } type ViewItemSize = number | { cachedVisibleSize: number }; diff --git a/src/vs/base/browser/ui/splitview/tree-collapsed-dark.svg b/src/vs/base/browser/ui/splitview/tree-collapsed-dark.svg deleted file mode 100644 index c2c2298dd5c..00000000000 --- a/src/vs/base/browser/ui/splitview/tree-collapsed-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/browser/ui/splitview/tree-collapsed-hc.svg b/src/vs/base/browser/ui/splitview/tree-collapsed-hc.svg deleted file mode 100644 index 3732cbc04b8..00000000000 --- a/src/vs/base/browser/ui/splitview/tree-collapsed-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/browser/ui/splitview/tree-collapsed-light.svg b/src/vs/base/browser/ui/splitview/tree-collapsed-light.svg deleted file mode 100644 index 1952ad63f84..00000000000 --- a/src/vs/base/browser/ui/splitview/tree-collapsed-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/browser/ui/splitview/tree-expanded-dark.svg b/src/vs/base/browser/ui/splitview/tree-expanded-dark.svg deleted file mode 100644 index 5570923e175..00000000000 --- a/src/vs/base/browser/ui/splitview/tree-expanded-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/browser/ui/splitview/tree-expanded-hc.svg b/src/vs/base/browser/ui/splitview/tree-expanded-hc.svg deleted file mode 100644 index b370009330c..00000000000 --- a/src/vs/base/browser/ui/splitview/tree-expanded-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/browser/ui/splitview/tree-expanded-light.svg b/src/vs/base/browser/ui/splitview/tree-expanded-light.svg deleted file mode 100644 index 939ebc8b969..00000000000 --- a/src/vs/base/browser/ui/splitview/tree-expanded-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index 7a45bdc5938..3e13d9ce66d 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -129,9 +129,9 @@ export class ToolBar extends Disposable { } private getKeybindingLabel(action: IAction): string | undefined { - const key = this.lookupKeybindings && this.options.getKeyBinding ? this.options.getKeyBinding(action) : undefined; + const key = this.lookupKeybindings ? this.options.getKeyBinding?.(action) : undefined; - return withNullAsUndefined(key && key.getLabel()); + return withNullAsUndefined(key?.getLabel()); } addPrimaryAction(primaryAction: IAction): () => void { diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 41018dd1e50..99fd7b20463 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/tree'; import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IListOptions, List, IListStyles, MouseController, DefaultKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/listWidget'; import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/list'; -import { append, $, toggleClass, getDomNodePagePosition, removeClass, addClass, hasClass, hasParentWithClass, createStyleSheet, clearNode } from 'vs/base/browser/dom'; +import { append, $, toggleClass, getDomNodePagePosition, removeClass, addClass, hasClass, hasParentWithClass, createStyleSheet, clearNode, addClasses, removeClasses } from 'vs/base/browser/dom'; import { Event, Relay, Emitter, EventBufferer } from 'vs/base/common/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -211,6 +211,8 @@ export enum RenderIndentGuides { interface ITreeRendererOptions { readonly indent?: number; readonly renderIndentGuides?: RenderIndentGuides; + // TODO@joao replace this with collapsible: boolean | 'ondemand' + readonly hideTwistiesOfChildlessElements?: boolean; } interface IRenderData { @@ -225,36 +227,33 @@ interface Collection { class EventCollection implements Collection { - private disposables = new DisposableStore(); + readonly onDidChange: Event; 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(); + constructor(onDidChange: Event, private _elements: T[] = []) { + this.onDidChange = Event.forEach(onDidChange, elements => this._elements = elements); } } class TreeRenderer implements IListRenderer, ITreeListTemplateData> { - private static DefaultIndent = 8; + private static readonly DefaultIndent = 8; readonly templateId: string; private renderedElements = new Map>(); private renderedNodes = new Map, IRenderData>(); private indent: number = TreeRenderer.DefaultIndent; + private hideTwistiesOfChildlessElements: boolean = false; - private _renderIndentGuides: RenderIndentGuides = RenderIndentGuides.None; + private shouldRenderIndentGuides: boolean = false; private renderedIndentGuides = new SetMap, HTMLDivElement>(); private activeIndentNodes = new Set>(); private indentGuidesDisposable: IDisposable = Disposable.None; - private disposables: IDisposable[] = []; + private readonly disposables = new DisposableStore(); constructor( private renderer: ITreeRenderer, @@ -279,22 +278,25 @@ class TreeRenderer implements IListRenderer } if (typeof options.renderIndentGuides !== 'undefined') { - const renderIndentGuides = options.renderIndentGuides; + const shouldRenderIndentGuides = options.renderIndentGuides !== RenderIndentGuides.None; - if (renderIndentGuides !== this._renderIndentGuides) { - this._renderIndentGuides = renderIndentGuides; + if (shouldRenderIndentGuides !== this.shouldRenderIndentGuides) { + this.shouldRenderIndentGuides = shouldRenderIndentGuides; + this.indentGuidesDisposable.dispose(); - if (renderIndentGuides) { + if (shouldRenderIndentGuides) { const disposables = new DisposableStore(); this.activeNodes.onDidChange(this._onDidChangeActiveNodes, this, disposables); this.indentGuidesDisposable = disposables; this._onDidChangeActiveNodes(this.activeNodes.elements); - } else { - this.indentGuidesDisposable.dispose(); } } } + + if (typeof options.hideTwistiesOfChildlessElements !== 'undefined') { + this.hideTwistiesOfChildlessElements = options.hideTwistiesOfChildlessElements; + } } renderTemplate(container: HTMLElement): ITreeListTemplateData { @@ -370,8 +372,12 @@ class TreeRenderer implements IListRenderer this.renderer.renderTwistie(node.element, templateData.twistie); } - toggleClass(templateData.twistie, 'collapsible', node.collapsible); - toggleClass(templateData.twistie, 'collapsed', node.collapsible && node.collapsed); + if (node.collapsible && (!this.hideTwistiesOfChildlessElements || node.visibleChildrenCount > 0)) { + addClasses(templateData.twistie, 'codicon', 'codicon-chevron-down', 'collapsible'); + toggleClass(templateData.twistie, 'collapsed', node.collapsed); + } else { + removeClasses(templateData.twistie, 'codicon', 'codicon-chevron-down', 'collapsible', 'collapsed'); + } if (node.collapsible) { templateData.container.setAttribute('aria-expanded', String(!node.collapsed)); @@ -384,7 +390,7 @@ class TreeRenderer implements IListRenderer clearNode(templateData.indent); templateData.indentGuidesDisposable.dispose(); - if (this._renderIndentGuides === RenderIndentGuides.None) { + if (!this.shouldRenderIndentGuides) { return; } @@ -424,7 +430,7 @@ class TreeRenderer implements IListRenderer } private _onDidChangeActiveNodes(nodes: ITreeNode[]): void { - if (this._renderIndentGuides === RenderIndentGuides.None) { + if (!this.shouldRenderIndentGuides) { return; } @@ -433,12 +439,16 @@ class TreeRenderer implements IListRenderer nodes.forEach(node => { const ref = model.getNodeLocation(node); - const parentRef = model.getParentNodeLocation(ref); + try { + const parentRef = model.getParentNodeLocation(ref); - if (node.collapsible && node.children.length > 0 && !node.collapsed) { - set.add(node); - } else if (parentRef) { - set.add(model.getNode(parentRef)); + if (node.collapsible && node.children.length > 0 && !node.collapsed) { + set.add(node); + } else if (parentRef) { + set.add(model.getNode(parentRef)); + } + } catch { + // noop } }); @@ -461,7 +471,7 @@ class TreeRenderer implements IListRenderer this.renderedNodes.clear(); this.renderedElements.clear(); this.indentGuidesDisposable.dispose(); - this.disposables = dispose(this.disposables); + dispose(this.disposables); } } @@ -474,7 +484,7 @@ class TypeFilter implements ITreeFilter, IDisposable { private _pattern: string = ''; private _lowercasePattern: string = ''; - private disposables: IDisposable[] = []; + private readonly disposables = new DisposableStore(); set pattern(pattern: string) { this._pattern = pattern; @@ -549,7 +559,7 @@ class TypeFilter implements ITreeFilter, IDisposable { } dispose(): void { - this.disposables = dispose(this.disposables); + dispose(this.disposables); } } @@ -584,8 +594,8 @@ class TypeFilterController implements IDisposable { private readonly _onDidChangePattern = new Emitter(); readonly onDidChangePattern = this._onDidChangePattern.event; - private enabledDisposables: IDisposable[] = []; - private disposables: IDisposable[] = []; + private readonly enabledDisposables = new DisposableStore(); + private readonly disposables = new DisposableStore(); constructor( private tree: AbstractTree, @@ -660,6 +670,7 @@ class TypeFilterController implements IDisposable { const onKeyDown = Event.chain(domEvent(this.view.getHTMLElement(), 'keydown')) .filter(e => !isInputElement(e.target as HTMLElement) || e.target === this.filterOnTypeDomNode) + .filter(e => e.key !== 'Dead' && !/^Media/.test(e.key)) .map(e => new StandardKeyboardEvent(e)) .filter(this.keyboardNavigationEventFilter || (() => true)) .filter(() => this.automaticKeyboardNavigation || this.triggered) @@ -685,7 +696,7 @@ class TypeFilterController implements IDisposable { } this.domNode.remove(); - this.enabledDisposables = dispose(this.enabledDisposables); + this.enabledDisposables.clear(); this.tree.refilter(); this.render(); this._enabled = false; @@ -747,7 +758,7 @@ class TypeFilterController implements IDisposable { const containerWidth = container.clientWidth; const midContainerWidth = containerWidth / 2; const width = this.domNode.clientWidth; - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); let positionClassName = this.positionClassName; const updatePosition = () => { @@ -783,8 +794,8 @@ class TypeFilterController implements IDisposable { const onDragEnd = () => { this.positionClassName = positionClassName; this.domNode.className = `monaco-list-type-filter ${this.positionClassName}`; - this.domNode.style.top = null; - this.domNode.style.left = null; + this.domNode.style.top = ''; + this.domNode.style.left = ''; dispose(disposables); }; @@ -793,13 +804,13 @@ class TypeFilterController implements IDisposable { removeClass(this.domNode, positionClassName); addClass(this.domNode, 'dragging'); - disposables.push(toDisposable(() => removeClass(this.domNode, 'dragging'))); + disposables.add(toDisposable(() => removeClass(this.domNode, 'dragging'))); domEvent(document, 'dragover')(onDragOver, null, disposables); domEvent(this.domNode, 'dragend')(onDragEnd, null, disposables); StaticDND.CurrentDragAndDropData = new DragAndDropData('vscode-ui'); - disposables.push(toDisposable(() => StaticDND.CurrentDragAndDropData = undefined)); + disposables.add(toDisposable(() => StaticDND.CurrentDragAndDropData = undefined)); } private onDidSpliceModel(): void { @@ -858,9 +869,15 @@ class TypeFilterController implements IDisposable { } dispose() { - this.disable(); + if (this._enabled) { + this.domNode.remove(); + this.enabledDisposables.dispose(); + this._enabled = false; + this.triggered = false; + } + this._onDidChangePattern.dispose(); - this.disposables = dispose(this.disposables); + dispose(this.disposables); } } @@ -1001,7 +1018,6 @@ 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(); @@ -1014,13 +1030,11 @@ class Trait { if (insertedNode) { nodes.push(insertedNode); - } else { - silent = false; } } } - this._set(nodes, silent); + this._set(nodes, true); } private createNodeSet(): Set> { @@ -1181,7 +1195,7 @@ export abstract class AbstractTree implements IDisposable private typeFilterController?: TypeFilterController; private focusNavigationFilter: ((node: ITreeNode) => boolean) | undefined; private styleElement: HTMLStyleElement; - protected disposables: IDisposable[] = []; + protected readonly disposables = new DisposableStore(); get onDidScroll(): Event { return this.view.onDidScroll; } @@ -1228,19 +1242,19 @@ export abstract class AbstractTree implements IDisposable const treeDelegate = new ComposedTreeDelegate>(delegate); const onDidChangeCollapseStateRelay = new Relay>(); - const onDidChangeActiveNodes = new Emitter[]>(); + const onDidChangeActiveNodes = new Relay[]>(); const activeNodes = new EventCollection(onDidChangeActiveNodes.event); - this.disposables.push(activeNodes); - this.renderers = renderers.map(r => new TreeRenderer(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options)); - this.disposables.push(...this.renderers); + for (let r of this.renderers) { + this.disposables.add(r); + } let filter: TypeFilter | undefined; if (_options.keyboardNavigationLabelProvider) { filter = new TypeFilter(this, _options.keyboardNavigationLabelProvider, _options.filter as any as ITreeFilter); _options = { ..._options, filter: filter as ITreeFilter }; // TODO need typescript help here - this.disposables.push(filter); + this.disposables.add(filter); } this.focus = new Trait(_options.identityProvider); @@ -1250,24 +1264,35 @@ export abstract class AbstractTree implements IDisposable this.model = this.createModel(user, this.view, _options); onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState; - this.model.onDidSplice(e => { + const onDidModelSplice = Event.forEach(this.model.onDidSplice, e => { this.eventBufferer.bufferEvents(() => { this.focus.onDidModelSplice(e); this.selection.onDidModelSplice(e); }); + }); - const set = new Set>(); + // Make sure the `forEach` always runs + onDidModelSplice(() => null, null, this.disposables); - for (const node of this.focus.getNodes()) { - set.add(node); - } + // Active nodes can change when the model changes or when focus or selection change. + // We debouce it with 0 delay since these events may fire in the same stack and we only + // want to run this once. It also doesn't matter if it runs on the next tick since it's only + // a nice to have UI feature. + onDidChangeActiveNodes.input = Event.chain(Event.any(onDidModelSplice, this.focus.onDidChange, this.selection.onDidChange)) + .debounce(() => null, 0) + .map(() => { + const set = new Set>(); - for (const node of this.selection.getNodes()) { - set.add(node); - } + for (const node of this.focus.getNodes()) { + set.add(node); + } - onDidChangeActiveNodes.fire(fromSet(set)); - }, null, this.disposables); + for (const node of this.selection.getNodes()) { + set.add(node); + } + + return fromSet(set); + }).event; if (_options.keyboardSupport !== false) { const onKeyDown = Event.chain(this.view.onKeyDown) @@ -1283,7 +1308,7 @@ export abstract class AbstractTree implements IDisposable const delegate = _options.keyboardNavigationDelegate || DefaultKeyboardNavigationDelegate; this.typeFilterController = new TypeFilterController(this, this.model, this.view, filter!, delegate); this.focusNavigationFilter = node => this.typeFilterController!.shouldAllowFocus(node); - this.disposables.push(this.typeFilterController!); + this.disposables.add(this.typeFilterController!); } this.styleElement = createStyleSheet(this.view.getHTMLElement()); @@ -1358,7 +1383,7 @@ export abstract class AbstractTree implements IDisposable } get scrollLeft(): number { - return this.view.scrollTop; + return this.view.scrollLeft; } set scrollLeft(scrollLeft: number) { @@ -1637,7 +1662,7 @@ export abstract class AbstractTree implements IDisposable } dispose(): void { - this.disposables = dispose(this.disposables); + dispose(this.disposables); this.view.dispose(); } } diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 6e6efad8cac..e7514bfabe6 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -7,7 +7,7 @@ import { ComposedTreeDelegate, IAbstractTreeOptions, IAbstractTreeOptionsUpdate import { ObjectTree, IObjectTreeOptions, CompressibleObjectTree, ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider, ICompressibleObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction } from 'vs/base/browser/ui/list/list'; import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop, TreeError, WeakMapper } from 'vs/base/browser/ui/tree/tree'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { Emitter, Event } from 'vs/base/common/event'; import { timeout, CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { IListStyles } from 'vs/base/browser/ui/list/listWidget'; @@ -88,7 +88,6 @@ class AsyncDataTreeRenderer implements IT readonly templateId: string; private renderedNodes = new Map, IDataTreeListTemplateData>(); - private disposables: IDisposable[] = []; constructor( protected renderer: ITreeRenderer, @@ -108,7 +107,7 @@ class AsyncDataTreeRenderer implements IT } renderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean { - toggleClass(twistieElement, 'loading', element.slow); + toggleClass(twistieElement, 'codicon-loading', element.slow); return false; } @@ -124,7 +123,6 @@ class AsyncDataTreeRenderer implements IT dispose(): void { this.renderedNodes.clear(); - this.disposables = dispose(this.disposables); } } @@ -292,7 +290,7 @@ export class AsyncDataTree implements IDisposable protected readonly nodeMapper: AsyncDataTreeNodeMapper = new WeakMapper(node => new AsyncDataTreeNodeWrapper(node)); - protected readonly disposables: IDisposable[] = []; + protected readonly disposables = new DisposableStore(); get onDidScroll(): Event { return this.tree.onDidScroll; } @@ -930,7 +928,7 @@ export class AsyncDataTree implements IDisposable } dispose(): void { - dispose(this.disposables); + this.disposables.dispose(); } } @@ -986,7 +984,7 @@ class CompressibleAsyncDataTreeRenderer i } renderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean { - toggleClass(twistieElement, 'loading', element.slow); + toggleClass(twistieElement, 'codicon-loading', element.slow); return false; } diff --git a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts index 7abfbd15b6a..dbe8ad198b3 100644 --- a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts @@ -27,7 +27,9 @@ function noCompress(element: ICompressedTreeElement): ITreeElement(element: ICompressedTreeElement): ITreeElement(element: ITreeElement>, index = 0 } if (index === 0 && element.element.incompressible) { - return { element: element.element.elements[index], children, incompressible: true }; + return { + element: element.element.elements[index], + children, + incompressible: true, + collapsible: element.collapsible, + collapsed: element.collapsed + }; } - return { element: element.element.elements[index], children }; + return { + element: element.element.elements[index], + children, + collapsible: element.collapsible, + collapsed: element.collapsed + }; } // Exported only for test reasons, do not use directly diff --git a/src/vs/base/browser/ui/tree/dataTree.ts b/src/vs/base/browser/ui/tree/dataTree.ts index 9771eb4a544..2dbfc990a61 100644 --- a/src/vs/base/browser/ui/tree/dataTree.ts +++ b/src/vs/base/browser/ui/tree/dataTree.ts @@ -11,7 +11,7 @@ import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list import { Iterator } from 'vs/base/common/iterator'; export interface IDataTreeOptions extends IAbstractTreeOptions { - sorter?: ITreeSorter; + readonly sorter?: ITreeSorter; } export interface IDataTreeViewState { diff --git a/src/vs/base/browser/ui/tree/indexTreeModel.ts b/src/vs/base/browser/ui/tree/indexTreeModel.ts index 8616d00e8cd..c7f287e873b 100644 --- a/src/vs/base/browser/ui/tree/indexTreeModel.ts +++ b/src/vs/base/browser/ui/tree/indexTreeModel.ts @@ -442,6 +442,7 @@ export class IndexTreeModel, TFilterData = voi if (visibility === TreeVisibility.Hidden) { node.visible = false; + node.renderNodeCount = 0; return false; } diff --git a/src/vs/base/browser/ui/tree/media/panelviewlet.css b/src/vs/base/browser/ui/tree/media/panelviewlet.css index 9691ecbdeb7..7aba33ef440 100644 --- a/src/vs/base/browser/ui/tree/media/panelviewlet.css +++ b/src/vs/base/browser/ui/tree/media/panelviewlet.css @@ -8,6 +8,5 @@ text-overflow: ellipsis; overflow: hidden; font-size: 11px; - -webkit-margin-before: 0; - -webkit-margin-after: 0; + margin: 0; } diff --git a/src/vs/base/browser/ui/tree/media/tree.css b/src/vs/base/browser/ui/tree/media/tree.css index 47c1e405b96..49acc994b20 100644 --- a/src/vs/base/browser/ui/tree/media/tree.css +++ b/src/vs/base/browser/ui/tree/media/tree.css @@ -44,6 +44,11 @@ margin-right: 6px; flex-shrink: 0; width: 16px; + display: flex !important; + align-items: center; + justify-content: center; + color: inherit !important; + transform: translateX(3px); } .monaco-tl-contents { @@ -51,43 +56,10 @@ overflow: hidden; } -.monaco-tl-twistie.collapsible { - background-size: 16px; - background-position: 3px 50%; - background-repeat: no-repeat; - background-image: url("tree-expanded-light.svg"); +.monaco-tl-twistie.collapsed::before { + transform: rotate(-90deg); } -.monaco-tl-twistie.collapsible.collapsed:not(.loading) { - display: inline-block; - background-image: url("tree-collapsed-light.svg"); -} - -.vs-dark .monaco-tl-twistie.collapsible:not(.loading) { - background-image: url("tree-expanded-dark.svg"); -} - -.vs-dark .monaco-tl-twistie.collapsible.collapsed:not(.loading) { - background-image: url("tree-collapsed-dark.svg"); -} - -.hc-black .monaco-tl-twistie.collapsible:not(.loading) { - background-image: url("tree-expanded-hc.svg"); -} - -.hc-black .monaco-tl-twistie.collapsible.collapsed:not(.loading) { - background-image: url("tree-collapsed-hc.svg"); -} - -.monaco-tl-twistie.loading { - background-image: url("loading.svg"); - background-position: 0 center; -} - -.vs-dark .monaco-tl-twistie.loading { - background-image: url("loading-dark.svg"); -} - -.hc-black .monaco-tl-twistie.loading { - background-image: url("loading-hc.svg"); +.monaco-tl-twistie.codicon-loading::before { + animation: codicon-spin 1.25s linear infinite; } diff --git a/src/vs/base/browser/ui/tree/objectTree.ts b/src/vs/base/browser/ui/tree/objectTree.ts index eff86b6ab5e..b168e7e14ce 100644 --- a/src/vs/base/browser/ui/tree/objectTree.ts +++ b/src/vs/base/browser/ui/tree/objectTree.ts @@ -14,7 +14,7 @@ import { CompressibleObjectTreeModel, ElementMapper, ICompressedTreeNode, ICompr import { memoize } from 'vs/base/common/decorators'; export interface IObjectTreeOptions extends IAbstractTreeOptions { - sorter?: ITreeSorter; + readonly sorter?: ITreeSorter; } export class ObjectTree, TFilterData = void> extends AbstractTree { @@ -59,10 +59,6 @@ interface ICompressedTreeNodeProvider { getCompressedTreeNode(element: T): ITreeNode, TFilterData>; } -export interface ICompressibleObjectTreeOptions extends IObjectTreeOptions { - readonly elementMapper?: ElementMapper; -} - export interface ICompressibleTreeRenderer extends ITreeRenderer { renderCompressedElements(node: ITreeNode, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void; disposeCompressedElements?(node: ITreeNode, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void; @@ -136,6 +132,7 @@ export interface ICompressibleKeyboardNavigationLabelProvider extends IKeyboa } export interface ICompressibleObjectTreeOptions extends IObjectTreeOptions { + readonly elementMapper?: ElementMapper; readonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider; } @@ -164,7 +161,7 @@ function asObjectTreeOptions(compressedTreeNodeProvider: () => I export class CompressibleObjectTree, TFilterData = void> extends ObjectTree implements ICompressedTreeNodeProvider { - protected model: CompressibleObjectTreeModel; + protected model!: CompressibleObjectTreeModel; constructor( user: string, diff --git a/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts index d21b8ba3836..9d6b9749510 100644 --- a/src/vs/base/browser/ui/tree/objectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/objectTreeModel.ts @@ -257,7 +257,12 @@ export class ObjectTreeModel, TFilterData extends Non throw new TreeError(this.user, `Invalid getParentNodeLocation call`); } - const node = this.nodes.get(element)!; + const node = this.nodes.get(element); + + if (!node) { + throw new TreeError(this.user, `Tree element not found: ${element}`); + } + const location = this.model.getNodeLocation(node); const parentLocation = this.model.getParentNodeLocation(location); const parent = this.model.getNode(parentLocation); diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index e6e769ea897..135008aa81d 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -29,7 +29,6 @@ export interface IAction extends IDisposable { class: string | undefined; enabled: boolean; checked: boolean; - radio: boolean; run(event?: any): Promise; } @@ -54,7 +53,6 @@ export interface IActionChangeEvent { readonly class?: string; readonly enabled?: boolean; readonly checked?: boolean; - readonly radio?: boolean; } export class Action extends Disposable implements IAction { @@ -68,7 +66,6 @@ export class Action extends Disposable implements IAction { protected _cssClass: string | undefined; protected _enabled: boolean = true; protected _checked: boolean = false; - protected _radio: boolean = false; protected readonly _actionCallback?: (event?: any) => Promise; constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Promise) { @@ -152,14 +149,6 @@ export class Action extends Disposable implements IAction { this._setChecked(value); } - get radio(): boolean { - return this._radio; - } - - set radio(value: boolean) { - this._setRadio(value); - } - protected _setChecked(value: boolean): void { if (this._checked !== value) { this._checked = value; @@ -167,13 +156,6 @@ export class Action extends Disposable implements IAction { } } - protected _setRadio(value: boolean): void { - if (this._radio !== value) { - this._radio = value; - this._onDidChange.fire({ radio: value }); - } - } - run(event?: any, _data?: ITelemetryData): Promise { if (this._actionCallback) { return this._actionCallback(event); diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 6906e1376ec..39055d0201e 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -764,5 +764,5 @@ export async function retry(task: ITask>, delay: number, retries: } } - return Promise.reject(lastError); + throw lastError; } diff --git a/src/vs/base/common/buffer.ts b/src/vs/base/common/buffer.ts index 99d5e5274e1..25371f5ec79 100644 --- a/src/vs/base/common/buffer.ts +++ b/src/vs/base/common/buffer.ts @@ -3,8 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as strings from 'vs/base/common/strings'; +import * as streams from 'vs/base/common/stream'; + declare var Buffer: any; -export const hasBuffer = (typeof Buffer !== 'undefined'); + +const hasBuffer = (typeof Buffer !== 'undefined'); +const hasTextEncoder = (typeof TextEncoder !== 'undefined'); +const hasTextDecoder = (typeof TextDecoder !== 'undefined'); let textEncoder: TextEncoder | null; let textDecoder: TextDecoder | null; @@ -31,11 +37,13 @@ export class VSBuffer { static fromString(source: string): VSBuffer { if (hasBuffer) { return new VSBuffer(Buffer.from(source)); - } else { + } else if (hasTextEncoder) { if (!textEncoder) { textEncoder = new TextEncoder(); } return new VSBuffer(textEncoder.encode(source)); + } else { + return new VSBuffer(strings.encodeUTF8(source)); } } @@ -69,11 +77,13 @@ export class VSBuffer { toString(): string { if (hasBuffer) { return this.buffer.toString(); - } else { + } else if (hasTextDecoder) { if (!textDecoder) { textDecoder = new TextDecoder(); } return textDecoder.decode(this.buffer); + } else { + return strings.decodeUTF8(this.buffer); } } @@ -132,335 +142,32 @@ function writeUInt8(destination: Uint8Array, value: number, offset: number): voi destination[offset] = value; } -export interface VSBufferReadable { +export interface VSBufferReadable extends streams.Readable { } - /** - * Read data from the underlying source. Will return - * null to indicate that no more data can be read. - */ - read(): VSBuffer | null; -} +export interface VSBufferReadableStream extends streams.ReadableStream { } -export interface ReadableStream { +export interface VSBufferWriteableStream extends streams.WriteableStream { } - /** - * The 'data' event is emitted whenever the stream is - * relinquishing ownership of a chunk of data to a consumer. - */ - on(event: 'data', callback: (chunk: T) => void): void; - - /** - * Emitted when any error occurs. - */ - on(event: 'error', callback: (err: any) => void): void; - - /** - * The 'end' event is emitted when there is no more data - * to be consumed from the stream. The 'end' event will - * not be emitted unless the data is completely consumed. - */ - on(event: 'end', callback: () => void): void; - - /** - * Stops emitting any events until resume() is called. - */ - pause?(): void; - - /** - * Starts emitting events again after pause() was called. - */ - 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. - */ export function readableToBuffer(readable: VSBufferReadable): VSBuffer { - const chunks: VSBuffer[] = []; - - let chunk: VSBuffer | null; - while (chunk = readable.read()) { - chunks.push(chunk); - } - - return VSBuffer.concat(chunks); + return streams.consumeReadable(readable, chunks => VSBuffer.concat(chunks)); } -/** - * Helper to convert a buffer into a readable buffer. - */ export function bufferToReadable(buffer: VSBuffer): VSBufferReadable { - let done = false; - - return { - read: () => { - if (done) { - return null; - } - - done = true; - - return buffer; - } - }; + return streams.toReadable(buffer); } -/** - * Helper to fully read a VSBuffer stream into a single buffer. - */ -export function streamToBuffer(stream: VSBufferReadableStream): Promise { - return new Promise((resolve, reject) => { - const chunks: VSBuffer[] = []; - - stream.on('data', chunk => chunks.push(chunk)); - stream.on('error', error => reject(error)); - stream.on('end', () => resolve(VSBuffer.concat(chunks))); - }); +export function streamToBuffer(stream: streams.ReadableStream): Promise { + return streams.consumeStream(stream, chunks => VSBuffer.concat(chunks)); } -/** - * Helper to create a VSBufferStream from an existing VSBuffer. - */ -export function bufferToStream(buffer: VSBuffer): VSBufferReadableStream { - const stream = writeableBufferStream(); - - stream.end(buffer); - - return stream; +export function bufferToStream(buffer: VSBuffer): streams.ReadableStream { + return streams.toStream(buffer, chunks => VSBuffer.concat(chunks)); } -/** - * 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; +export function streamToBufferReadableStream(stream: streams.ReadableStreamEvents): streams.ReadableStream { + return streams.transform(stream, { data: data => typeof data === 'string' ? VSBuffer.fromString(data) : VSBuffer.wrap(data) }, chunks => VSBuffer.concat(chunks)); } -/** - * Helper to create a VSBufferStream that can be pushed - * buffers to. Will only start to emit data when a listener - * is added. - */ -export function writeableBufferStream(): VSBufferWriteableStream { - return new VSBufferWriteableStreamImpl(); -} - -export interface VSBufferWriteableStream extends VSBufferReadableStream { - write(chunk: VSBuffer): void; - error(error: Error): void; - end(result?: VSBuffer | Error): void; -} - -class VSBufferWriteableStreamImpl implements VSBufferWriteableStream { - - private readonly state = { - flowing: false, - ended: false, - destroyed: false - }; - - private readonly buffer = { - data: [] as VSBuffer[], - error: [] as Error[] - }; - - private readonly listeners = { - data: [] as { (chunk: VSBuffer): void }[], - error: [] as { (error: Error): void }[], - end: [] as { (): void }[] - }; - - pause(): void { - if (this.state.destroyed) { - return; - } - - this.state.flowing = false; - } - - resume(): void { - if (this.state.destroyed) { - return; - } - - if (!this.state.flowing) { - this.state.flowing = true; - - // emit buffered events - this.flowData(); - this.flowErrors(); - this.flowEnd(); - } - } - - write(chunk: VSBuffer): void { - if (this.state.destroyed) { - return; - } - - // flowing: directly send the data to listeners - if (this.state.flowing) { - this.listeners.data.forEach(listener => listener(chunk)); - } - - // not yet flowing: buffer data until flowing - else { - this.buffer.data.push(chunk); - } - } - - error(error: Error): void { - if (this.state.destroyed) { - return; - } - - // flowing: directly send the error to listeners - if (this.state.flowing) { - this.listeners.error.forEach(listener => listener(error)); - } - - // not yet flowing: buffer errors until flowing - else { - this.buffer.error.push(error); - } - } - - end(result?: VSBuffer | Error): void { - if (this.state.destroyed) { - return; - } - - // end with data or error if provided - if (result instanceof Error) { - this.error(result); - } else if (result) { - this.write(result); - } - - // flowing: send end event to listeners - if (this.state.flowing) { - this.listeners.end.forEach(listener => listener()); - - this.destroy(); - } - - // not yet flowing: remember state - else { - this.state.ended = true; - } - } - - on(event: 'data', callback: (chunk: VSBuffer) => void): void; - on(event: 'error', callback: (err: any) => void): void; - on(event: 'end', callback: () => void): void; - on(event: 'data' | 'error' | 'end', callback: (arg0?: any) => void): void { - if (this.state.destroyed) { - return; - } - - switch (event) { - case 'data': - this.listeners.data.push(callback); - - // switch into flowing mode as soon as the first 'data' - // listener is added and we are not yet in flowing mode - this.resume(); - - break; - - case 'end': - this.listeners.end.push(callback); - - // emit 'end' event directly if we are flowing - // and the end has already been reached - // - // finish() when it went through - if (this.state.flowing && this.flowEnd()) { - this.destroy(); - } - - break; - - case 'error': - this.listeners.error.push(callback); - - // emit buffered 'error' events unless done already - // now that we know that we have at least one listener - if (this.state.flowing) { - this.flowErrors(); - } - - break; - } - } - - private flowData(): void { - if (this.buffer.data.length > 0) { - const fullDataBuffer = VSBuffer.concat(this.buffer.data); - - this.listeners.data.forEach(listener => listener(fullDataBuffer)); - - this.buffer.data.length = 0; - } - } - - private flowErrors(): void { - if (this.listeners.error.length > 0) { - for (const error of this.buffer.error) { - this.listeners.error.forEach(listener => listener(error)); - } - - this.buffer.error.length = 0; - } - } - - private flowEnd(): boolean { - if (this.state.ended) { - this.listeners.end.forEach(listener => listener()); - - return this.listeners.end.length > 0; - } - - return false; - } - - destroy(): void { - if (!this.state.destroyed) { - this.state.destroyed = true; - this.state.ended = true; - - this.buffer.data.length = 0; - this.buffer.error.length = 0; - - this.listeners.data.length = 0; - this.listeners.error.length = 0; - this.listeners.end.length = 0; - } - } +export function newWriteableBufferStream(): streams.WriteableStream { + return streams.newWriteableStream(chunks => VSBuffer.concat(chunks)); } diff --git a/src/vs/base/common/cancellation.ts b/src/vs/base/common/cancellation.ts index fb274fb941f..f741f6b7af1 100644 --- a/src/vs/base/common/cancellation.ts +++ b/src/vs/base/common/cancellation.ts @@ -116,7 +116,10 @@ export class CancellationTokenSource { } } - dispose(): void { + dispose(cancel: boolean = false): void { + if (cancel) { + this.cancel(); + } if (this._parentListener) { this._parentListener.dispose(); } diff --git a/src/vs/base/common/codicon.ts b/src/vs/base/common/codicon.ts new file mode 100644 index 00000000000..51189279780 --- /dev/null +++ b/src/vs/base/common/codicon.ts @@ -0,0 +1,135 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { matchesFuzzy, IMatch } from 'vs/base/common/filters'; +import { ltrim } from 'vs/base/common/strings'; + +const codiconStartMarker = '$('; + +export interface IParsedCodicons { + readonly text: string; + readonly codiconOffsets?: readonly number[]; +} + +export function parseCodicons(text: string): IParsedCodicons { + const firstCodiconIndex = text.indexOf(codiconStartMarker); + if (firstCodiconIndex === -1) { + return { text }; // return early if the word does not include an codicon + } + + return doParseCodicons(text, firstCodiconIndex); +} + +function doParseCodicons(text: string, firstCodiconIndex: number): IParsedCodicons { + const codiconOffsets: number[] = []; + let textWithoutCodicons: string = ''; + + function appendChars(chars: string) { + if (chars) { + textWithoutCodicons += chars; + + for (const _ of chars) { + codiconOffsets.push(codiconsOffset); // make sure to fill in codicon offsets + } + } + } + + let currentCodiconStart = -1; + let currentCodiconValue: string = ''; + let codiconsOffset = 0; + + let char: string; + let nextChar: string; + + let offset = firstCodiconIndex; + const length = text.length; + + // Append all characters until the first codicon + appendChars(text.substr(0, firstCodiconIndex)); + + // example: $(file-symlink-file) my cool $(other-codicon) entry + while (offset < length) { + char = text[offset]; + nextChar = text[offset + 1]; + + // beginning of codicon: some value $( <-- + if (char === codiconStartMarker[0] && nextChar === codiconStartMarker[1]) { + currentCodiconStart = offset; + + // if we had a previous potential codicon value without + // the closing ')', it was actually not an codicon and + // so we have to add it to the actual value + appendChars(currentCodiconValue); + + currentCodiconValue = codiconStartMarker; + + offset++; // jump over '(' + } + + // end of codicon: some value $(some-codicon) <-- + else if (char === ')' && currentCodiconStart !== -1) { + const currentCodiconLength = offset - currentCodiconStart + 1; // +1 to include the closing ')' + codiconsOffset += currentCodiconLength; + currentCodiconStart = -1; + currentCodiconValue = ''; + } + + // within codicon + else if (currentCodiconStart !== -1) { + // Make sure this is a real codicon name + if (/^[a-z0-9\-]$/i.test(char)) { + currentCodiconValue += char; + } else { + // This is not a real codicon, treat it as text + appendChars(currentCodiconValue); + + currentCodiconStart = -1; + currentCodiconValue = ''; + } + } + + // any value outside of codicons + else { + appendChars(char); + } + + offset++; + } + + // if we had a previous potential codicon value without + // the closing ')', it was actually not an codicon and + // so we have to add it to the actual value + appendChars(currentCodiconValue); + + return { text: textWithoutCodicons, codiconOffsets }; +} + +export function matchesFuzzyCodiconAware(query: string, target: IParsedCodicons, enableSeparateSubstringMatching = false): IMatch[] | null { + const { text, codiconOffsets } = target; + + // Return early if there are no codicon markers in the word to match against + if (!codiconOffsets || codiconOffsets.length === 0) { + return matchesFuzzy(query, text, enableSeparateSubstringMatching); + } + + // Trim the word to match against because it could have leading + // whitespace now if the word started with an codicon + const wordToMatchAgainstWithoutCodiconsTrimmed = ltrim(text, ' '); + const leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutCodiconsTrimmed.length; + + // match on value without codicons + const matches = matchesFuzzy(query, wordToMatchAgainstWithoutCodiconsTrimmed, enableSeparateSubstringMatching); + + // Map matches back to offsets with codicons and trimming + if (matches) { + for (const match of matches) { + const codiconOffset = codiconOffsets[match.start + leadingWhitespaceOffset] /* codicon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */; + match.start += codiconOffset; + match.end += codiconOffset; + } + } + + return matches; +} diff --git a/src/vs/base/common/color.ts b/src/vs/base/common/color.ts index 97528a4534c..8068e76aadd 100644 --- a/src/vs/base/common/color.ts +++ b/src/vs/base/common/color.ts @@ -507,10 +507,6 @@ export namespace Color { * The default format will use HEX if opaque and RGBA otherwise. */ export function format(color: Color): string | null { - if (!color) { - return null; - } - if (color.isOpaque()) { return Color.Format.CSS.formatHex(color); } @@ -524,11 +520,6 @@ export namespace Color { * @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA). */ export function parseHex(hex: string): Color | null { - if (!hex) { - // Invalid color - return null; - } - const length = hex.length; if (length === 0) { diff --git a/src/vs/base/common/diff/diff.ts b/src/vs/base/common/diff/diff.ts index 6eb26b885af..d81c79eaaa1 100644 --- a/src/vs/base/common/diff/diff.ts +++ b/src/vs/base/common/diff/diff.ts @@ -4,22 +4,29 @@ *--------------------------------------------------------------------------------------------*/ import { DiffChange } from 'vs/base/common/diff/diffChange'; +import { stringHash } from 'vs/base/common/hash'; +import { Constants } from 'vs/base/common/uint'; -function createStringSequence(a: string): ISequence { - return { - getLength() { return a.length; }, - getElementAtIndex(pos: number) { return a.charCodeAt(pos); } - }; +export class StringDiffSequence implements ISequence { + + constructor(private source: string) { } + + getElements(): Int32Array | number[] | string[] { + const source = this.source; + const characters = new Int32Array(source.length); + for (let i = 0, len = source.length; i < len; i++) { + characters[i] = source.charCodeAt(i); + } + return characters; + } } export function stringDiff(original: string, modified: string, pretty: boolean): IDiffChange[] { - return new LcsDiff(createStringSequence(original), createStringSequence(modified)).ComputeDiff(pretty); + return new LcsDiff(new StringDiffSequence(original), new StringDiffSequence(modified)).ComputeDiff(pretty).changes; } - export interface ISequence { - getLength(): number; - getElementAtIndex(index: number): number | string; + getElements(): Int32Array | number[] | string[]; } export interface IDiffChange { @@ -49,7 +56,12 @@ export interface IDiffChange { } export interface IContinueProcessingPredicate { - (furthestOriginalIndex: number, originalSequence: ISequence, matchLengthOfLongest: number): boolean; + (furthestOriginalIndex: number, matchLengthOfLongest: number): boolean; +} + +export interface IDiffResult { + quitEarly: boolean; + changes: IDiffChange[]; } // @@ -86,6 +98,11 @@ export class MyArray { destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i]; } } + public static Copy2(sourceArray: Int32Array, sourceIndex: number, destinationArray: Int32Array, destinationIndex: number, length: number) { + for (let i = 0; i < length; i++) { + destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i]; + } + } } //***************************************************************************** @@ -100,11 +117,9 @@ export class MyArray { // Our total memory usage for storing history is (worst-case): // 2 * [(MaxDifferencesHistory + 1) * (MaxDifferencesHistory + 1) - 1] * sizeof(int) // 2 * [1448*1448 - 1] * 4 = 16773624 = 16MB -let MaxDifferencesHistory = 1447; -//let MaxDifferencesHistory = 100; - - - +const enum LocalConstants { + MaxDifferencesHistory = 1447 +} /** * A utility class which helps to create the set of DiffChanges from @@ -127,8 +142,8 @@ class DiffChangeHelper { */ constructor() { this.m_changes = []; - this.m_originalStart = Number.MAX_VALUE; - this.m_modifiedStart = Number.MAX_VALUE; + this.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER; + this.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER; this.m_originalCount = 0; this.m_modifiedCount = 0; } @@ -147,8 +162,8 @@ class DiffChangeHelper { // Reset for the next change this.m_originalCount = 0; this.m_modifiedCount = 0; - this.m_originalStart = Number.MAX_VALUE; - this.m_modifiedStart = Number.MAX_VALUE; + this.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER; + this.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER; } /** @@ -214,39 +229,81 @@ class DiffChangeHelper { */ export class LcsDiff { - private OriginalSequence: ISequence; - private ModifiedSequence: ISequence; - private ContinueProcessingPredicate: IContinueProcessingPredicate | null; + private readonly ContinueProcessingPredicate: IContinueProcessingPredicate | null; - private m_forwardHistory: number[][]; - private m_reverseHistory: number[][]; + private readonly _hasStrings: boolean; + private readonly _originalStringElements: string[]; + private readonly _originalElementsOrHash: Int32Array; + private readonly _modifiedStringElements: string[]; + private readonly _modifiedElementsOrHash: Int32Array; + + private m_forwardHistory: Int32Array[]; + private m_reverseHistory: Int32Array[]; /** * Constructs the DiffFinder */ - constructor(originalSequence: ISequence, newSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) { - this.OriginalSequence = originalSequence; - this.ModifiedSequence = newSequence; + constructor(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) { this.ContinueProcessingPredicate = continueProcessingPredicate; + const [originalStringElements, originalElementsOrHash, originalHasStrings] = LcsDiff._getElements(originalSequence); + const [modifiedStringElements, modifiedElementsOrHash, modifiedHasStrings] = LcsDiff._getElements(modifiedSequence); + + this._hasStrings = (originalHasStrings && modifiedHasStrings); + this._originalStringElements = originalStringElements; + this._originalElementsOrHash = originalElementsOrHash; + this._modifiedStringElements = modifiedStringElements; + this._modifiedElementsOrHash = modifiedElementsOrHash; + this.m_forwardHistory = []; this.m_reverseHistory = []; } + private static _isStringArray(arr: Int32Array | number[] | string[]): arr is string[] { + return (arr.length > 0 && typeof arr[0] === 'string'); + } + + private static _getElements(sequence: ISequence): [string[], Int32Array, boolean] { + const elements = sequence.getElements(); + + if (LcsDiff._isStringArray(elements)) { + const hashes = new Int32Array(elements.length); + for (let i = 0, len = elements.length; i < len; i++) { + hashes[i] = stringHash(elements[i], 0); + } + return [elements, hashes, true]; + } + + if (elements instanceof Int32Array) { + return [[], elements, false]; + } + + return [[], new Int32Array(elements), false]; + } + private ElementsAreEqual(originalIndex: number, newIndex: number): boolean { - return (this.OriginalSequence.getElementAtIndex(originalIndex) === this.ModifiedSequence.getElementAtIndex(newIndex)); + if (this._originalElementsOrHash[originalIndex] !== this._modifiedElementsOrHash[newIndex]) { + return false; + } + return (this._hasStrings ? this._originalStringElements[originalIndex] === this._modifiedStringElements[newIndex] : true); } private OriginalElementsAreEqual(index1: number, index2: number): boolean { - return (this.OriginalSequence.getElementAtIndex(index1) === this.OriginalSequence.getElementAtIndex(index2)); + if (this._originalElementsOrHash[index1] !== this._originalElementsOrHash[index2]) { + return false; + } + return (this._hasStrings ? this._originalStringElements[index1] === this._originalStringElements[index2] : true); } private ModifiedElementsAreEqual(index1: number, index2: number): boolean { - return (this.ModifiedSequence.getElementAtIndex(index1) === this.ModifiedSequence.getElementAtIndex(index2)); + if (this._modifiedElementsOrHash[index1] !== this._modifiedElementsOrHash[index2]) { + return false; + } + return (this._hasStrings ? this._modifiedStringElements[index1] === this._modifiedStringElements[index2] : true); } - public ComputeDiff(pretty: boolean): IDiffChange[] { - return this._ComputeDiff(0, this.OriginalSequence.getLength() - 1, 0, this.ModifiedSequence.getLength() - 1, pretty); + public ComputeDiff(pretty: boolean): IDiffResult { + return this._ComputeDiff(0, this._originalElementsOrHash.length - 1, 0, this._modifiedElementsOrHash.length - 1, pretty); } /** @@ -254,18 +311,21 @@ export class LcsDiff { * sequences on the bounded range. * @returns An array of the differences between the two input sequences. */ - private _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): DiffChange[] { - let quitEarlyArr = [false]; + private _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): IDiffResult { + const quitEarlyArr = [false]; let changes = this.ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr); if (pretty) { // We have to clean up the computed diff to be more intuitive // but it turns out this cannot be done correctly until the entire set // of diffs have been computed - return this.PrettifyChanges(changes); + changes = this.PrettifyChanges(changes); } - return changes; + return { + quitEarly: quitEarlyArr[0], + changes: changes + }; } /** @@ -318,11 +378,12 @@ export class LcsDiff { } // This problem can be solved using the Divide-And-Conquer technique. - let midOriginalArr = [0], midModifiedArr = [0]; - let result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr); + const midOriginalArr = [0]; + const midModifiedArr = [0]; + const result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr); - let midOriginal = midOriginalArr[0]; - let midModified = midModifiedArr[0]; + const midOriginal = midOriginalArr[0]; + const midModified = midModifiedArr[0]; if (result !== null) { // Result is not-null when there was enough memory to compute the changes while @@ -334,7 +395,7 @@ export class LcsDiff { // Second Half: (midOriginal + 1, minModified + 1) to (originalEnd, modifiedEnd) // NOTE: ComputeDiff() is inclusive, therefore the second range starts on the next point - let leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr); + const leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr); let rightChanges: DiffChange[] = []; if (!quitEarlyArr[0]) { @@ -358,24 +419,25 @@ export class LcsDiff { private WALKTRACE(diagonalForwardBase: number, diagonalForwardStart: number, diagonalForwardEnd: number, diagonalForwardOffset: number, diagonalReverseBase: number, diagonalReverseStart: number, diagonalReverseEnd: number, diagonalReverseOffset: number, - forwardPoints: number[], reversePoints: number[], + forwardPoints: Int32Array, reversePoints: Int32Array, originalIndex: number, originalEnd: number, midOriginalArr: number[], modifiedIndex: number, modifiedEnd: number, midModifiedArr: number[], - deltaIsEven: boolean, quitEarlyArr: boolean[]): DiffChange[] { - let forwardChanges: DiffChange[] | null = null, reverseChanges: DiffChange[] | null = null; + deltaIsEven: boolean, quitEarlyArr: boolean[] + ): DiffChange[] { + let forwardChanges: DiffChange[] | null = null; + let reverseChanges: DiffChange[] | null = null; // First, walk backward through the forward diagonals history let changeHelper = new DiffChangeHelper(); let diagonalMin = diagonalForwardStart; let diagonalMax = diagonalForwardEnd; let diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalForwardOffset; - let lastOriginalIndex = Number.MIN_VALUE; + let lastOriginalIndex = Constants.MIN_SAFE_SMALL_INTEGER; let historyIndex = this.m_forwardHistory.length - 1; - let diagonal: number; do { // Get the diagonal index from the relative diagonal number - diagonal = diagonalRelative + diagonalForwardBase; + const diagonal = diagonalRelative + diagonalForwardBase; // Figure out where we came from if (diagonal === diagonalMin || (diagonal < diagonalMax && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) { @@ -420,7 +482,7 @@ export class LcsDiff { let modifiedStartPoint = midModifiedArr[0] + 1; if (forwardChanges !== null && forwardChanges.length > 0) { - let lastForwardChange = forwardChanges[forwardChanges.length - 1]; + const lastForwardChange = forwardChanges[forwardChanges.length - 1]; originalStartPoint = Math.max(originalStartPoint, lastForwardChange.getOriginalEnd()); modifiedStartPoint = Math.max(modifiedStartPoint, lastForwardChange.getModifiedEnd()); } @@ -435,12 +497,12 @@ export class LcsDiff { diagonalMin = diagonalReverseStart; diagonalMax = diagonalReverseEnd; diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalReverseOffset; - lastOriginalIndex = Number.MAX_VALUE; + lastOriginalIndex = Constants.MAX_SAFE_SMALL_INTEGER; historyIndex = (deltaIsEven) ? this.m_reverseHistory.length - 1 : this.m_reverseHistory.length - 2; do { // Get the diagonal index from the relative diagonal number - diagonal = diagonalRelative + diagonalReverseBase; + const diagonal = diagonalRelative + diagonalReverseBase; // Figure out where we came from if (diagonal === diagonalMin || (diagonal < diagonalMax && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) { @@ -501,7 +563,6 @@ export class LcsDiff { let originalIndex = 0, modifiedIndex = 0; let diagonalForwardStart = 0, diagonalForwardEnd = 0; let diagonalReverseStart = 0, diagonalReverseEnd = 0; - let numDifferences: number; // To traverse the edit graph and produce the proper LCS, our actual // start position is just outside the given boundary @@ -521,26 +582,26 @@ export class LcsDiff { // The integer value in the cell represents the originalIndex of the furthest // reaching point found so far that ends in that diagonal. // The modifiedIndex can be computed mathematically from the originalIndex and the diagonal number. - let maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart); - let numDiagonals = maxDifferences + 1; - let forwardPoints: number[] = new Array(numDiagonals); - let reversePoints: number[] = new Array(numDiagonals); + const maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart); + const numDiagonals = maxDifferences + 1; + const forwardPoints = new Int32Array(numDiagonals); + const reversePoints = new Int32Array(numDiagonals); // diagonalForwardBase: Index into forwardPoints of the diagonal which passes through (originalStart, modifiedStart) // diagonalReverseBase: Index into reversePoints of the diagonal which passes through (originalEnd, modifiedEnd) - let diagonalForwardBase = (modifiedEnd - modifiedStart); - let diagonalReverseBase = (originalEnd - originalStart); + const diagonalForwardBase = (modifiedEnd - modifiedStart); + const diagonalReverseBase = (originalEnd - originalStart); // diagonalForwardOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the // diagonal number (relative to diagonalForwardBase) // diagonalReverseOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the // diagonal number (relative to diagonalReverseBase) - let diagonalForwardOffset = (originalStart - modifiedStart); - let diagonalReverseOffset = (originalEnd - modifiedEnd); + const diagonalForwardOffset = (originalStart - modifiedStart); + const diagonalReverseOffset = (originalEnd - modifiedEnd); // delta: The difference between the end diagonal and the start diagonal. This is used to relate diagonal numbers // relative to the start diagonal with diagonal numbers relative to the end diagonal. // The Even/Oddn-ness of this delta is important for determining when we should check for overlap - let delta = diagonalReverseBase - diagonalForwardBase; - let deltaIsEven = (delta % 2 === 0); + const delta = diagonalReverseBase - diagonalForwardBase; + const deltaIsEven = (delta % 2 === 0); // Here we set up the start and end points as the furthest points found so far // in both the forward and reverse directions, respectively @@ -559,15 +620,14 @@ export class LcsDiff { // away from the reference diagonal (which is diagonalForwardBase for forward, diagonalReverseBase for reverse). // --We extend on even diagonals (relative to the reference diagonal) only when numDifferences // is even and odd diagonals only when numDifferences is odd. - let diagonal: number, tempOriginalIndex: number; - for (numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) { + for (let numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) { let furthestOriginalIndex = 0; let furthestModifiedIndex = 0; // Run the algorithm in the forward direction diagonalForwardStart = this.ClipDiagonalBound(diagonalForwardBase - numDifferences, numDifferences, diagonalForwardBase, numDiagonals); diagonalForwardEnd = this.ClipDiagonalBound(diagonalForwardBase + numDifferences, numDifferences, diagonalForwardBase, numDiagonals); - for (diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) { + for (let diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) { // STEP 1: We extend the furthest reaching point in the present diagonal // by looking at the diagonals above and below and picking the one whose point // is further away from the start point (originalStart, modifiedStart) @@ -579,7 +639,7 @@ export class LcsDiff { modifiedIndex = originalIndex - (diagonal - diagonalForwardBase) - diagonalForwardOffset; // Save the current originalIndex so we can test for false overlap in step 3 - tempOriginalIndex = originalIndex; + const tempOriginalIndex = originalIndex; // STEP 2: We can continue to extend the furthest reaching point in the present diagonal // so long as the elements are equal. @@ -603,7 +663,7 @@ export class LcsDiff { midOriginalArr[0] = originalIndex; midModifiedArr[0] = modifiedIndex; - if (tempOriginalIndex <= reversePoints[diagonal] && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) { + if (tempOriginalIndex <= reversePoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) { // BINGO! We overlapped, and we have the full trace in memory! return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset, @@ -622,9 +682,9 @@ export class LcsDiff { } // Check to see if we should be quitting early, before moving on to the next iteration. - let matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2; + const matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2; - if (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, this.OriginalSequence, matchLengthOfLongest)) { + if (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, matchLengthOfLongest)) { // We can't finish, so skip ahead to generating a result from what we have. quitEarlyArr[0] = true; @@ -632,7 +692,7 @@ export class LcsDiff { midOriginalArr[0] = furthestOriginalIndex; midModifiedArr[0] = furthestModifiedIndex; - if (matchLengthOfLongest > 0 && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) { + if (matchLengthOfLongest > 0 && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) { // Enough of the history is in memory to walk it backwards return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset, @@ -659,7 +719,7 @@ export class LcsDiff { // Run the algorithm in the reverse direction diagonalReverseStart = this.ClipDiagonalBound(diagonalReverseBase - numDifferences, numDifferences, diagonalReverseBase, numDiagonals); diagonalReverseEnd = this.ClipDiagonalBound(diagonalReverseBase + numDifferences, numDifferences, diagonalReverseBase, numDiagonals); - for (diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) { + for (let diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) { // STEP 1: We extend the furthest reaching point in the present diagonal // by looking at the diagonals above and below and picking the one whose point // is further away from the start point (originalEnd, modifiedEnd) @@ -671,7 +731,7 @@ export class LcsDiff { modifiedIndex = originalIndex - (diagonal - diagonalReverseBase) - diagonalReverseOffset; // Save the current originalIndex so we can test for false overlap - tempOriginalIndex = originalIndex; + const tempOriginalIndex = originalIndex; // STEP 2: We can continue to extend the furthest reaching point in the present diagonal // as long as the elements are equal. @@ -689,7 +749,7 @@ export class LcsDiff { midOriginalArr[0] = originalIndex; midModifiedArr[0] = modifiedIndex; - if (tempOriginalIndex >= forwardPoints[diagonal] && MaxDifferencesHistory > 0 && numDifferences <= (MaxDifferencesHistory + 1)) { + if (tempOriginalIndex >= forwardPoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) { // BINGO! We overlapped, and we have the full trace in memory! return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset, @@ -708,24 +768,22 @@ export class LcsDiff { } // Save current vectors to history before the next iteration - if (numDifferences <= MaxDifferencesHistory) { + if (numDifferences <= LocalConstants.MaxDifferencesHistory) { // We are allocating space for one extra int, which we fill with // the index of the diagonal base index - let temp: number[] = new Array(diagonalForwardEnd - diagonalForwardStart + 2); + let temp = new Int32Array(diagonalForwardEnd - diagonalForwardStart + 2); temp[0] = diagonalForwardBase - diagonalForwardStart + 1; - MyArray.Copy(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1); + MyArray.Copy2(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1); this.m_forwardHistory.push(temp); - temp = new Array(diagonalReverseEnd - diagonalReverseStart + 2); + temp = new Int32Array(diagonalReverseEnd - diagonalReverseStart + 2); temp[0] = diagonalReverseBase - diagonalReverseStart + 1; - MyArray.Copy(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1); + MyArray.Copy2(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1); this.m_reverseHistory.push(temp); } } - - // If we got here, then we have the full trace in history. We just have to convert it to a change list // NOTE: This part is a bit messy return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, @@ -750,8 +808,8 @@ export class LcsDiff { // Shift all the changes down first for (let i = 0; i < changes.length; i++) { const change = changes[i]; - const originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this.OriginalSequence.getLength(); - const modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this.ModifiedSequence.getLength(); + const originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this._originalElementsOrHash.length; + const modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this._modifiedElementsOrHash.length; const checkOriginal = change.originalLength > 0; const checkModified = change.modifiedLength > 0; @@ -795,8 +853,8 @@ export class LcsDiff { let bestScore = this._boundaryScore(change.originalStart, change.originalLength, change.modifiedStart, change.modifiedLength); for (let delta = 1; ; delta++) { - let originalStart = change.originalStart - delta; - let modifiedStart = change.modifiedStart - delta; + const originalStart = change.originalStart - delta; + const modifiedStart = change.modifiedStart - delta; if (originalStart < originalStop || modifiedStart < modifiedStop) { break; @@ -810,7 +868,7 @@ export class LcsDiff { break; } - let score = this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength); + const score = this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength); if (score > bestScore) { bestScore = score; @@ -826,11 +884,10 @@ export class LcsDiff { } private _OriginalIsBoundary(index: number): boolean { - if (index <= 0 || index >= this.OriginalSequence.getLength() - 1) { + if (index <= 0 || index >= this._originalElementsOrHash.length - 1) { return true; } - const element = this.OriginalSequence.getElementAtIndex(index); - return (typeof element === 'string' && /^\s*$/.test(element)); + return (this._hasStrings && /^\s*$/.test(this._originalStringElements[index])); } private _OriginalRegionIsBoundary(originalStart: number, originalLength: number): boolean { @@ -838,7 +895,7 @@ export class LcsDiff { return true; } if (originalLength > 0) { - let originalEnd = originalStart + originalLength; + const originalEnd = originalStart + originalLength; if (this._OriginalIsBoundary(originalEnd - 1) || this._OriginalIsBoundary(originalEnd)) { return true; } @@ -847,11 +904,10 @@ export class LcsDiff { } private _ModifiedIsBoundary(index: number): boolean { - if (index <= 0 || index >= this.ModifiedSequence.getLength() - 1) { + if (index <= 0 || index >= this._modifiedElementsOrHash.length - 1) { return true; } - const element = this.ModifiedSequence.getElementAtIndex(index); - return (typeof element === 'string' && /^\s*$/.test(element)); + return (this._hasStrings && /^\s*$/.test(this._modifiedStringElements[index])); } private _ModifiedRegionIsBoundary(modifiedStart: number, modifiedLength: number): boolean { @@ -859,7 +915,7 @@ export class LcsDiff { return true; } if (modifiedLength > 0) { - let modifiedEnd = modifiedStart + modifiedLength; + const modifiedEnd = modifiedStart + modifiedLength; if (this._ModifiedIsBoundary(modifiedEnd - 1) || this._ModifiedIsBoundary(modifiedEnd)) { return true; } @@ -868,8 +924,8 @@ export class LcsDiff { } private _boundaryScore(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number): number { - let originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0); - let modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0); + const originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0); + const modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0); return (originalScore + modifiedScore); } @@ -890,14 +946,14 @@ export class LcsDiff { // might recurse in the middle of a change thereby splitting it into // two changes. Here in the combining stage, we detect and fuse those // changes back together - let result = new Array(left.length + right.length - 1); + const result = new Array(left.length + right.length - 1); MyArray.Copy(left, 0, result, 0, left.length - 1); result[left.length - 1] = mergedChangeArr[0]; MyArray.Copy(right, 1, result, left.length, right.length - 1); return result; } else { - let result = new Array(left.length + right.length); + const result = new Array(left.length + right.length); MyArray.Copy(left, 0, result, 0, left.length); MyArray.Copy(right, 0, result, left.length, right.length); @@ -918,9 +974,9 @@ export class LcsDiff { Debug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change'); if (left.originalStart + left.originalLength >= right.originalStart || left.modifiedStart + left.modifiedLength >= right.modifiedStart) { - let originalStart = left.originalStart; + const originalStart = left.originalStart; let originalLength = left.originalLength; - let modifiedStart = left.modifiedStart; + const modifiedStart = left.modifiedStart; let modifiedLength = left.modifiedLength; if (left.originalStart + left.originalLength >= right.originalStart) { @@ -958,15 +1014,15 @@ export class LcsDiff { // diagonalsBelow: The number of diagonals below the reference diagonal // diagonalsAbove: The number of diagonals above the reference diagonal - let diagonalsBelow = diagonalBaseIndex; - let diagonalsAbove = numDiagonals - diagonalBaseIndex - 1; - let diffEven = (numDifferences % 2 === 0); + const diagonalsBelow = diagonalBaseIndex; + const diagonalsAbove = numDiagonals - diagonalBaseIndex - 1; + const diffEven = (numDifferences % 2 === 0); if (diagonal < 0) { - let lowerBoundEven = (diagonalsBelow % 2 === 0); + const lowerBoundEven = (diagonalsBelow % 2 === 0); return (diffEven === lowerBoundEven) ? 0 : 1; } else { - let upperBoundEven = (diagonalsAbove % 2 === 0); + const upperBoundEven = (diagonalsAbove % 2 === 0); return (diffEven === upperBoundEven) ? numDiagonals - 1 : numDiagonals - 2; } } diff --git a/src/vs/base/common/errors.ts b/src/vs/base/common/errors.ts index b8077dd5376..0beea24d6f3 100644 --- a/src/vs/base/common/errors.ts +++ b/src/vs/base/common/errors.ts @@ -195,7 +195,6 @@ export function getErrorMessage(err: any): string { return String(err); } - export class NotImplementedError extends Error { constructor(message?: string) { super('NotImplemented'); diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index d09206cd9d9..b85073b6786 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -271,6 +271,8 @@ export namespace Event { filter(fn: (e: T) => boolean): IChainableEvent; reduce(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent; latch(): IChainableEvent; + debounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent; + debounce(merge: (last: R | undefined, event: T) => R, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent; on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable; once(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable; } @@ -299,6 +301,12 @@ export namespace Event { return new ChainableEvent(latch(this.event)); } + debounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent; + debounce(merge: (last: R | undefined, event: T) => R, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent; + debounce(merge: (last: R | undefined, event: T) => R, delay: number = 100, leading = false, leakWarningThreshold?: number): IChainableEvent { + return new ChainableEvent(debounce(this.event, merge, delay, leading, leakWarningThreshold)); + } + on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[] | DisposableStore) { return this.event(listener, thisArgs, disposables); } @@ -680,7 +688,7 @@ export class AsyncEmitter extends Emitter { // freeze thenables-collection to enforce sync-calls to // wait until and then wait for all thenables to resolve Object.freeze(thenables); - await Promise.all(thenables); + await Promise.all(thenables).catch(e => onUnexpectedError(e)); } } } diff --git a/src/vs/base/common/extpath.ts b/src/vs/base/common/extpath.ts index 8f47ac2cc5e..907dc51ff93 100644 --- a/src/vs/base/common/extpath.ts +++ b/src/vs/base/common/extpath.ts @@ -8,7 +8,7 @@ import { startsWithIgnoreCase, equalsIgnoreCase, endsWith, rtrim } from 'vs/base import { CharCode } from 'vs/base/common/charCode'; import { sep, posix, isAbsolute, join, normalize } from 'vs/base/common/path'; -function isPathSeparator(code: number) { +export function isPathSeparator(code: number) { return code === CharCode.Slash || code === CharCode.Backslash; } @@ -282,4 +282,4 @@ export function isRootOrDriveLetter(path: string): boolean { } return pathNormalized === posix.sep; -} \ No newline at end of file +} diff --git a/src/vs/base/common/hash.ts b/src/vs/base/common/hash.ts index 0a5106d3bd6..1902e82c312 100644 --- a/src/vs/base/common/hash.ts +++ b/src/vs/base/common/hash.ts @@ -36,7 +36,7 @@ function booleanHash(b: boolean, initialHashVal: number): number { return numberHash(b ? 433 : 863, initialHashVal); } -function stringHash(s: string, hashVal: number) { +export function stringHash(s: string, hashVal: number) { hashVal = numberHash(149417, hashVal); for (let i = 0, length = s.length; i < length; i++) { hashVal = numberHash(s.charCodeAt(i), hashVal); diff --git a/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts index ac7c8ed3a91..c9bfed7ea8f 100644 --- a/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -7,37 +7,44 @@ import { equals } from 'vs/base/common/arrays'; import { UriComponents } from 'vs/base/common/uri'; export interface IMarkdownString { - value: string; - isTrusted?: boolean; + readonly value: string; + readonly isTrusted?: boolean; uris?: { [href: string]: UriComponents }; } export class MarkdownString implements IMarkdownString { - value: string; - isTrusted?: boolean; + private _value: string; + private _isTrusted: boolean; - constructor(value: string = '') { - this.value = value; + constructor(value: string = '', isTrusted = false) { + this._value = value; + this._isTrusted = isTrusted; } + get value() { return this._value; } + get isTrusted() { return this._isTrusted; } + appendText(value: string): MarkdownString { // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash - this.value += value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&'); + this._value += value + .replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&') + .replace('\n', '\n\n'); + return this; } appendMarkdown(value: string): MarkdownString { - this.value += value; + this._value += value; return this; } appendCodeblock(langId: string, code: string): MarkdownString { - this.value += '\n```'; - this.value += langId; - this.value += '\n'; - this.value += code; - this.value += '\n```\n'; + this._value += '\n```'; + this._value += langId; + this._value += '\n'; + this._value += code; + this._value += '\n```\n'; return this; } } diff --git a/src/vs/base/common/insane/insane.d.ts b/src/vs/base/common/insane/insane.d.ts index def347529e9..9b5a77c3b8e 100644 --- a/src/vs/base/common/insane/insane.d.ts +++ b/src/vs/base/common/insane/insane.d.ts @@ -3,11 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export as namespace insane; - -export = insane; - -declare function insane( +export function insane( html: string, options?: { readonly allowedSchemes?: readonly string[], @@ -16,5 +12,3 @@ declare function insane( }, strict?: boolean, ): string; - -declare namespace insane { } diff --git a/src/vs/base/common/insane/insane.js b/src/vs/base/common/insane/insane.js index 3cfdf5886bb..cedeb883165 100644 --- a/src/vs/base/common/insane/insane.js +++ b/src/vs/base/common/insane/insane.js @@ -21,11 +21,7 @@ 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. */ -// ESM-comment-begin -let __insane_exports; -// ESM-comment-end - - +let __insane_func; (function () { function r(e, n, t) { function o(i, f) { if (!n[i]) { if (!e[i]) { var c = "function" == typeof require && require; if (!f && c) return c(i, !0); if (u) return u(i, !0); var a = new Error("Cannot find module '" + i + "'"); throw a.code = "MODULE_NOT_FOUND", a } var p = n[i] = { exports: {} }; e[i][0].call(p.exports, function (r) { var n = e[i][1][r]; return o(n || r) }, p, p.exports, r, e, n, t) } return n[i].exports } for (var u = "function" == typeof require && require, i = 0; i < t.length; i++)o(t[i]); return o } return r })()({ 1: [function (require, module, exports) { @@ -92,7 +88,7 @@ let __insane_exports; insane.defaults = defaults; module.exports = insane; - __insane_exports = insane; + __insane_func = insane; }, { "./defaults": 2, "./parser": 7, "./sanitizer": 8, "assignment": 6, "he": 9 }], 5: [function (require, module, exports) { 'use strict'; @@ -469,10 +465,10 @@ let __insane_exports; }, {}] }, {}, [4]); -// BEGIN MONACOCHANGE -// __marked_exports = marked; -// }).call(this); - // ESM-comment-begin -define(function() { return __insane_exports; }); +define(function() { return { insane: __insane_func }; }); // ESM-comment-end + +// ESM-uncomment-begin +// export var insane = __insane_func; +// ESM-uncomment-end diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index da56ba7e095..f44cbd236b8 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -60,7 +60,7 @@ export module Iterator { }; } - export function fromArray(array: T[], index = 0, length = array.length): Iterator { + export function fromArray(array: ReadonlyArray, index = 0, length = array.length): Iterator { return { next(): IteratorResult { if (index >= length) { diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index 12a9c0a9761..df362c06589 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -137,6 +137,7 @@ export interface Location { export interface ParseOptions { disallowComments?: boolean; allowTrailingComma?: boolean; + allowEmptyContent?: boolean; } export namespace ParseOptions { @@ -785,7 +786,7 @@ export function getLocation(text: string, position: number): Location { if (position < offset) { throw earlyReturnException; } - setPreviousNode(value, offset, length, getLiteralNodeType(value)); + setPreviousNode(value, offset, length, getNodeType(value)); if (position <= offset + length) { throw earlyReturnException; @@ -848,7 +849,7 @@ export function parse(text: string, errors: ParseError[] = [], options: ParseOpt function onValue(value: any) { if (Array.isArray(currentParent)) { (currentParent).push(value); - } else if (currentProperty) { + } else if (currentProperty !== null) { currentParent[currentProperty] = value; } } @@ -927,7 +928,7 @@ export function parseTree(text: string, errors: ParseError[] = [], options: Pars ensurePropertyComplete(offset + length); }, onLiteralValue: (value: any, offset: number, length: number) => { - onValue({ type: getLiteralNodeType(value), offset, length, parent: currentParent, value }); + onValue({ type: getNodeType(value), offset, length, parent: currentParent, value }); ensurePropertyComplete(offset + length); }, onSeparator: (sep: string, offset: number, length: number) => { @@ -1287,7 +1288,11 @@ export function visit(text: string, visitor: JSONVisitor, options: ParseOptions scanNext(); if (_scanner.getToken() === SyntaxKind.EOF) { - return true; + if (options.allowEmptyContent) { + return true; + } + handleError(ParseErrorCode.ValueExpected, [], []); + return false; } if (!parseValue()) { handleError(ParseErrorCode.ValueExpected, [], []); @@ -1333,11 +1338,19 @@ export function stripComments(text: string, replaceCh?: string): string { return parts.join(''); } -function getLiteralNodeType(value: any): NodeType { +export function getNodeType(value: any): NodeType { switch (typeof value) { case 'boolean': return 'boolean'; case 'number': return 'number'; case 'string': return 'string'; + case 'object': { + if (!value) { + return 'null'; + } else if (Array.isArray(value)) { + return 'array'; + } + return 'object'; + } default: return 'null'; } } diff --git a/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts index e866c720bc1..86a05d80658 100644 --- a/src/vs/base/common/labels.ts +++ b/src/vs/base/common/labels.ts @@ -4,12 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { sep, posix, normalize } from 'vs/base/common/path'; +import { sep, posix, normalize, win32 } from 'vs/base/common/path'; import { endsWith, startsWithIgnoreCase, rtrim, startsWith } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform'; import { isEqual, basename, relativePath } from 'vs/base/common/resources'; -import { CharCode } from 'vs/base/common/charCode'; export interface IWorkspaceFolderProvider { getWorkspaceFolder(resource: URI): { uri: URI, name?: string } | null; @@ -44,7 +43,7 @@ export function getPathLabel(resource: URI | string, userHomeProvider?: IUserHom } if (hasMultipleRoots) { - const rootName = (baseResource && baseResource.name) ? baseResource.name : basename(baseResource.uri); + const rootName = baseResource.name ? baseResource.name : basename(baseResource.uri); pathLabel = pathLabel ? (rootName + ' • ' + pathLabel) : rootName; // always show root basename if there are multiple } @@ -388,11 +387,12 @@ export function unmnemonicLabel(label: string): string { * Splits a path in name and parent path, supporting both '/' and '\' */ export function splitName(fullPath: string): { name: string, parentPath: string } { - for (let i = fullPath.length - 1; i >= 1; i--) { - const code = fullPath.charCodeAt(i); - if (code === CharCode.Slash || code === CharCode.Backslash) { - return { parentPath: fullPath.substr(0, i), name: fullPath.substr(i + 1) }; - } + const p = fullPath.indexOf('/') !== -1 ? posix : win32; + const name = p.basename(fullPath); + const parentPath = p.dirname(fullPath); + if (name.length) { + return { name, parentPath }; } - return { parentPath: '', name: fullPath }; + // only the root segment + return { name: parentPath, parentPath: '' }; } diff --git a/src/vs/base/common/lazy.ts b/src/vs/base/common/lazy.ts new file mode 100644 index 00000000000..fe88e82bc80 --- /dev/null +++ b/src/vs/base/common/lazy.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * A value that is resolved synchronously when it is first needed. + */ +export interface Lazy { + + hasValue(): boolean; + + + getValue(): T; + + + map(f: (x: T) => R): Lazy; +} + +export class Lazy { + + private _didRun: boolean = false; + private _value?: T; + private _error: any; + + constructor( + private readonly executor: () => T, + ) { } + + /** + * True if the lazy value has been resolved. + */ + hasValue() { return this._didRun; } + + /** + * Get the wrapped value. + * + * This will force evaluation of the lazy value if it has not been resolved yet. Lazy values are only + * resolved once. `getValue` will re-throw exceptions that are hit while resolving the value + */ + getValue(): T { + if (!this._didRun) { + try { + this._value = this.executor(); + } catch (err) { + this._error = err; + } finally { + this._didRun = true; + } + } + if (this._error) { + throw this._error; + } + return this._value!; + } + + /** + * Create a new lazy value that is the result of applying `f` to the wrapped value. + * + * This does not force the evaluation of the current lazy value. + */ + map(f: (x: T) => R): Lazy { + return new Lazy(() => f(this.getValue())); + } +} diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index 44cfdada8ab..8d1cbd5b996 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -138,7 +138,7 @@ export class DisposableStore implements IDisposable { export abstract class Disposable implements IDisposable { - static None = Object.freeze({ dispose() { } }); + static readonly None = Object.freeze({ dispose() { } }); private readonly _store = new DisposableStore(); diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 007d0a0d529..dadb16862bb 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -117,6 +117,8 @@ export class PathIterator implements IKeyIterator { private _from!: number; private _to!: number; + constructor(private _splitOnBackslash: boolean = true) { } + reset(key: string): this { this._value = key.replace(/\\$|\/$/, ''); this._from = 0; @@ -134,7 +136,7 @@ export class PathIterator implements IKeyIterator { let justSeps = true; for (; this._to < this._value.length; this._to++) { const ch = this._value.charCodeAt(this._to); - if (ch === CharCode.Slash || ch === CharCode.Backslash) { + if (ch === CharCode.Slash || this._splitOnBackslash && ch === CharCode.Backslash) { if (justSeps) { this._from++; } else { diff --git a/src/vs/base/common/mime.ts b/src/vs/base/common/mime.ts index d9451a64def..0a3a692a307 100644 --- a/src/vs/base/common/mime.ts +++ b/src/vs/base/common/mime.ts @@ -262,7 +262,14 @@ export function suggestFilename(mode: string | undefined, prefix: string): strin .filter(assoc => startsWith(assoc, '.')); if (extensionsWithDotFirst.length > 0) { - return prefix + extensionsWithDotFirst[0]; + const candidateExtension = extensionsWithDotFirst[0]; + if (endsWith(prefix, candidateExtension)) { + // do not add the prefix if it already exists + // https://github.com/microsoft/vscode/issues/83603 + return prefix; + } + + return prefix + candidateExtension; } return extensions[0] || prefix; diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 7d525614421..231180d513f 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -56,50 +56,49 @@ export namespace Schemas { } class RemoteAuthoritiesImpl { - private readonly _hosts: { [authority: string]: string; }; - private readonly _ports: { [authority: string]: number; }; - private readonly _connectionTokens: { [authority: string]: string; }; - private _preferredWebSchema: 'http' | 'https'; - private _delegate: ((uri: URI) => URI) | null; + private readonly _hosts: { [authority: string]: string | undefined; } = Object.create(null); + private readonly _ports: { [authority: string]: number | undefined; } = Object.create(null); + private readonly _connectionTokens: { [authority: string]: string | undefined; } = Object.create(null); + private _preferredWebSchema: 'http' | 'https' = 'http'; + private _delegate: ((uri: URI) => URI) | null = null; - constructor() { - this._hosts = Object.create(null); - this._ports = Object.create(null); - this._connectionTokens = Object.create(null); - this._preferredWebSchema = 'http'; - this._delegate = null; - } - - public setPreferredWebSchema(schema: 'http' | 'https') { + setPreferredWebSchema(schema: 'http' | 'https') { this._preferredWebSchema = schema; } - public setDelegate(delegate: (uri: URI) => URI): void { + setDelegate(delegate: (uri: URI) => URI): void { this._delegate = delegate; } - public set(authority: string, host: string, port: number): void { + set(authority: string, host: string, port: number): void { this._hosts[authority] = host; this._ports[authority] = port; } - public setConnectionToken(authority: string, connectionToken: string): void { + setConnectionToken(authority: string, connectionToken: string): void { this._connectionTokens[authority] = connectionToken; } - public rewrite(uri: URI): URI { + rewrite(uri: URI): URI { if (this._delegate) { return this._delegate(uri); } const authority = uri.authority; - const host = this._hosts[authority]; + let host = this._hosts[authority]; + if (host && host.indexOf(':') !== -1) { + host = `[${host}]`; + } const port = this._ports[authority]; const connectionToken = this._connectionTokens[authority]; + let query = `path=${encodeURIComponent(uri.path)}`; + if (typeof connectionToken === 'string') { + query += `&tkn=${encodeURIComponent(connectionToken)}`; + } return URI.from({ scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource, authority: `${host}:${port}`, path: `/vscode-remote-resource`, - query: `path=${encodeURIComponent(uri.path)}&tkn=${encodeURIComponent(connectionToken)}` + query }); } } diff --git a/src/vs/base/common/octicon.ts b/src/vs/base/common/octicon.ts deleted file mode 100644 index 48da86f6cc1..00000000000 --- a/src/vs/base/common/octicon.ts +++ /dev/null @@ -1,126 +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 { matchesFuzzy, IMatch } from 'vs/base/common/filters'; -import { ltrim } from 'vs/base/common/strings'; - -const octiconStartMarker = '$('; - -export interface IParsedOcticons { - text: string; - octiconOffsets?: number[]; -} - -export function parseOcticons(text: string): IParsedOcticons { - const firstOcticonIndex = text.indexOf(octiconStartMarker); - if (firstOcticonIndex === -1) { - return { text }; // return early if the word does not include an octicon - } - - return doParseOcticons(text, firstOcticonIndex); -} - -function doParseOcticons(text: string, firstOcticonIndex: number): IParsedOcticons { - const octiconOffsets: number[] = []; - let textWithoutOcticons: string = ''; - - function appendChars(chars: string) { - if (chars) { - textWithoutOcticons += chars; - - for (const _ of chars) { - octiconOffsets.push(octiconsOffset); // make sure to fill in octicon offsets - } - } - } - - let currentOcticonStart = -1; - let currentOcticonValue: string = ''; - let octiconsOffset = 0; - - let char: string; - let nextChar: string; - - let offset = firstOcticonIndex; - const length = text.length; - - // Append all characters until the first octicon - appendChars(text.substr(0, firstOcticonIndex)); - - // example: $(file-symlink-file) my cool $(other-octicon) entry - while (offset < length) { - char = text[offset]; - nextChar = text[offset + 1]; - - // beginning of octicon: some value $( <-- - if (char === octiconStartMarker[0] && nextChar === octiconStartMarker[1]) { - currentOcticonStart = offset; - - // if we had a previous potential octicon value without - // the closing ')', it was actually not an octicon and - // so we have to add it to the actual value - appendChars(currentOcticonValue); - - currentOcticonValue = octiconStartMarker; - - offset++; // jump over '(' - } - - // end of octicon: some value $(some-octicon) <-- - else if (char === ')' && currentOcticonStart !== -1) { - const currentOcticonLength = offset - currentOcticonStart + 1; // +1 to include the closing ')' - octiconsOffset += currentOcticonLength; - currentOcticonStart = -1; - currentOcticonValue = ''; - } - - // within octicon - else if (currentOcticonStart !== -1) { - currentOcticonValue += char; - } - - // any value outside of octicons - else { - appendChars(char); - } - - offset++; - } - - // if we had a previous potential octicon value without - // the closing ')', it was actually not an octicon and - // so we have to add it to the actual value - appendChars(currentOcticonValue); - - return { text: textWithoutOcticons, octiconOffsets }; -} - -export function matchesFuzzyOcticonAware(query: string, target: IParsedOcticons, enableSeparateSubstringMatching = false): IMatch[] | null { - const { text, octiconOffsets } = target; - - // Return early if there are no octicon markers in the word to match against - if (!octiconOffsets || octiconOffsets.length === 0) { - return matchesFuzzy(query, text, enableSeparateSubstringMatching); - } - - // Trim the word to match against because it could have leading - // whitespace now if the word started with an octicon - const wordToMatchAgainstWithoutOcticonsTrimmed = ltrim(text, ' '); - const leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutOcticonsTrimmed.length; - - // match on value without octicons - const matches = matchesFuzzy(query, wordToMatchAgainstWithoutOcticonsTrimmed, enableSeparateSubstringMatching); - - // Map matches back to offsets with octicons and trimming - if (matches) { - for (const match of matches) { - const octiconOffset = octiconOffsets[match.start + leadingWhitespaceOffset] /* octicon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */; - match.start += octiconOffset; - match.end += octiconOffset; - } - } - - return matches; -} \ No newline at end of file diff --git a/src/vs/base/common/path.ts b/src/vs/base/common/path.ts index 5ab3ac2621c..28b7d5e61cc 100644 --- a/src/vs/base/common/path.ts +++ b/src/vs/base/common/path.ts @@ -169,7 +169,7 @@ function _format(sep: string, pathObject: ParsedPath) { return dir + sep + base; } -interface ParsedPath { +export interface ParsedPath { root: string; dir: string; base: string; @@ -177,7 +177,7 @@ interface ParsedPath { name: string; } -interface IPath { +export interface IPath { normalize(path: string): string; isAbsolute(path: string): boolean; join(...paths: string[]): string; diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index a657f4a4d9c..b3c7001a51d 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -164,6 +164,34 @@ export const setImmediate: ISetImmediate = (function defineSetImmediate() { if (globals.setImmediate) { return globals.setImmediate.bind(globals); } + if (typeof globals.postMessage === 'function' && !globals.importScripts) { + interface IQueueElement { + id: number; + callback: () => void; + } + let pending: IQueueElement[] = []; + globals.addEventListener('message', (e: MessageEvent) => { + if (e.data && e.data.vscodeSetImmediateId) { + for (let i = 0, len = pending.length; i < len; i++) { + const candidate = pending[i]; + if (candidate.id === e.data.vscodeSetImmediateId) { + pending.splice(i, 1); + candidate.callback(); + return; + } + } + } + }); + let lastId = 0; + return (callback: () => void) => { + const myId = ++lastId; + pending.push({ + id: myId, + callback: callback + }); + globals.postMessage({ vscodeSetImmediateId: myId }, '*'); + }; + } if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { return process.nextTick.bind(process); } diff --git a/src/vs/base/common/resourceTree.ts b/src/vs/base/common/resourceTree.ts index 98c0f518d73..4adca4ca4f2 100644 --- a/src/vs/base/common/resourceTree.ts +++ b/src/vs/base/common/resourceTree.ts @@ -9,93 +9,77 @@ import { Iterator } from 'vs/base/common/iterator'; import { relativePath, joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { mapValues } from 'vs/base/common/collections'; +import { PathIterator } from 'vs/base/common/map'; -export interface ILeafNode { +export interface IResourceNode { readonly uri: URI; readonly relativePath: string; readonly name: string; - readonly element: T; + readonly element: T | undefined; + readonly children: Iterator>; + readonly childrenCount: number; + readonly parent: IResourceNode | undefined; readonly context: C; + get(childName: string): IResourceNode | undefined; } -export interface IBranchNode { - readonly uri: URI; - readonly relativePath: string; - readonly name: string; - readonly size: number; - readonly children: Iterator>; - readonly parent: IBranchNode | undefined; - readonly context: C; - get(childName: string): INode | undefined; -} +class Node implements IResourceNode { -export type INode = IBranchNode | ILeafNode; + private _children = new Map>(); -// Internals - -class Node { - - @memoize - get name(): string { return paths.posix.basename(this.relativePath); } - - constructor(readonly uri: URI, readonly relativePath: string, readonly context: C) { } -} - -class BranchNode extends Node implements IBranchNode { - - private _children = new Map | LeafNode>(); - - get size(): number { + get childrenCount(): number { return this._children.size; } - get children(): Iterator | LeafNode> { + get children(): Iterator> { return Iterator.fromArray(mapValues(this._children)); } - constructor(uri: URI, relativePath: string, context: C, readonly parent: IBranchNode | undefined = undefined) { - super(uri, relativePath, context); + @memoize + get name(): string { + return paths.posix.basename(this.relativePath); } - get(path: string): BranchNode | LeafNode | undefined { + constructor( + readonly uri: URI, + readonly relativePath: string, + readonly context: C, + public element: T | undefined = undefined, + readonly parent: IResourceNode | undefined = undefined + ) { } + + get(path: string): Node | undefined { return this._children.get(path); } - set(path: string, child: BranchNode | LeafNode): void { + set(path: string, child: Node): void { this._children.set(path, child); } delete(path: string): void { this._children.delete(path); } -} -class LeafNode extends Node implements ILeafNode { - - constructor(uri: URI, path: string, context: C, readonly element: T) { - super(uri, path, context); + clear(): void { + this._children.clear(); } } -function collect(node: INode, result: T[]): T[] { - if (ResourceTree.isBranchNode(node)) { - Iterator.forEach(node.children, child => collect(child, result)); - } else { +function collect(node: IResourceNode, result: T[]): T[] { + if (typeof node.element !== 'undefined') { result.push(node.element); } + Iterator.forEach(node.children, child => collect(child, result)); + return result; } export class ResourceTree, C> { - readonly root: BranchNode; + readonly root: Node; - static isBranchNode(obj: any): obj is IBranchNode { - return obj instanceof BranchNode; - } - - static getRoot(node: IBranchNode): IBranchNode { + static getRoot(node: IResourceNode): IResourceNode { while (node.parent) { node = node.parent; } @@ -103,89 +87,101 @@ export class ResourceTree, C> { return node; } - static collect(node: INode): T[] { + static collect(node: IResourceNode): T[] { return collect(node, []); } + static isResourceNode(obj: any): obj is IResourceNode { + return obj instanceof Node; + } + constructor(context: C, rootURI: URI = URI.file('/')) { - this.root = new BranchNode(rootURI, '', context); + this.root = new Node(rootURI, '', context); } add(uri: URI, element: T): void { const key = relativePath(this.root.uri, uri) || uri.fsPath; - const parts = key.split(/[\\\/]/).filter(p => !!p); + const iterator = new PathIterator(false).reset(key); let node = this.root; let path = ''; - for (let i = 0; i < parts.length; i++) { - const name = parts[i]; + while (true) { + const name = iterator.value(); path = path + '/' + name; let child = node.get(name); if (!child) { - if (i < parts.length - 1) { - child = new BranchNode(joinPath(this.root.uri, path), path, this.root.context, node); - node.set(name, child); - } else { - child = new LeafNode(uri, path, this.root.context, element); - node.set(name, child); - return; - } - } + child = new Node( + joinPath(this.root.uri, path), + path, + this.root.context, + iterator.hasNext() ? undefined : element, + node + ); - if (!(child instanceof BranchNode)) { - if (i < parts.length - 1) { - throw new Error('Inconsistent tree: can\'t override leaf with branch.'); - } - - // replace - node.set(name, new LeafNode(uri, path, this.root.context, element)); - return; - } else if (i === parts.length - 1) { - throw new Error('Inconsistent tree: can\'t override branch with leaf.'); + node.set(name, child); + } else if (!iterator.hasNext()) { + child.element = element; } node = child; + + if (!iterator.hasNext()) { + return; + } + + iterator.next(); } } delete(uri: URI): T | undefined { const key = relativePath(this.root.uri, uri) || uri.fsPath; - const parts = key.split(/[\\\/]/).filter(p => !!p); - return this._delete(this.root, parts, 0); + const iterator = new PathIterator(false).reset(key); + return this._delete(this.root, iterator); } - private _delete(node: BranchNode, parts: string[], index: number): T | undefined { - const name = parts[index]; + private _delete(node: Node, iterator: PathIterator): T | undefined { + const name = iterator.value(); const child = node.get(name); if (!child) { return undefined; } - // not at end - if (index < parts.length - 1) { - if (child instanceof BranchNode) { - const result = this._delete(child, parts, index + 1); + if (iterator.hasNext()) { + const result = this._delete(child, iterator.next()); - if (typeof result !== 'undefined' && child.size === 0) { - node.delete(name); - } - - return result; - } else { - throw new Error('Inconsistent tree: Expected a branch, found a leaf instead.'); + if (typeof result !== 'undefined' && child.childrenCount === 0) { + node.delete(name); } - } - //at end - if (child instanceof BranchNode) { - // TODO: maybe we can allow this - throw new Error('Inconsistent tree: Expected a leaf, found a branch instead.'); + return result; } node.delete(name); return child.element; } + + clear(): void { + this.root.clear(); + } + + getNode(uri: URI): IResourceNode | undefined { + const key = relativePath(this.root.uri, uri) || uri.fsPath; + const iterator = new PathIterator(false).reset(key); + let node = this.root; + + while (true) { + const name = iterator.value(); + const child = node.get(name); + + if (!child || !iterator.hasNext()) { + return child; + } + + node = child; + iterator.next(); + } + } } diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 8ccc9567737..bea40bbdc62 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -246,7 +246,8 @@ export function relativePath(from: URI, to: URI, ignoreCase = hasToIgnoreCase(fr } /** - * Resolves a absolute or relative path against a base URI. + * Resolves an absolute or relative path against a base URI. + * The path can be relative or absolute posix or a Windows path */ export function resolvePath(base: URI, path: string): URI { if (base.scheme === Schemas.file) { @@ -256,6 +257,12 @@ export function resolvePath(base: URI, path: string): URI { path: newURI.path }); } + if (path.indexOf('/') === -1) { // no slashes? it's likely a Windows path + path = extpath.toSlashes(path); + if (/^[a-zA-Z]:(\/|$)/.test(path)) { // starts with a drive letter + path = '/' + path; + } + } return base.with({ path: paths.posix.resolve(base.path, path) }); @@ -353,4 +360,4 @@ export function toLocalResource(resource: URI, authority: string | undefined): U } return resource.with({ scheme: Schemas.file }); -} \ No newline at end of file +} diff --git a/src/vs/base/common/search.ts b/src/vs/base/common/search.ts index d92882578b7..7b57f1e5a66 100644 --- a/src/vs/base/common/search.ts +++ b/src/vs/base/common/search.ts @@ -7,20 +7,19 @@ import * as strings from './strings'; export function buildReplaceStringWithCasePreserved(matches: string[] | null, pattern: string): string { if (matches && (matches[0] !== '')) { + const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-'); + const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_'); + if (containsHyphens && !containsUnderscores) { + return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-'); + } else if (!containsHyphens && containsUnderscores) { + return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_'); + } if (matches[0].toUpperCase() === matches[0]) { return pattern.toUpperCase(); } else if (matches[0].toLowerCase() === matches[0]) { return pattern.toLowerCase(); } else if (strings.containsUppercaseCharacter(matches[0][0])) { - const containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-'); - const containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_'); - if (containsHyphens && !containsUnderscores) { - return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-'); - } else if (!containsHyphens && containsUnderscores) { - return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_'); - } else { - return pattern[0].toUpperCase() + pattern.substr(1); - } + return pattern[0].toUpperCase() + pattern.substr(1); } else { // we don't understand its pattern yet. return pattern; diff --git a/src/vs/base/common/stream.ts b/src/vs/base/common/stream.ts new file mode 100644 index 00000000000..1172496a897 --- /dev/null +++ b/src/vs/base/common/stream.ts @@ -0,0 +1,487 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * The payload that flows in readable stream events. + */ +export type ReadableStreamEventPayload = T | Error | 'end'; + +export interface ReadableStreamEvents { + + /** + * The 'data' event is emitted whenever the stream is + * relinquishing ownership of a chunk of data to a consumer. + */ + on(event: 'data', callback: (data: T) => void): void; + + /** + * Emitted when any error occurs. + */ + on(event: 'error', callback: (err: Error) => void): void; + + /** + * The 'end' event is emitted when there is no more data + * to be consumed from the stream. The 'end' event will + * not be emitted unless the data is completely consumed. + */ + on(event: 'end', callback: () => void): void; +} + +/** + * A interface that emulates the API shape of a node.js readable + * stream for use in desktop and web environments. + */ +export interface ReadableStream extends ReadableStreamEvents { + + /** + * Stops emitting any events until resume() is called. + */ + pause(): void; + + /** + * Starts emitting events again after pause() was called. + */ + resume(): void; + + /** + * Destroys the stream and stops emitting any event. + */ + destroy(): void; +} + +/** + * A interface that emulates the API shape of a node.js readable + * for use in desktop and web environments. + */ +export interface Readable { + + /** + * Read data from the underlying source. Will return + * null to indicate that no more data can be read. + */ + read(): T | null; +} + +/** + * A interface that emulates the API shape of a node.js writeable + * stream for use in desktop and web environments. + */ +export interface WriteableStream extends ReadableStream { + + /** + * Writing data to the stream will trigger the on('data') + * event listener if the stream is flowing and buffer the + * data otherwise until the stream is flowing. + */ + write(data: T): void; + + /** + * Signals an error to the consumer of the stream via the + * on('error') handler if the stream is flowing. + */ + error(error: Error): void; + + /** + * Signals the end of the stream to the consumer. If the + * result is not an error, will trigger the on('data') event + * listener if the stream is flowing and buffer the data + * otherwise until the stream is flowing. + * + * In case of an error, the on('error') event will be used + * if the stream is flowing. + */ + end(result?: T | Error): void; +} + +export function isReadableStream(obj: any): obj is ReadableStream { + const candidate: ReadableStream = obj; + + return candidate && [candidate.on, candidate.pause, candidate.resume, candidate.destroy].every(fn => typeof fn === 'function'); +} + +export interface IReducer { + (data: T[]): T; +} + +export interface IDataTransformer { + (data: Original): Transformed; +} + +export interface IErrorTransformer { + (error: Error): Error; +} + +export interface ITransformer { + data: IDataTransformer; + error?: IErrorTransformer; +} + +export function newWriteableStream(reducer: IReducer): WriteableStream { + return new WriteableStreamImpl(reducer); +} + +class WriteableStreamImpl implements WriteableStream { + + private readonly state = { + flowing: false, + ended: false, + destroyed: false + }; + + private readonly buffer = { + data: [] as T[], + error: [] as Error[] + }; + + private readonly listeners = { + data: [] as { (data: T): void }[], + error: [] as { (error: Error): void }[], + end: [] as { (): void }[] + }; + + constructor(private reducer: IReducer) { } + + pause(): void { + if (this.state.destroyed) { + return; + } + + this.state.flowing = false; + } + + resume(): void { + if (this.state.destroyed) { + return; + } + + if (!this.state.flowing) { + this.state.flowing = true; + + // emit buffered events + this.flowData(); + this.flowErrors(); + this.flowEnd(); + } + } + + write(data: T): void { + if (this.state.destroyed) { + return; + } + + // flowing: directly send the data to listeners + if (this.state.flowing) { + this.listeners.data.forEach(listener => listener(data)); + } + + // not yet flowing: buffer data until flowing + else { + this.buffer.data.push(data); + } + } + + error(error: Error): void { + if (this.state.destroyed) { + return; + } + + // flowing: directly send the error to listeners + if (this.state.flowing) { + this.listeners.error.forEach(listener => listener(error)); + } + + // not yet flowing: buffer errors until flowing + else { + this.buffer.error.push(error); + } + } + + end(result?: T | Error): void { + if (this.state.destroyed) { + return; + } + + // end with data or error if provided + if (result instanceof Error) { + this.error(result); + } else if (result) { + this.write(result); + } + + // flowing: send end event to listeners + if (this.state.flowing) { + this.listeners.end.forEach(listener => listener()); + + this.destroy(); + } + + // not yet flowing: remember state + else { + this.state.ended = true; + } + } + + on(event: 'data', callback: (data: T) => void): void; + on(event: 'error', callback: (err: Error) => void): void; + on(event: 'end', callback: () => void): void; + on(event: 'data' | 'error' | 'end', callback: (arg0?: any) => void): void { + if (this.state.destroyed) { + return; + } + + switch (event) { + case 'data': + this.listeners.data.push(callback); + + // switch into flowing mode as soon as the first 'data' + // listener is added and we are not yet in flowing mode + this.resume(); + + break; + + case 'end': + this.listeners.end.push(callback); + + // emit 'end' event directly if we are flowing + // and the end has already been reached + // + // finish() when it went through + if (this.state.flowing && this.flowEnd()) { + this.destroy(); + } + + break; + + case 'error': + this.listeners.error.push(callback); + + // emit buffered 'error' events unless done already + // now that we know that we have at least one listener + if (this.state.flowing) { + this.flowErrors(); + } + + break; + } + } + + private flowData(): void { + if (this.buffer.data.length > 0) { + const fullDataBuffer = this.reducer(this.buffer.data); + + this.listeners.data.forEach(listener => listener(fullDataBuffer)); + + this.buffer.data.length = 0; + } + } + + private flowErrors(): void { + if (this.listeners.error.length > 0) { + for (const error of this.buffer.error) { + this.listeners.error.forEach(listener => listener(error)); + } + + this.buffer.error.length = 0; + } + } + + private flowEnd(): boolean { + if (this.state.ended) { + this.listeners.end.forEach(listener => listener()); + + return this.listeners.end.length > 0; + } + + return false; + } + + destroy(): void { + if (!this.state.destroyed) { + this.state.destroyed = true; + this.state.ended = true; + + this.buffer.data.length = 0; + this.buffer.error.length = 0; + + this.listeners.data.length = 0; + this.listeners.error.length = 0; + this.listeners.end.length = 0; + } + } +} + +/** + * Helper to fully read a T readable into a T. + */ +export function consumeReadable(readable: Readable, reducer: IReducer): T { + const chunks: T[] = []; + + let chunk: T | null; + while ((chunk = readable.read()) !== null) { + chunks.push(chunk); + } + + return reducer(chunks); +} + +/** + * Helper to read a T readable up to a maximum of chunks. If the limit is + * reached, will return a readable instead to ensure all data can still + * be read. + */ +export function consumeReadableWithLimit(readable: Readable, reducer: IReducer, maxChunks: number): T | Readable { + const chunks: T[] = []; + + let chunk: T | null | undefined = undefined; + while ((chunk = readable.read()) !== null && chunks.length < maxChunks) { + chunks.push(chunk); + } + + // If the last chunk is null, it means we reached the end of + // the readable and return all the data at once + if (chunk === null && chunks.length > 0) { + return reducer(chunks); + } + + // Otherwise, we still have a chunk, it means we reached the maxChunks + // value and as such we return a new Readable that first returns + // the existing read chunks and then continues with reading from + // the underlying readable. + return { + read: () => { + + // First consume chunks from our array + if (chunks.length > 0) { + return chunks.shift()!; + } + + // Then ensure to return our last read chunk + if (typeof chunk !== 'undefined') { + const lastReadChunk = chunk; + + // explicitly use undefined here to indicate that we consumed + // the chunk, which could have either been null or valued. + chunk = undefined; + + return lastReadChunk; + } + + // Finally delegate back to the Readable + return readable.read(); + } + }; +} + +/** + * Helper to fully read a T stream into a T. + */ +export function consumeStream(stream: ReadableStream, reducer: IReducer): Promise { + return new Promise((resolve, reject) => { + const chunks: T[] = []; + + stream.on('data', data => chunks.push(data)); + stream.on('error', error => reject(error)); + stream.on('end', () => resolve(reducer(chunks))); + }); +} + +/** + * Helper to read a T stream up to a maximum of chunks. If the limit is + * reached, will return a stream instead to ensure all data can still + * be read. + */ +export function consumeStreamWithLimit(stream: ReadableStream, reducer: IReducer, maxChunks: number): Promise> { + return new Promise((resolve, reject) => { + const chunks: T[] = []; + + let wrapperStream: WriteableStream | undefined = undefined; + + stream.on('data', data => { + + // If we reach maxChunks, we start to return a stream + // and make sure that any data we have already read + // is in it as well + if (!wrapperStream && chunks.length === maxChunks) { + wrapperStream = newWriteableStream(reducer); + while (chunks.length) { + wrapperStream.write(chunks.shift()!); + } + + wrapperStream.write(data); + + return resolve(wrapperStream); + } + + if (wrapperStream) { + wrapperStream.write(data); + } else { + chunks.push(data); + } + }); + + stream.on('error', error => { + if (wrapperStream) { + wrapperStream.error(error); + } else { + return reject(error); + } + }); + + stream.on('end', () => { + if (wrapperStream) { + while (chunks.length) { + wrapperStream.write(chunks.shift()!); + } + + wrapperStream.end(); + } else { + return resolve(reducer(chunks)); + } + }); + }); +} + +/** + * Helper to create a readable stream from an existing T. + */ +export function toStream(t: T, reducer: IReducer): ReadableStream { + const stream = newWriteableStream(reducer); + + stream.end(t); + + return stream; +} + +/** + * Helper to convert a T into a Readable. + */ +export function toReadable(t: T): Readable { + let consumed = false; + + return { + read: () => { + if (consumed) { + return null; + } + + consumed = true; + + return t; + } + }; +} + +/** + * Helper to transform a readable stream into another stream. + */ +export function transform(stream: ReadableStreamEvents, transformer: ITransformer, reducer: IReducer): ReadableStream { + const target = newWriteableStream(reducer); + + stream.on('data', data => target.write(transformer.data(data))); + stream.on('end', () => target.end()); + stream.on('error', error => target.error(transformer.error ? transformer.error(error) : error)); + + return target; +} diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index eadbb152df0..02fe7deb960 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CharCode } from 'vs/base/common/charCode'; +import { Constants } from 'vs/base/common/uint'; export function isFalsyOrWhitespace(str: string | undefined): boolean { if (!str || typeof str !== 'string') { @@ -350,21 +351,10 @@ function isAsciiLetter(code: number): boolean { } export function equalsIgnoreCase(a: string, b: string): boolean { - const len1 = a ? a.length : 0; - const len2 = b ? b.length : 0; - - if (len1 !== len2) { - return false; - } - - return doEqualsIgnoreCase(a, b); + return a.length === b.length && doEqualsIgnoreCase(a, b); } function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean { - if (typeof a !== 'string' || typeof b !== 'string') { - return false; - } - for (let i = 0; i < stopAt; i++) { const codeA = a.charCodeAt(i); const codeB = b.charCodeAt(i); @@ -498,6 +488,303 @@ export function isLowSurrogate(charCode: number): boolean { return (0xDC00 <= charCode && charCode <= 0xDFFF); } +/** + * get the code point that begins at offset `offset` + */ +export function getNextCodePoint(str: string, len: number, offset: number): number { + const charCode = str.charCodeAt(offset); + if (isHighSurrogate(charCode) && offset + 1 < len) { + const nextCharCode = str.charCodeAt(offset + 1); + if (isLowSurrogate(nextCharCode)) { + return ((charCode - 0xD800) << 10) + (nextCharCode - 0xDC00) + 0x10000; + } + } + return charCode; +} + +/** + * get the code point that ends right before offset `offset` + */ +function getPrevCodePoint(str: string, offset: number): number { + const charCode = str.charCodeAt(offset - 1); + if (isLowSurrogate(charCode) && offset > 1) { + const prevCharCode = str.charCodeAt(offset - 2); + if (isHighSurrogate(prevCharCode)) { + return ((prevCharCode - 0xD800) << 10) + (charCode - 0xDC00) + 0x10000; + } + } + return charCode; +} + +export function nextCharLength(str: string, offset: number): number { + const initialOffset = offset; + const len = str.length; + + let codePoint = getNextCodePoint(str, len, offset); + offset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + while (offset < len) { + codePoint = getNextCodePoint(str, len, offset); + if (!isUnicodeMark(codePoint)) { + break; + } + offset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + + return (offset - initialOffset); +} + +export function prevCharLength(str: string, offset: number): number { + const initialOffset = offset; + + let codePoint = getPrevCodePoint(str, offset); + offset -= (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + while (offset > 0 && isUnicodeMark(codePoint)) { + codePoint = getPrevCodePoint(str, offset); + offset -= (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + + return (initialOffset - offset); +} + +function _getCharContainingOffset(str: string, offset: number): [number, number] { + const len = str.length; + const initialOffset = offset; + const initialCodePoint = getNextCodePoint(str, len, offset); + offset += (initialCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + // extend to the right + while (offset < len) { + const nextCodePoint = getNextCodePoint(str, len, offset); + if (!isUnicodeMark(nextCodePoint)) { + break; + } + offset += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + const endOffset = offset; + + // extend to the left + offset = initialOffset; + let codePoint = initialCodePoint; + + while (offset > 0 && isUnicodeMark(codePoint)) { + codePoint = getPrevCodePoint(str, offset); + offset -= (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + + return [offset, endOffset]; +} + +export function getCharContainingOffset(str: string, offset: number): [number, number] { + if (offset > 0 && isLowSurrogate(str.charCodeAt(offset))) { + return _getCharContainingOffset(str, offset - 1); + } + return _getCharContainingOffset(str, offset); +} + +export function isUnicodeMark(codePoint: number): boolean { + return MarkClassifier.getInstance().isUnicodeMark(codePoint); +} + +class MarkClassifier { + + private static _INSTANCE: MarkClassifier | null = null; + + public static getInstance(): MarkClassifier { + if (!MarkClassifier._INSTANCE) { + MarkClassifier._INSTANCE = new MarkClassifier(); + } + return MarkClassifier._INSTANCE; + } + + private arr: Uint8Array; + + constructor() { + // generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-mark-test.js + const ranges = [ + 0x0300, 0x036F, 0x0483, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2, 0x05C4, 0x05C5, + 0x05C7, 0x05C7, 0x0610, 0x061A, 0x064B, 0x065F, 0x0670, 0x0670, 0x06D6, 0x06DC, 0x06DF, 0x06E4, + 0x06E7, 0x06E8, 0x06EA, 0x06ED, 0x0711, 0x0711, 0x0730, 0x074A, 0x07A6, 0x07B0, 0x07EB, 0x07F3, + 0x07FD, 0x07FD, 0x0816, 0x0819, 0x081B, 0x0823, 0x0825, 0x0827, 0x0829, 0x082D, 0x0859, 0x085B, + 0x08D3, 0x08E1, 0x08E3, 0x0903, 0x093A, 0x093C, 0x093E, 0x094F, 0x0951, 0x0957, 0x0962, 0x0963, + 0x0981, 0x0983, 0x09BC, 0x09BC, 0x09BE, 0x09CD, 0x09D7, 0x09D7, 0x09E2, 0x09E3, 0x09FE, 0x0A03, + 0x0A3C, 0x0A51, 0x0A70, 0x0A71, 0x0A75, 0x0A75, 0x0A81, 0x0A83, 0x0ABC, 0x0ABC, 0x0ABE, 0x0ACD, + 0x0AE2, 0x0AE3, 0x0AFA, 0x0B03, 0x0B3C, 0x0B3C, 0x0B3E, 0x0B57, 0x0B62, 0x0B63, 0x0B82, 0x0B82, + 0x0BBE, 0x0BCD, 0x0BD7, 0x0BD7, 0x0C00, 0x0C04, 0x0C3E, 0x0C56, 0x0C62, 0x0C63, 0x0C81, 0x0C83, + 0x0CBC, 0x0CBC, 0x0CBE, 0x0CD6, 0x0CE2, 0x0CE3, 0x0D00, 0x0D03, 0x0D3B, 0x0D3C, 0x0D3E, 0x0D4D, + 0x0D57, 0x0D57, 0x0D62, 0x0D63, 0x0D81, 0x0D83, 0x0DCA, 0x0DDF, 0x0DF2, 0x0DF3, 0x0E31, 0x0E31, + 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1, 0x0EB4, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19, + 0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F3E, 0x0F3F, 0x0F71, 0x0F84, 0x0F86, 0x0F87, + 0x0F8D, 0x0FBC, 0x0FC6, 0x0FC6, 0x102B, 0x103E, 0x1056, 0x1059, 0x105E, 0x1060, 0x1062, 0x1064, + 0x1067, 0x106D, 0x1071, 0x1074, 0x1082, 0x108D, 0x108F, 0x108F, 0x109A, 0x109D, 0x135D, 0x135F, + 0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773, 0x17B4, 0x17D3, 0x17DD, 0x17DD, + 0x180B, 0x180D, 0x1885, 0x1886, 0x18A9, 0x18A9, 0x1920, 0x193B, 0x1A17, 0x1A1B, 0x1A55, 0x1A7F, + 0x1AB0, 0x1B04, 0x1B34, 0x1B44, 0x1B6B, 0x1B73, 0x1B80, 0x1B82, 0x1BA1, 0x1BAD, 0x1BE6, 0x1BF3, + 0x1C24, 0x1C37, 0x1CD0, 0x1CD2, 0x1CD4, 0x1CE8, 0x1CED, 0x1CED, 0x1CF4, 0x1CF4, 0x1CF7, 0x1CF9, + 0x1DC0, 0x1DFF, 0x20D0, 0x20F0, 0x2CEF, 0x2CF1, 0x2D7F, 0x2D7F, 0x2DE0, 0x2DFF, 0x302A, 0x302F, + 0x3099, 0x309A, 0xA66F, 0xA672, 0xA674, 0xA67D, 0xA69E, 0xA69F, 0xA6F0, 0xA6F1, 0xA802, 0xA802, + 0xA806, 0xA806, 0xA80B, 0xA80B, 0xA823, 0xA827, 0xA82C, 0xA82C, 0xA880, 0xA881, 0xA8B4, 0xA8C5, + 0xA8E0, 0xA8F1, 0xA8FF, 0xA8FF, 0xA926, 0xA92D, 0xA947, 0xA953, 0xA980, 0xA983, 0xA9B3, 0xA9C0, + 0xA9E5, 0xA9E5, 0xAA29, 0xAA36, 0xAA43, 0xAA43, 0xAA4C, 0xAA4D, 0xAA7B, 0xAA7D, 0xAAB0, 0xAAB0, + 0xAAB2, 0xAAB4, 0xAAB7, 0xAAB8, 0xAABE, 0xAABF, 0xAAC1, 0xAAC1, 0xAAEB, 0xAAEF, 0xAAF5, 0xAAF6, + 0xABE3, 0xABEA, 0xABEC, 0xABED, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F, 0xFE20, 0xFE2F, 0x101FD, 0x101FD, + 0x102E0, 0x102E0, 0x10376, 0x1037A, 0x10A01, 0x10A0F, 0x10A38, 0x10A3F, 0x10AE5, 0x10AE6, 0x10D24, 0x10D27, + 0x10EAB, 0x10EAC, 0x10F46, 0x10F50, 0x11000, 0x11002, 0x11038, 0x11046, 0x1107F, 0x11082, 0x110B0, 0x110BA, + 0x11100, 0x11102, 0x11127, 0x11134, 0x11145, 0x11146, 0x11173, 0x11173, 0x11180, 0x11182, 0x111B3, 0x111C0, + 0x111C9, 0x111CC, 0x111CE, 0x111CF, 0x1122C, 0x11237, 0x1123E, 0x1123E, 0x112DF, 0x112EA, 0x11300, 0x11303, + 0x1133B, 0x1133C, 0x1133E, 0x1134D, 0x11357, 0x11357, 0x11362, 0x11374, 0x11435, 0x11446, 0x1145E, 0x1145E, + 0x114B0, 0x114C3, 0x115AF, 0x115C0, 0x115DC, 0x115DD, 0x11630, 0x11640, 0x116AB, 0x116B7, 0x1171D, 0x1172B, + 0x1182C, 0x1183A, 0x11930, 0x1193E, 0x11940, 0x11940, 0x11942, 0x11943, 0x119D1, 0x119E0, 0x119E4, 0x119E4, + 0x11A01, 0x11A0A, 0x11A33, 0x11A39, 0x11A3B, 0x11A3E, 0x11A47, 0x11A47, 0x11A51, 0x11A5B, 0x11A8A, 0x11A99, + 0x11C2F, 0x11C3F, 0x11C92, 0x11CB6, 0x11D31, 0x11D45, 0x11D47, 0x11D47, 0x11D8A, 0x11D97, 0x11EF3, 0x11EF6, + 0x16AF0, 0x16AF4, 0x16B30, 0x16B36, 0x16F4F, 0x16F4F, 0x16F51, 0x16F92, 0x16FE4, 0x16FF1, 0x1BC9D, 0x1BC9E, + 0x1D165, 0x1D169, 0x1D16D, 0x1D172, 0x1D17B, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD, 0x1D242, 0x1D244, + 0x1DA00, 0x1DA36, 0x1DA3B, 0x1DA6C, 0x1DA75, 0x1DA75, 0x1DA84, 0x1DA84, 0x1DA9B, 0x1E02A, 0x1E130, 0x1E136, + 0x1E2EC, 0x1E2EF, 0x1E8D0, 0x1E8D6, 0x1E944, 0x1E94A, 0xE0100, 0xE01EF + ]; + + const maxCodePoint = ranges[ranges.length - 1]; + const arrLen = Math.ceil(maxCodePoint / 8); + const arr = new Uint8Array(arrLen); + + for (let i = 0, len = ranges.length / 2; i < len; i++) { + const from = ranges[2 * i]; + const to = ranges[2 * i + 1]; + + for (let j = from; j <= to; j++) { + const div8 = j >>> 3; + const mod8 = j & 7; + arr[div8] = arr[div8] | (1 << mod8); + } + } + + this.arr = arr; + } + + public isUnicodeMark(codePoint: number): boolean { + const div8 = codePoint >>> 3; + const mod8 = codePoint & 7; + if (div8 >= this.arr.length) { + return false; + } + return (this.arr[div8] & (1 << mod8)) ? true : false; + } +} + +/** + * A manual encoding of `str` to UTF8. + * Use only in environments which do not offer native conversion methods! + */ +export function encodeUTF8(str: string): Uint8Array { + const strLen = str.length; + + // See https://en.wikipedia.org/wiki/UTF-8 + + // first loop to establish needed buffer size + let neededSize = 0; + let strOffset = 0; + while (strOffset < strLen) { + const codePoint = getNextCodePoint(str, strLen, strOffset); + strOffset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + if (codePoint < 0x0080) { + neededSize += 1; + } else if (codePoint < 0x0800) { + neededSize += 2; + } else if (codePoint < 0x10000) { + neededSize += 3; + } else { + neededSize += 4; + } + } + + // second loop to actually encode + const arr = new Uint8Array(neededSize); + strOffset = 0; + let arrOffset = 0; + while (strOffset < strLen) { + const codePoint = getNextCodePoint(str, strLen, strOffset); + strOffset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + if (codePoint < 0x0080) { + arr[arrOffset++] = codePoint; + } else if (codePoint < 0x0800) { + arr[arrOffset++] = 0b11000000 | ((codePoint & 0b00000000000000000000011111000000) >>> 6); + arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0); + } else if (codePoint < 0x10000) { + arr[arrOffset++] = 0b11100000 | ((codePoint & 0b00000000000000001111000000000000) >>> 12); + arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6); + arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0); + } else { + arr[arrOffset++] = 0b11110000 | ((codePoint & 0b00000000000111000000000000000000) >>> 18); + arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000111111000000000000) >>> 12); + arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6); + arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0); + } + } + + return arr; +} + +/** + * A manual decoding of a UTF8 string. + * Use only in environments which do not offer native conversion methods! + */ +export function decodeUTF8(buffer: Uint8Array): string { + // https://en.wikipedia.org/wiki/UTF-8 + + const len = buffer.byteLength; + const result: string[] = []; + let offset = 0; + while (offset < len) { + const v0 = buffer[offset]; + let codePoint: number; + if (v0 >= 0b11110000 && offset + 3 < len) { + // 4 bytes + codePoint = ( + (((buffer[offset++] & 0b00000111) << 18) >>> 0) + | (((buffer[offset++] & 0b00111111) << 12) >>> 0) + | (((buffer[offset++] & 0b00111111) << 6) >>> 0) + | (((buffer[offset++] & 0b00111111) << 0) >>> 0) + ); + } else if (v0 >= 0b11100000 && offset + 2 < len) { + // 3 bytes + codePoint = ( + (((buffer[offset++] & 0b00001111) << 12) >>> 0) + | (((buffer[offset++] & 0b00111111) << 6) >>> 0) + | (((buffer[offset++] & 0b00111111) << 0) >>> 0) + ); + } else if (v0 >= 0b11000000 && offset + 1 < len) { + // 2 bytes + codePoint = ( + (((buffer[offset++] & 0b00011111) << 6) >>> 0) + | (((buffer[offset++] & 0b00111111) << 0) >>> 0) + ); + } else { + // 1 byte + codePoint = buffer[offset++]; + } + + if ((codePoint >= 0 && codePoint <= 0xD7FF) || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) { + // Basic Multilingual Plane + result.push(String.fromCharCode(codePoint)); + } else if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) { + // Supplementary Planes + const uPrime = codePoint - 0x10000; + const w1 = 0xD800 + ((uPrime & 0b11111111110000000000) >>> 10); + const w2 = 0xDC00 + ((uPrime & 0b00000000001111111111) >>> 0); + result.push(String.fromCharCode(w1)); + result.push(String.fromCharCode(w2)); + } else { + // illegal code point + result.push(String.fromCharCode(0xFFFD)); + } + } + + return result.join(''); +} + /** * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-rtl-test.js */ @@ -513,7 +800,7 @@ export function containsRTL(str: string): boolean { /** * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-emoji-test.js */ -const CONTAINS_EMOJI = /(?:[\u231A\u231B\u23F0\u23F3\u2600-\u27BF\u2B50\u2B55]|\uD83C[\uDDE6-\uDDFF\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F\uDE80-\uDEF8]|\uD83E[\uDD00-\uDDE6])/; +const CONTAINS_EMOJI = /(?:[\u231A\u231B\u23F0\u23F3\u2600-\u27BF\u2B50\u2B55]|\uD83C[\uDDE6-\uDDFF\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F\uDE80-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD00-\uDDFF\uDE70-\uDE73\uDE78-\uDE82\uDE90-\uDE95])/; export function containsEmoji(str: string): boolean { return CONTAINS_EMOJI.test(str); @@ -583,6 +870,18 @@ export function isFullWidthCharacter(charCode: number): boolean { ); } +/** + * A fast function (therefore imprecise) to check if code points are emojis. + * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-emoji-test.js + */ +export function isEmojiImprecise(x: number): boolean { + return ( + (x >= 0x1F1E6 && x <= 0x1F1FF) || (x >= 9728 && x <= 10175) || (x >= 127744 && x <= 128591) + || (x >= 128640 && x <= 128764) || (x >= 128992 && x <= 129003) || (x >= 129280 && x <= 129535) + || (x >= 129648 && x <= 129651) || (x >= 129656 && x <= 129666) || (x >= 129680 && x <= 129685) + ); +} + /** * Given a string and a max length returns a shorted version. Shorting * happens at favorable positions - such as whitespace or punctuation characters. diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index 56d365091e9..f464f9a0cb4 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -93,6 +93,39 @@ export function isUndefinedOrNull(obj: any): obj is undefined | null { return isUndefined(obj) || obj === null; } +/** + * Asserts that the argument passed in is neither undefined nor null. + */ +export function assertIsDefined(arg: T | null | undefined): T { + if (isUndefinedOrNull(arg)) { + throw new Error('Assertion Failed: argument is undefined or null'); + } + + return arg; +} + +/** + * Asserts that each argument passed in is neither undefined nor null. + */ +export function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined): [T1, T2]; +export function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined): [T1, T2, T3]; +export function assertAllDefined(t1: T1 | null | undefined, t2: T2 | null | undefined, t3: T3 | null | undefined, t4: T4 | null | undefined): [T1, T2, T3, T4]; +export function assertAllDefined(...args: (unknown | null | undefined)[]): unknown[] { + const result = []; + + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + + if (isUndefinedOrNull(arg)) { + throw new Error(`Assertion Failed: argument at index ${i} is undefined or null`); + } + + result.push(arg); + } + + return result; +} + const hasOwnProperty = Object.prototype.hasOwnProperty; /** @@ -207,3 +240,18 @@ export function withNullAsUndefined(x: T | null): T | undefined { export function withUndefinedAsNull(x: T | undefined): T | null { return typeof x === 'undefined' ? null : x; } + +/** + * Allows to add a first parameter to functions of a type. + */ +export type AddFirstParameterToFunctions = { + + // For every property + [K in keyof Target]: + + // Function: add param to function + Target[K] extends (...args: any) => TargetFunctionsReturnType ? (firstArg: FirstParameter, ...args: Parameters) => ReturnType : + + // Else: just leave as is + Target[K] +}; diff --git a/src/vs/editor/common/core/uint.ts b/src/vs/base/common/uint.ts similarity index 74% rename from src/vs/editor/common/core/uint.ts rename to src/vs/base/common/uint.ts index 00e3b872903..b44e0fdaec7 100644 --- a/src/vs/editor/common/core/uint.ts +++ b/src/vs/base/common/uint.ts @@ -3,32 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export class Uint8Matrix { - - private readonly _data: Uint8Array; - public readonly rows: number; - public readonly cols: number; - - constructor(rows: number, cols: number, defaultValue: number) { - const data = new Uint8Array(rows * cols); - for (let i = 0, len = rows * cols; i < len; i++) { - data[i] = defaultValue; - } - - this._data = data; - this.rows = rows; - this.cols = cols; - } - - public get(row: number, col: number): number { - return this._data[row * this.cols + col]; - } - - public set(row: number, col: number, value: number): void { - this._data[row * this.cols + col] = value; - } -} - export const enum Constants { /** * MAX SMI (SMall Integer) as defined in v8. @@ -61,7 +35,7 @@ export const enum Constants { */ MAX_UINT_32 = 4294967295, // 2^32 - 1 - + UNICODE_SUPPLEMENTARY_PLANE_BEGIN = 0x010000 } export function toUint8(v: number): number { diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 966555e04d0..f6a8959a04c 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -10,26 +10,11 @@ const _schemePattern = /^\w[\w\d+.-]*$/; const _singleSlashStart = /^\//; const _doubleSlashStart = /^\/\//; -let _throwOnMissingSchema: boolean = true; - -/** - * @internal - */ -export function setUriThrowOnMissingScheme(value: boolean): boolean { - const old = _throwOnMissingSchema; - _throwOnMissingSchema = value; - return old; -} - function _validateUri(ret: URI, _strict?: boolean): void { // scheme, must be set - if (!ret.scheme) { - if (_strict || _throwOnMissingSchema) { - throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`); - } else { - console.warn(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`); - } + if (!ret.scheme && _strict) { + throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`); } // scheme, https://tools.ietf.org/html/rfc3986#section-3.1 @@ -61,12 +46,8 @@ function _validateUri(ret: URI, _strict?: boolean): void { // back to the file-scheme. that should cause the least carnage and still be a // clear warning function _schemeFix(scheme: string, _strict: boolean): string { - if (_strict || _throwOnMissingSchema) { - return scheme || _empty; - } - if (!scheme) { - console.trace('BAD uri lacks scheme, falling back to file-scheme.'); - scheme = 'file'; + if (!scheme && !_strict) { + return 'file'; } return scheme; } diff --git a/src/vs/base/node/decoder.ts b/src/vs/base/node/decoder.ts index 5146d0e24de..0e313a5715a 100644 --- a/src/vs/base/node/decoder.ts +++ b/src/vs/base/node/decoder.ts @@ -59,4 +59,4 @@ export class LineDecoder { end(): string | null { return this.remaining; } -} \ No newline at end of file +} diff --git a/src/vs/base/node/encoding.ts b/src/vs/base/node/encoding.ts index 83428b3590c..0df9dbd26c2 100644 --- a/src/vs/base/node/encoding.ts +++ b/src/vs/base/node/encoding.ts @@ -111,7 +111,7 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions }); } - _final(callback: (error: Error | null) => void) { + _final(callback: () => void) { // normal finish if (this.decodeStream) { @@ -122,7 +122,11 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions // detection. thus, wrap up starting the stream even // without all the data to get things going else { - this._startDecodeStream(() => this.decodeStream!.end(callback)); + this._startDecodeStream(() => { + if (this.decodeStream) { + this.decodeStream.end(callback); + } + }); } } }; @@ -140,7 +144,7 @@ export function decode(buffer: Buffer, encoding: string): string { } export function encode(content: string | Buffer, encoding: string, options?: { addBOM?: boolean }): Buffer { - return iconv.encode(content, toNodeEncoding(encoding), options); + return iconv.encode(content as string /* TODO report into upstream typings */, toNodeEncoding(encoding), options); } export function encodingExists(encoding: string): boolean { diff --git a/src/vs/base/node/languagePacks.d.ts b/src/vs/base/node/languagePacks.d.ts index 241392e5eca..5c69043ef23 100644 --- a/src/vs/base/node/languagePacks.d.ts +++ b/src/vs/base/node/languagePacks.d.ts @@ -9,6 +9,7 @@ export interface NLSConfiguration { [key: string]: string; }; pseudo?: boolean; + _languagePackSupport?: boolean; } export interface InternalNLSConfiguration extends NLSConfiguration { @@ -20,4 +21,4 @@ export interface InternalNLSConfiguration extends NLSConfiguration { _languagePackSupport?: boolean; } -export function getNLSConfiguration(commit: string, userDataPath: string, metaDataFile: string, locale: string): Promise; \ No newline at end of file +export function getNLSConfiguration(commit: string, userDataPath: string, metaDataFile: string, locale: string): Promise; diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js index 3ae24454cb7..2c64061da7b 100644 --- a/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js @@ -50,8 +50,8 @@ function factory(nodeRequire, path, fs, perf) { * @param {string} dir * @returns {Promise} */ - function mkdir(dir) { - return new Promise((c, e) => fs.mkdir(dir, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); + function mkdirp(dir) { + return new Promise((c, e) => fs.mkdir(dir, { recursive: true }, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); } /** @@ -91,24 +91,6 @@ function factory(nodeRequire, path, fs, perf) { }); } - /** - * @param {string} dir - * @returns {Promise} - */ - function mkdirp(dir) { - return mkdir(dir).then(null, err => { - if (err && err.code === 'ENOENT') { - const parent = path.dirname(dir); - - if (parent !== dir) { // if not arrived at root - return mkdirp(parent).then(() => mkdir(dir)); - } - } - - throw err; - }); - } - function readFile(file) { return new Promise(function (resolve, reject) { fs.readFile(file, 'utf8', function (err, data) { diff --git a/src/vs/base/node/macAddress.ts b/src/vs/base/node/macAddress.ts index dd36be22344..524b136c06b 100644 --- a/src/vs/base/node/macAddress.ts +++ b/src/vs/base/node/macAddress.ts @@ -11,21 +11,15 @@ const cmdline = { unix: '/sbin/ifconfig -a || /sbin/ip link' }; -const invalidMacAddresses = [ +const invalidMacAddresses = new Set([ '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; + const tempCandidate = candidate.replace(/\-/g, ':').toLowerCase(); + return !invalidMacAddresses.has(tempCandidate); } export function getMac(): Promise { @@ -66,4 +60,4 @@ function doGetMac(): Promise { reject(err); } }); -} \ No newline at end of file +} diff --git a/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts index 14dca3d5f49..1b294073eed 100644 --- a/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { join, dirname } from 'vs/base/common/path'; +import { join } from 'vs/base/common/path'; import { Queue } from 'vs/base/common/async'; import * as fs from 'fs'; import * as os from 'os'; @@ -11,7 +11,6 @@ import * as platform from 'vs/base/common/platform'; import { Event } from 'vs/base/common/event'; import { endsWith } from 'vs/base/common/strings'; import { promisify } from 'util'; -import { CancellationToken } from 'vs/base/common/cancellation'; import { isRootOrDriveLetter } from 'vs/base/common/extpath'; import { generateUuid } from 'vs/base/common/uuid'; import { normalizeNFC } from 'vs/base/common/normalization'; @@ -138,6 +137,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)); } @@ -384,7 +397,7 @@ function doWriteFileStreamAndFlush(path: string, reader: NodeJS.ReadableStream, // not in some cache. // // See https://github.com/nodejs/node/blob/v5.10.0/lib/fs.js#L1194 -function doWriteFileAndFlush(path: string, data: string | Buffer | Uint8Array, options: IEnsuredWriteFileOptions, callback: (error?: Error) => void): void { +function doWriteFileAndFlush(path: string, data: string | Buffer | Uint8Array, options: IEnsuredWriteFileOptions, callback: (error: Error | null) => void): void { if (options.encoding) { data = encode(data instanceof Uint8Array ? Buffer.from(data) : data, options.encoding.charset, { addBOM: options.encoding.addBOM }); } @@ -619,55 +632,8 @@ async function doCopyFile(source: string, target: string, mode: number): Promise }); } -export async function mkdirp(path: string, mode?: number, token?: CancellationToken): Promise { - const mkdir = async () => { - try { - await promisify(fs.mkdir)(path, mode); - } catch (error) { - - // ENOENT: a parent folder does not exist yet - if (error.code === 'ENOENT') { - return Promise.reject(error); - } - - // Any other error: check if folder exists and - // return normally in that case if its a folder - try { - const fileStat = await stat(path); - if (!fileStat.isDirectory()) { - return Promise.reject(new Error(`'${path}' exists and is not a directory.`)); - } - } catch (statError) { - throw error; // rethrow original error - } - } - }; - - // stop at root - if (path === dirname(path)) { - return Promise.resolve(); - } - - try { - await mkdir(); - } catch (error) { - - // Respect cancellation - if (token && token.isCancellationRequested) { - return Promise.resolve(); - } - - // ENOENT: a parent folder does not exist yet, continue - // to create the parent folder and then try again. - if (error.code === 'ENOENT') { - await mkdirp(dirname(path), mode); - - return mkdir(); - } - - // Any other error - return Promise.reject(error); - } +export async function mkdirp(path: string, mode?: number): Promise { + return promisify(fs.mkdir)(path, { mode, recursive: true }); } // See https://github.com/Microsoft/vscode/issues/30180 @@ -679,4 +645,4 @@ 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 +export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE; diff --git a/src/vs/base/node/processes.ts b/src/vs/base/node/processes.ts index 5bee9f9eced..b6f7742e2b3 100644 --- a/src/vs/base/node/processes.ts +++ b/src/vs/base/node/processes.ts @@ -40,7 +40,7 @@ function getWindowsCode(status: number): TerminateResponseCode { } } -export function terminateProcess(process: cp.ChildProcess, cwd?: string): TerminateResponse { +function terminateProcess(process: cp.ChildProcess, cwd?: string): Promise { if (Platform.isWindows) { try { const options: any = { @@ -49,24 +49,41 @@ export function terminateProcess(process: cp.ChildProcess, cwd?: string): Termin if (cwd) { options.cwd = cwd; } - cp.execFileSync('taskkill', ['/T', '/F', '/PID', process.pid.toString()], options); + const killProcess = cp.execFile('taskkill', ['/T', '/F', '/PID', process.pid.toString()], options); + return new Promise((resolve, reject) => { + killProcess.once('error', (err) => { + resolve({ success: false, error: err }); + }); + killProcess.once('exit', (code, signal) => { + if (code === 0) { + resolve({ success: true }); + } else { + resolve({ success: false, code: code !== null ? code : TerminateResponseCode.Unknown }); + } + }); + }); } catch (err) { - return { success: false, error: err, code: err.status ? getWindowsCode(err.status) : TerminateResponseCode.Unknown }; + return Promise.resolve({ success: false, error: err, code: err.status ? getWindowsCode(err.status) : TerminateResponseCode.Unknown }); } } else if (Platform.isLinux || Platform.isMacintosh) { try { const cmd = getPathFromAmdModule(require, 'vs/base/node/terminateProcess.sh'); - const result = cp.spawnSync(cmd, [process.pid.toString()]); - if (result.error) { - return { success: false, error: result.error }; - } + return new Promise((resolve, reject) => { + cp.execFile(cmd, [process.pid.toString()], { encoding: 'utf8', shell: true } as cp.ExecFileOptions, (err, stdout, stderr) => { + if (err) { + resolve({ success: false, error: err }); + } else { + resolve({ success: true }); + } + }); + }); } catch (err) { - return { success: false, error: err }; + return Promise.resolve({ success: false, error: err }); } } else { process.kill('SIGKILL'); } - return { success: true }; + return Promise.resolve({ success: true }); } export function getWindowsShell(): string { @@ -122,6 +139,7 @@ export abstract class AbstractProcess { } this.childProcess = null; + this.childProcessPromise = null; this.terminateRequested = false; if (this.options.env) { @@ -288,11 +306,12 @@ export abstract class AbstractProcess { } return this.childProcessPromise.then((childProcess) => { this.terminateRequested = true; - const result = terminateProcess(childProcess, this.options.cwd); - if (result.success) { - this.childProcess = null; - } - return result; + return terminateProcess(childProcess, this.options.cwd).then(response => { + if (response.success) { + this.childProcess = null; + } + return response; + }); }, (err) => { return { success: true }; }); @@ -316,13 +335,16 @@ export abstract class AbstractProcess { export class LineProcess extends AbstractProcess { - private stdoutLineDecoder: LineDecoder; - private stderrLineDecoder: LineDecoder; + private stdoutLineDecoder: LineDecoder | null; + private stderrLineDecoder: LineDecoder | null; public constructor(executable: Executable); public constructor(cmd: string, args: string[], shell: boolean, options: CommandOptions); public constructor(arg1: string | Executable, arg2?: string[], arg3?: boolean | ForkOptions, arg4?: CommandOptions) { super(arg1, arg2, arg3, arg4); + + this.stdoutLineDecoder = null; + this.stderrLineDecoder = null; } protected handleExec(cc: ValueCallback, pp: ProgressCallback, error: Error, stdout: Buffer, stderr: Buffer) { @@ -341,24 +363,30 @@ export class LineProcess extends AbstractProcess { } protected handleSpawn(childProcess: cp.ChildProcess, cc: ValueCallback, pp: ProgressCallback, ee: ErrorCallback, sync: boolean): void { - this.stdoutLineDecoder = new LineDecoder(); - this.stderrLineDecoder = new LineDecoder(); - childProcess.stdout.on('data', (data: Buffer) => { - const lines = this.stdoutLineDecoder.write(data); + const stdoutLineDecoder = new LineDecoder(); + const stderrLineDecoder = new LineDecoder(); + childProcess.stdout!.on('data', (data: Buffer) => { + const lines = stdoutLineDecoder.write(data); lines.forEach(line => pp({ line: line, source: Source.stdout })); }); - childProcess.stderr.on('data', (data: Buffer) => { - const lines = this.stderrLineDecoder.write(data); + childProcess.stderr!.on('data', (data: Buffer) => { + const lines = stderrLineDecoder.write(data); lines.forEach(line => pp({ line: line, source: Source.stderr })); }); + + this.stdoutLineDecoder = stdoutLineDecoder; + this.stderrLineDecoder = stderrLineDecoder; } protected handleClose(data: any, cc: ValueCallback, pp: ProgressCallback, ee: ErrorCallback): void { - [this.stdoutLineDecoder.end(), this.stderrLineDecoder.end()].forEach((line, index) => { - if (line) { - pp({ line: line, source: index === 0 ? Source.stdout : Source.stderr }); - } - }); + const stdoutLine = this.stdoutLineDecoder ? this.stdoutLineDecoder.end() : null; + if (stdoutLine) { + pp({ line: stdoutLine, source: Source.stdout }); + } + const stderrLine = this.stderrLineDecoder ? this.stderrLineDecoder.end() : null; + if (stderrLine) { + pp({ line: stderrLine, source: Source.stderr }); + } } } @@ -426,6 +454,14 @@ export namespace win32 { if (paths === undefined || paths.length === 0) { return path.join(cwd, command); } + + async function fileExists(path: string): Promise { + if (await promisify(fs.exists)(path)) { + return !((await promisify(fs.stat)(path)).isDirectory); + } + return false; + } + // We have a simple file name. We get the path variable from the env // and try to find the executable on the path. for (let pathEntry of paths) { @@ -436,15 +472,15 @@ export namespace win32 { } else { fullPath = path.join(cwd, pathEntry, command); } - if (await promisify(fs.exists)(fullPath)) { + if (await fileExists(fullPath)) { return fullPath; } let withExtension = fullPath + '.com'; - if (await promisify(fs.exists)(withExtension)) { + if (await fileExists(withExtension)) { return withExtension; } withExtension = fullPath + '.exe'; - if (await promisify(fs.exists)(withExtension)) { + if (await fileExists(withExtension)) { return withExtension; } } diff --git a/src/vs/base/node/zip.ts b/src/vs/base/node/zip.ts index 3c474dc0343..eaa6fa36ff8 100644 --- a/src/vs/base/node/zip.ts +++ b/src/vs/base/node/zip.ts @@ -86,7 +86,7 @@ function extractEntry(stream: Readable, fileName: string, mode: number, targetPa } }); - return Promise.resolve(mkdirp(targetDirName, undefined, token)).then(() => new Promise((c, e) => { + return Promise.resolve(mkdirp(targetDirName)).then(() => new Promise((c, e) => { if (token.isCancellationRequested) { return; } @@ -149,14 +149,14 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions, tok // directory file names end with '/' if (/\/$/.test(fileName)) { const targetFileName = path.join(targetPath, fileName); - last = createCancelablePromise(token => mkdirp(targetFileName, undefined, token).then(() => readNextEntry(token)).then(undefined, e)); + last = createCancelablePromise(token => mkdirp(targetFileName).then(() => readNextEntry(token)).then(undefined, e)); return; } const stream = openZipStream(zipfile, entry); const mode = modeFromEntry(entry); - last = createCancelablePromise(token => throttler.queue(() => stream.then(stream => extractEntry(stream, fileName, mode, targetPath, options, token).then(() => readNextEntry(token)))).then(null!, e)); + last = createCancelablePromise(token => throttler.queue(() => stream.then(stream => extractEntry(stream, fileName, mode, targetPath, options, token).then(() => readNextEntry(token)))).then(null, e)); }); }); } diff --git a/src/vs/base/parts/contextmenu/electron-browser/contextmenu.ts b/src/vs/base/parts/contextmenu/electron-browser/contextmenu.ts index 26212a79fe1..da008e59930 100644 --- a/src/vs/base/parts/contextmenu/electron-browser/contextmenu.ts +++ b/src/vs/base/parts/contextmenu/electron-browser/contextmenu.ts @@ -28,7 +28,7 @@ export function popup(items: IContextMenuItem[], options?: IPopupOptions): void ipcRenderer.removeListener(onClickChannel, onClickChannelHandler); - if (options && options.onHide) { + if (options?.onHide) { options.onHide(); } }); @@ -55,4 +55,4 @@ function createItem(item: IContextMenuItem, processedItems: IContextMenuItem[]): } return serializableItem; -} \ 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 b2b939b0ba2..132654b320f 100644 --- a/src/vs/base/parts/ipc/common/ipc.net.ts +++ b/src/vs/base/parts/ipc/common/ipc.net.ts @@ -137,7 +137,7 @@ export const enum ProtocolConstants { /** * If there is a message that has been unacknowledged for 10 seconds, consider the connection closed... */ - AcknowledgeTimeoutTime = 10000, // 10 seconds + AcknowledgeTimeoutTime = 20000, // 20 seconds /** * Send at least a message every 5s for keep alive reasons. */ @@ -145,7 +145,7 @@ export const enum ProtocolConstants { /** * If there is no message received for 10 seconds, consider the connection closed... */ - KeepAliveTimeoutTime = 10000, // 10 seconds + KeepAliveTimeoutTime = 20000, // 20 seconds /** * If there is no reconnection within this time-frame, consider the connection permanently closed... */ @@ -284,8 +284,8 @@ class ProtocolWriter { public write(msg: ProtocolMessage) { if (this._isDisposed) { - console.warn(`Cannot write message in a disposed ProtocolWriter`); - console.warn(msg); + // ignore: there could be left-over promises which complete and then + // decide to write a response, etc... return; } msg.writtenTime = Date.now(); diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 7b60ba4a101..48f75577206 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -8,7 +8,6 @@ import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/li import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; -import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; import { VSBuffer } from 'vs/base/common/buffer'; /** diff --git a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts index b310a886f67..bac2223ede6 100644 --- a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts +++ b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts @@ -23,7 +23,7 @@ function createScopedOnMessageEvent(senderId: number, eventName: string): Event< export class Server extends IPCServer { - private static Clients = new Map(); + private static readonly Clients = new Map(); private static getOnDidClientConnect(): Event { const onHello = Event.fromNodeEventEmitter(ipcMain, 'ipc:hello', ({ sender }) => sender); diff --git a/src/vs/base/parts/ipc/node/ipc.ts b/src/vs/base/parts/ipc/node/ipc.ts new file mode 100644 index 00000000000..631e5139133 --- /dev/null +++ b/src/vs/base/parts/ipc/node/ipc.ts @@ -0,0 +1,133 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { revive } from 'vs/base/common/marshalling'; +import { isUndefinedOrNull } from 'vs/base/common/types'; +import { isUpperAsciiLetter } from 'vs/base/common/strings'; + +/** + * Use both `createChannelReceiver` and `createChannelSender` + * for automated process <=> process communication over methods + * and events. You do not need to spell out each method on both + * sides, a proxy will take care of this. + * + * Rules: + * - if marshalling is enabled, only `URI` and `RegExp` is converted + * automatically for you + * - events must follow the naming convention `onUppercase` + * - `CancellationToken` is currently not supported + * - if a context is provided, you can use `AddFirstParameterToFunctions` + * utility to signal this in the receiving side type + */ + +export interface IBaseChannelOptions { + + /** + * Disables automatic marshalling of `URI`. + * If marshalling is disabled, `UriComponents` + * must be used instead. + */ + disableMarshalling?: boolean; +} + +export interface IChannelReceiverOptions extends IBaseChannelOptions { } + +export function createChannelReceiver(service: unknown, options?: IChannelReceiverOptions): IServerChannel { + const handler = service as { [key: string]: unknown }; + const disableMarshalling = options && options.disableMarshalling; + + // Buffer any event that should be supported by + // iterating over all property keys and finding them + const mapEventNameToEvent = new Map>(); + for (const key in handler) { + if (propertyIsEvent(key)) { + mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event, true)); + } + } + + return new class implements IServerChannel { + + listen(_: unknown, event: string): Event { + const eventImpl = mapEventNameToEvent.get(event); + if (eventImpl) { + return eventImpl as Event; + } + + throw new Error(`Event not found: ${event}`); + } + + call(_: unknown, command: string, args?: any[]): Promise { + const target = handler[command]; + if (typeof target === 'function') { + + // Revive unless marshalling disabled + if (!disableMarshalling && Array.isArray(args)) { + for (let i = 0; i < args.length; i++) { + args[i] = revive(args[i]); + } + } + + return target.apply(handler, args); + } + + throw new Error(`Method not found: ${command}`); + } + }; +} + +export interface IChannelSenderOptions extends IBaseChannelOptions { + + /** + * If provided, will add the value of `context` + * to each method call to the target. + */ + context?: unknown; +} + +export function createChannelSender(channel: IChannel, options?: IChannelSenderOptions): T { + const disableMarshalling = options && options.disableMarshalling; + + return new Proxy({}, { + get(_target: T, propKey: PropertyKey) { + if (typeof propKey === 'string') { + + // Event + if (propertyIsEvent(propKey)) { + return channel.listen(propKey); + } + + // Function + return async function (...args: any[]) { + + // Add context if any + let methodArgs: any[]; + if (options && !isUndefinedOrNull(options.context)) { + methodArgs = [options.context, ...args]; + } else { + methodArgs = args; + } + + const result = await channel.call(propKey, methodArgs); + + // Revive unless marshalling disabled + if (!disableMarshalling) { + return revive(result); + } + + return result; + }; + } + + throw new Error(`Property not found: ${String(propKey)}`); + } + }) as T; +} + +function propertyIsEvent(name: string): boolean { + // Assume a property is an event if it has a form of "onSomething" + return name[0] === 'o' && name[1] === 'n' && isUpperAsciiLetter(name.charCodeAt(2)); +} diff --git a/src/vs/base/parts/ipc/test/node/ipc.test.ts b/src/vs/base/parts/ipc/test/node/ipc.test.ts index 26481f88f55..589acae53d4 100644 --- a/src/vs/base/parts/ipc/test/node/ipc.test.ts +++ b/src/vs/base/parts/ipc/test/node/ipc.test.ts @@ -5,11 +5,14 @@ import * as assert from 'assert'; import { IChannel, IServerChannel, IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient } from 'vs/base/parts/ipc/common/ipc'; +import { createChannelReceiver, createChannelSender } from 'vs/base/parts/ipc/node/ipc'; import { Emitter, Event } from 'vs/base/common/event'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { canceled } from 'vs/base/common/errors'; import { timeout } from 'vs/base/common/async'; import { VSBuffer } from 'vs/base/common/buffer'; +import { URI } from 'vs/base/common/uri'; +import { isEqual } from 'vs/base/common/resources'; class QueueProtocol implements IMessagePassingProtocol { @@ -101,14 +104,16 @@ interface ITestService { neverComplete(): Promise; neverCompleteCT(cancellationToken: CancellationToken): Promise; buffersLength(buffers: Buffer[]): Promise; + marshall(uri: URI): Promise; + context(): Promise; - pong: Event; + onPong: Event; } class TestService implements ITestService { - private readonly _pong = new Emitter(); - readonly pong = this._pong.event; + private readonly _onPong = new Emitter(); + readonly onPong = this._onPong.event; marco(): Promise { return Promise.resolve('polo'); @@ -135,7 +140,15 @@ class TestService implements ITestService { } ping(msg: string): void { - this._pong.fire(msg); + this._onPong.fire(msg); + } + + marshall(uri: URI): Promise { + return Promise.resolve(uri); + } + + context(context?: unknown): Promise { + return Promise.resolve(context); } } @@ -156,7 +169,7 @@ class TestChannel implements IServerChannel { listen(_: unknown, event: string, arg?: any): Event { switch (event) { - case 'pong': return this.service.pong; + case 'onPong': return this.service.onPong; default: throw new Error('not implemented'); } } @@ -164,8 +177,8 @@ class TestChannel implements IServerChannel { class TestChannelClient implements ITestService { - get pong(): Event { - return this.channel.listen('pong'); + get onPong(): Event { + return this.channel.listen('onPong'); } constructor(private channel: IChannel) { } @@ -189,6 +202,14 @@ class TestChannelClient implements ITestService { buffersLength(buffers: Buffer[]): Promise { return this.channel.call('buffersLength', buffers); } + + marshall(uri: URI): Promise { + return this.channel.call('marshall', uri); + } + + context(): Promise { + return this.channel.call('context'); + } } suite('Base IPC', function () { @@ -281,7 +302,7 @@ suite('Base IPC', function () { test('listen to events', async function () { const messages: string[] = []; - ipcService.pong(msg => messages.push(msg)); + ipcService.onPong(msg => messages.push(msg)); await timeout(0); assert.deepEqual(messages, []); @@ -300,4 +321,98 @@ suite('Base IPC', function () { return assert.equal(r, 5); }); }); + + suite('one to one (proxy)', function () { + let server: IPCServer; + let client: IPCClient; + let service: TestService; + let ipcService: ITestService; + + setup(function () { + service = new TestService(); + const testServer = new TestIPCServer(); + server = testServer; + + server.registerChannel(TestChannelId, createChannelReceiver(service)); + + client = testServer.createConnection('client1'); + ipcService = createChannelSender(client.getChannel(TestChannelId)); + }); + + teardown(function () { + client.dispose(); + server.dispose(); + }); + + test('call success', async function () { + const r = await ipcService.marco(); + return assert.equal(r, 'polo'); + }); + + test('call error', async function () { + try { + await ipcService.error('nice error'); + return assert.fail('should not reach here'); + } catch (err) { + return assert.equal(err.message, 'nice error'); + } + }); + + test('listen to events', async function () { + const messages: string[] = []; + + ipcService.onPong(msg => messages.push(msg)); + await timeout(0); + + assert.deepEqual(messages, []); + service.ping('hello'); + await timeout(0); + + assert.deepEqual(messages, ['hello']); + service.ping('world'); + await timeout(0); + + assert.deepEqual(messages, ['hello', 'world']); + }); + + test('marshalling uri', async function () { + const uri = URI.file('foobar'); + const r = await ipcService.marshall(uri); + assert.ok(r instanceof URI); + return assert.ok(isEqual(r, uri)); + }); + + test('buffers in arrays', async function () { + const r = await ipcService.buffersLength([Buffer.allocUnsafe(2), Buffer.allocUnsafe(3)]); + return assert.equal(r, 5); + }); + }); + + suite('one to one (proxy, extra context)', function () { + let server: IPCServer; + let client: IPCClient; + let service: TestService; + let ipcService: ITestService; + + setup(function () { + service = new TestService(); + const testServer = new TestIPCServer(); + server = testServer; + + server.registerChannel(TestChannelId, createChannelReceiver(service)); + + client = testServer.createConnection('client1'); + ipcService = createChannelSender(client.getChannel(TestChannelId), { context: 'Super Context' }); + }); + + teardown(function () { + client.dispose(); + server.dispose(); + }); + + test('call extra context', async function () { + const r = await ipcService.context(); + return assert.equal(r, 'Super Context'); + }); + }); }); diff --git a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts index fdd8bcbf06b..463323c2363 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts @@ -53,7 +53,7 @@ export const QuickOpenItemAccessor = new QuickOpenItemAccessorClass(); export class QuickOpenEntry { private id: string; - private labelHighlights: IHighlight[]; + private labelHighlights?: IHighlight[]; private descriptionHighlights?: IHighlight[]; private detailHighlights?: IHighlight[]; private hidden: boolean | undefined; @@ -160,7 +160,7 @@ export class QuickOpenEntry { /** * Allows to set highlight ranges that should show up for the entry label and optionally description if set. */ - setHighlights(labelHighlights: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void { + setHighlights(labelHighlights?: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void { this.labelHighlights = labelHighlights; this.descriptionHighlights = descriptionHighlights; this.detailHighlights = detailHighlights; @@ -169,7 +169,7 @@ export class QuickOpenEntry { /** * Allows to return highlight ranges that should show up for the entry label and description. */ - getHighlights(): [IHighlight[] /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] { + getHighlights(): [IHighlight[] | undefined /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] { return [this.labelHighlights, this.descriptionHighlights, this.detailHighlights]; } @@ -260,7 +260,7 @@ export class QuickOpenEntryGroup extends QuickOpenEntry { return this.entry; } - getHighlights(): [IHighlight[], IHighlight[] | undefined, IHighlight[] | undefined] { + getHighlights(): [IHighlight[] | undefined, IHighlight[] | undefined, IHighlight[] | undefined] { return this.entry ? this.entry.getHighlights() : super.getHighlights(); } @@ -268,7 +268,7 @@ export class QuickOpenEntryGroup extends QuickOpenEntry { return this.entry ? this.entry.isHidden() : super.isHidden(); } - setHighlights(labelHighlights: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void { + setHighlights(labelHighlights?: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void { this.entry ? this.entry.setHighlights(labelHighlights, descriptionHighlights, detailHighlights) : super.setHighlights(labelHighlights, descriptionHighlights, detailHighlights); } @@ -351,7 +351,7 @@ class Renderer implements IRenderer { row1.appendChild(icon); // Label - const label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportOcticons: true }); + const label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportCodicons: true }); // Keybinding const keybindingContainer = document.createElement('span'); @@ -434,7 +434,7 @@ class Renderer implements IRenderer { } } else { DOM.removeClass(groupData.container, 'results-group-separator'); - groupData.container.style.borderTopColor = null; + groupData.container.style.borderTopColor = ''; } // Group Label diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 68be9fba510..7a3a473d970 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -99,25 +99,40 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { private isDisposed: boolean; private options: IQuickOpenOptions; + // @ts-ignore (legacy widget - to be replaced with quick input) private element: HTMLElement; + // @ts-ignore (legacy widget - to be replaced with quick input) private tree: ITree; + // @ts-ignore (legacy widget - to be replaced with quick input) private inputBox: InputBox; + // @ts-ignore (legacy widget - to be replaced with quick input) private inputContainer: HTMLElement; + // @ts-ignore (legacy widget - to be replaced with quick input) private helpText: HTMLElement; + // @ts-ignore (legacy widget - to be replaced with quick input) private resultCount: HTMLElement; + // @ts-ignore (legacy widget - to be replaced with quick input) private treeContainer: HTMLElement; + // @ts-ignore (legacy widget - to be replaced with quick input) private progressBar: ProgressBar; + // @ts-ignore (legacy widget - to be replaced with quick input) private visible: boolean; + // @ts-ignore (legacy widget - to be replaced with quick input) private isLoosingFocus: boolean; private callbacks: IQuickOpenCallbacks; private quickNavigateConfiguration: IQuickNavigateConfiguration | undefined; private container: HTMLElement; + // @ts-ignore (legacy widget - to be replaced with quick input) private treeElement: HTMLElement; + // @ts-ignore (legacy widget - to be replaced with quick input) private inputElement: HTMLElement; + // @ts-ignore (legacy widget - to be replaced with quick input) private layoutDimensions: DOM.Dimension; private model: IModel | null; private inputChangingTimeoutHandle: any; + // @ts-ignore (legacy widget - to be replaced with quick input) private styles: IQuickOpenStyles; + // @ts-ignore (legacy widget - to be replaced with quick input) private renderer: Renderer; constructor(container: HTMLElement, callbacks: IQuickOpenCallbacks, options: IQuickOpenOptions) { @@ -381,16 +396,16 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { protected applyStyles(): void { if (this.element) { const foreground = this.styles.foreground ? this.styles.foreground.toString() : null; - const background = this.styles.background ? this.styles.background.toString() : null; - const borderColor = this.styles.borderColor ? this.styles.borderColor.toString() : null; - const widgetShadow = this.styles.widgetShadow ? this.styles.widgetShadow.toString() : null; + const background = this.styles.background ? this.styles.background.toString() : ''; + const borderColor = this.styles.borderColor ? this.styles.borderColor.toString() : ''; + const widgetShadow = this.styles.widgetShadow ? this.styles.widgetShadow.toString() : ''; this.element.style.color = foreground; this.element.style.backgroundColor = background; this.element.style.borderColor = borderColor; - this.element.style.borderWidth = borderColor ? '1px' : null; - this.element.style.borderStyle = borderColor ? 'solid' : null; - this.element.style.boxShadow = widgetShadow ? `0 5px 8px ${widgetShadow}` : null; + this.element.style.borderWidth = borderColor ? '1px' : ''; + this.element.style.borderStyle = borderColor ? 'solid' : ''; + this.element.style.boxShadow = widgetShadow ? `0 5px 8px ${widgetShadow}` : ''; } if (this.progressBar) { diff --git a/src/vs/base/parts/quickopen/browser/quickopen.css b/src/vs/base/parts/quickopen/browser/quickopen.css index 97ddd6aab12..b6a9b9247d0 100644 --- a/src/vs/base/parts/quickopen/browser/quickopen.css +++ b/src/vs/base/parts/quickopen/browser/quickopen.css @@ -70,7 +70,8 @@ width: 16px; height: 16px; margin-right: 4px; - display: inline-block; + display: flex; + align-items: center; vertical-align: middle; flex-shrink: 0; } @@ -161,4 +162,4 @@ .monaco-quick-open-widget .quick-open-tree .monaco-highlighted-label .highlight { font-weight: bold; -} \ 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 index 85a3ef2d9ac..e73aafe6ad4 100644 --- a/src/vs/base/parts/storage/node/storage.ts +++ b/src/vs/base/parts/storage/node/storage.ts @@ -32,12 +32,12 @@ export interface ISQLiteStorageDatabaseLoggingOptions { export class SQLiteStorageDatabase implements IStorageDatabase { - static IN_MEMORY_PATH = ':memory:'; + static readonly 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 static readonly BUSY_OPEN_TIMEOUT = 2000; // timeout in ms to retry when opening DB fails with SQLITE_BUSY + private static readonly MAX_HOST_PARAMETERS = 256; // maximum number of parameters within a statement private path: string; private name: string; @@ -82,16 +82,18 @@ export class SQLiteStorageDatabase implements IStorageDatabase { } return this.transaction(connection, () => { + const toInsert = request.insert; + const toDelete = request.delete; // INSERT - if (request.insert && request.insert.size > 0) { + if (toInsert && toInsert.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) => { + toInsert.forEach((value, key) => { let keyValueChunk = keysValuesChunks[currentChunkIndex]; if (keyValueChunk.length > SQLiteStorageDatabase.MAX_HOST_PARAMETERS) { @@ -107,7 +109,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase { 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) => { + toInsert.forEach((value, key) => { keys.push(key); length += value.length; }); @@ -118,7 +120,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase { } // DELETE - if (request.delete && request.delete.size) { + if (toDelete && toDelete.size) { const keysChunks: (string[])[] = []; keysChunks.push([]); // seed with initial empty chunk @@ -126,7 +128,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase { // so that we can efficiently run the DELETE with as many HOST parameters // as possible let currentChunkIndex = 0; - request.delete.forEach(key => { + toDelete.forEach(key => { let keyChunk = keysChunks[currentChunkIndex]; if (keyChunk.length > SQLiteStorageDatabase.MAX_HOST_PARAMETERS) { @@ -141,7 +143,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase { 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 => { + toDelete.forEach(key => { keys.push(key); }); diff --git a/src/vs/base/parts/tree/browser/tree-collapsed-dark.svg b/src/vs/base/parts/tree/browser/tree-collapsed-dark.svg deleted file mode 100644 index c2c2298dd5c..00000000000 --- a/src/vs/base/parts/tree/browser/tree-collapsed-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/parts/tree/browser/tree-collapsed-hc.svg b/src/vs/base/parts/tree/browser/tree-collapsed-hc.svg deleted file mode 100644 index 3732cbc04b8..00000000000 --- a/src/vs/base/parts/tree/browser/tree-collapsed-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/parts/tree/browser/tree-collapsed-light.svg b/src/vs/base/parts/tree/browser/tree-collapsed-light.svg deleted file mode 100644 index 1952ad63f84..00000000000 --- a/src/vs/base/parts/tree/browser/tree-collapsed-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/parts/tree/browser/tree-expanded-dark.svg b/src/vs/base/parts/tree/browser/tree-expanded-dark.svg deleted file mode 100644 index d844b383ed3..00000000000 --- a/src/vs/base/parts/tree/browser/tree-expanded-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/parts/tree/browser/tree-expanded-hc.svg b/src/vs/base/parts/tree/browser/tree-expanded-hc.svg deleted file mode 100644 index 9faa2b2a6ed..00000000000 --- a/src/vs/base/parts/tree/browser/tree-expanded-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/parts/tree/browser/tree-expanded-light.svg b/src/vs/base/parts/tree/browser/tree-expanded-light.svg deleted file mode 100644 index f09125caf91..00000000000 --- a/src/vs/base/parts/tree/browser/tree-expanded-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/base/parts/tree/browser/tree.css b/src/vs/base/parts/tree/browser/tree.css index 6eb5f9b7aff..3e709334db6 100644 --- a/src/vs/base/parts/tree/browser/tree.css +++ b/src/vs/base/parts/tree/browser/tree.css @@ -6,12 +6,9 @@ height: 100%; width: 100%; white-space: nowrap; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: -moz-none; - -ms-user-select: none; - -o-user-select: none; user-select: none; + -webkit-user-select: none; + -ms-user-select: none; position: relative; } @@ -32,10 +29,7 @@ } .monaco-tree .monaco-tree-rows > .monaco-tree-row { - -moz-box-sizing: border-box; - -o-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; cursor: pointer; overflow: hidden; width: 100%; @@ -60,53 +54,8 @@ display: none; } -/* Expansion */ - -.monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before { - content: ' '; - position: absolute; - display: block; - background: url('tree-collapsed-light.svg') 50% 50% no-repeat; - width: 16px; - height: 100%; - top: 0; - left: -16px; -} - -.monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.expanded > .content:before { - background-image: url('tree-expanded-light.svg'); -} - -.monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before { - background-image: url('loading.svg'); -} - /* Highlighted */ .monaco-tree.highlighted .monaco-tree-rows > .monaco-tree-row:not(.highlighted) { opacity: 0.3; } - -.vs-dark .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before { - 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('tree-expanded-dark.svg'); -} - -.vs-dark .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before { - background-image: url('loading-dark.svg'); -} - -.hc-black .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before { - 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('tree-expanded-hc.svg'); -} - -.hc-black .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before { - background-image: url('loading-hc.svg'); -} diff --git a/src/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts index e24324e6d8c..64e5cfdb245 100644 --- a/src/vs/base/parts/tree/browser/treeView.ts +++ b/src/vs/base/parts/tree/browser/treeView.ts @@ -154,7 +154,7 @@ export class ViewItem implements IViewItem { } set loading(value: boolean) { - value ? this.addClass('loading') : this.removeClass('loading'); + value ? this.addClass('codicon-loading') : this.removeClass('codicon-loading'); } set draggable(value: boolean) { @@ -265,7 +265,7 @@ export class ViewItem implements IViewItem { } if (this.context.horizontalScrolling) { - this.element.style.width = 'fit-content'; + this.element.style.width = Browser.isFirefox ? '-moz-fit-content' : 'fit-content'; } try { @@ -289,7 +289,7 @@ export class ViewItem implements IViewItem { const style = window.getComputedStyle(this.element); const paddingLeft = parseFloat(style.paddingLeft!); - this.element.style.width = 'fit-content'; + this.element.style.width = Browser.isFirefox ? '-moz-fit-content' : 'fit-content'; this.width = DOM.getContentWidth(this.element) + paddingLeft; this.element.style.width = ''; } @@ -398,8 +398,8 @@ function reactionEquals(one: _.IDragOverReaction, other: _.IDragOverReaction | n export class TreeView extends HeightMap { - static BINDING = 'monaco-tree-row'; - static LOADING_DECORATION_DELAY = 800; + static readonly BINDING = 'monaco-tree-row'; + static readonly LOADING_DECORATION_DELAY = 800; private static counter: number = 0; private instance: number; @@ -437,6 +437,7 @@ export class TreeView extends HeightMap { private shouldInvalidateDropReaction: boolean; private currentDropTargets: ViewItem[] | null = null; private currentDropDisposable: Lifecycle.IDisposable = Lifecycle.Disposable.None; + private gestureDisposable: Lifecycle.IDisposable = Lifecycle.Disposable.None; private dragAndDropScrollInterval: number | null = null; private dragAndDropScrollTimeout: number | null = null; private dragAndDropMouseY: number | null = null; @@ -523,7 +524,7 @@ export class TreeView extends HeightMap { this.wrapper.style.msTouchAction = 'none'; this.wrapper.style.msContentZooming = 'none'; } else { - Touch.Gesture.addTarget(this.wrapper); + this.gestureDisposable = Touch.Gesture.addTarget(this.wrapper); } this.rowsContainer = document.createElement('div'); @@ -924,16 +925,15 @@ export class TreeView extends HeightMap { if (!skipDiff) { const lcs = new Diff.LcsDiff( { - getLength: () => previousChildrenIds.length, - getElementAtIndex: (i: number) => previousChildrenIds[i] - }, { - getLength: () => afterModelItems.length, - getElementAtIndex: (i: number) => afterModelItems[i].id - }, + getElements: () => previousChildrenIds + }, + { + getElements: () => afterModelItems.map(item => item.id) + }, null ); - diff = lcs.ComputeDiff(false); + diff = lcs.ComputeDiff(false).changes; // this means that the result of the diff algorithm would result // in inserting items that were already registered. this can only @@ -1675,6 +1675,7 @@ export class TreeView extends HeightMap { if (this.context.cache) { this.context.cache.dispose(); } + this.gestureDisposable.dispose(); super.dispose(); } diff --git a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts index e11b73ed9d8..d1914e5584f 100644 --- a/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts +++ b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts @@ -724,4 +724,35 @@ suite('IndexTreeModel', function () { model.refilter(); assert.deepEqual(toArray(list), ['platinum']); }); + + test('explicit hidden nodes should have renderNodeCount == 0, issue #83211', function () { + const list: ITreeNode[] = []; + let query = new RegExp(''); + const filter = new class implements ITreeFilter { + filter(element: string): boolean { + return query.test(element); + } + }; + + const model = new IndexTreeModel('test', toSpliceable(list), 'root', { filter }); + + model.splice([0], 0, [ + { element: 'a', children: [{ element: 'aa' }] }, + { element: 'b', children: [{ element: 'bb' }] } + ]); + + assert.deepEqual(toArray(list), ['a', 'aa', 'b', 'bb']); + assert.deepEqual(model.getListIndex([0]), 0); + assert.deepEqual(model.getListIndex([0, 0]), 1); + assert.deepEqual(model.getListIndex([1]), 2); + assert.deepEqual(model.getListIndex([1, 0]), 3); + + query = /b/; + model.refilter(); + assert.deepEqual(toArray(list), ['b', 'bb']); + assert.deepEqual(model.getListIndex([0]), -1); + assert.deepEqual(model.getListIndex([0, 0]), -1); + assert.deepEqual(model.getListIndex([1]), 0); + assert.deepEqual(model.getListIndex([1, 0]), 1); + }); }); diff --git a/src/vs/base/test/common/cancellation.test.ts b/src/vs/base/test/common/cancellation.test.ts index 536b2e21139..88d7d26e6fb 100644 --- a/src/vs/base/test/common/cancellation.test.ts +++ b/src/vs/base/test/common/cancellation.test.ts @@ -95,6 +95,20 @@ suite('CancellationToken', function () { assert.equal(count, 0); }); + test('dispose calls no listeners (unless told to cancel)', function () { + + let count = 0; + + let source = new CancellationTokenSource(); + source.token.onCancellationRequested(function () { + count += 1; + }); + + source.dispose(true); + // source.cancel(); + assert.equal(count, 1); + }); + test('parent cancels child', function () { let parent = new CancellationTokenSource(); diff --git a/src/vs/base/test/common/octicon.test.ts b/src/vs/base/test/common/codicon.test.ts similarity index 51% rename from src/vs/base/test/common/octicon.test.ts rename to src/vs/base/test/common/codicon.test.ts index c91055525d2..b3fdb5bde1b 100644 --- a/src/vs/base/test/common/octicon.test.ts +++ b/src/vs/base/test/common/codicon.test.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { IMatch } from 'vs/base/common/filters'; -import { matchesFuzzyOcticonAware, parseOcticons } from 'vs/base/common/octicon'; +import { matchesFuzzyCodiconAware, parseCodicons, IParsedCodicons } from 'vs/base/common/codicon'; -export interface IOcticonFilter { +export interface ICodiconFilter { // Returns null if word doesn't match. - (query: string, target: { text: string, octiconOffsets?: number[] }): IMatch[] | null; + (query: string, target: IParsedCodicons): IMatch[] | null; } -function filterOk(filter: IOcticonFilter, word: string, target: { text: string, octiconOffsets?: number[] }, highlights?: { start: number; end: number; }[]) { +function filterOk(filter: ICodiconFilter, word: string, target: IParsedCodicons, highlights?: { start: number; end: number; }[]) { let r = filter(word, target); assert(r); if (highlights) { @@ -19,24 +19,24 @@ function filterOk(filter: IOcticonFilter, word: string, target: { text: string, } } -suite('Octicon', () => { - test('matchesFuzzzyOcticonAware', () => { +suite('Codicon', () => { + test('matchesFuzzzyCodiconAware', () => { // Camel Case - filterOk(matchesFuzzyOcticonAware, 'ccr', parseOcticons('$(octicon)CamelCaseRocks$(octicon)'), [ + filterOk(matchesFuzzyCodiconAware, 'ccr', parseCodicons('$(codicon)CamelCaseRocks$(codicon)'), [ { start: 10, end: 11 }, { start: 15, end: 16 }, { start: 19, end: 20 } ]); - filterOk(matchesFuzzyOcticonAware, 'ccr', parseOcticons('$(octicon) CamelCaseRocks $(octicon)'), [ + filterOk(matchesFuzzyCodiconAware, 'ccr', parseCodicons('$(codicon) CamelCaseRocks $(codicon)'), [ { start: 11, end: 12 }, { start: 16, end: 17 }, { start: 20, end: 21 } ]); - filterOk(matchesFuzzyOcticonAware, 'iut', parseOcticons('$(octicon) Indent $(octico) Using $(octic) Tpaces'), [ + filterOk(matchesFuzzyCodiconAware, 'iut', parseCodicons('$(codicon) Indent $(octico) Using $(octic) Tpaces'), [ { start: 11, end: 12 }, { start: 28, end: 29 }, { start: 43, end: 44 }, @@ -44,22 +44,22 @@ suite('Octicon', () => { // Prefix - filterOk(matchesFuzzyOcticonAware, 'using', parseOcticons('$(octicon) Indent Using Spaces'), [ + filterOk(matchesFuzzyCodiconAware, 'using', parseCodicons('$(codicon) Indent Using Spaces'), [ { start: 18, end: 23 }, ]); - // Broken Octicon + // Broken Codicon - filterOk(matchesFuzzyOcticonAware, 'octicon', parseOcticons('This $(octicon Indent Using Spaces'), [ + filterOk(matchesFuzzyCodiconAware, 'codicon', parseCodicons('This $(codicon Indent Using Spaces'), [ { start: 7, end: 14 }, ]); - filterOk(matchesFuzzyOcticonAware, 'indent', parseOcticons('This $octicon Indent Using Spaces'), [ + filterOk(matchesFuzzyCodiconAware, 'indent', parseCodicons('This $codicon Indent Using Spaces'), [ { start: 14, end: 20 }, ]); // Testing #59343 - filterOk(matchesFuzzyOcticonAware, 'unt', parseOcticons('$(primitive-dot) $(file-text) Untitled-1'), [ + filterOk(matchesFuzzyCodiconAware, 'unt', parseCodicons('$(primitive-dot) $(file-text) Untitled-1'), [ { start: 30, end: 33 }, ]); }); diff --git a/src/vs/base/test/common/color.test.ts b/src/vs/base/test/common/color.test.ts index 865c158bab5..47d94c1dbf3 100644 --- a/src/vs/base/test/common/color.test.ts +++ b/src/vs/base/test/common/color.test.ts @@ -196,7 +196,6 @@ suite('Color', () => { test('parseHex', () => { // invalid - assert.deepEqual(Color.Format.CSS.parseHex(null!), null); assert.deepEqual(Color.Format.CSS.parseHex(''), null); assert.deepEqual(Color.Format.CSS.parseHex('#'), null); assert.deepEqual(Color.Format.CSS.parseHex('#0102030'), null); @@ -243,4 +242,4 @@ suite('Color', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/common/diff/diff.test.ts b/src/vs/base/test/common/diff/diff.test.ts index f80a6169f28..ca40c679297 100644 --- a/src/vs/base/test/common/diff/diff.test.ts +++ b/src/vs/base/test/common/diff/diff.test.ts @@ -4,21 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { LcsDiff, IDiffChange, ISequence } from 'vs/base/common/diff/diff'; - -class StringDiffSequence implements ISequence { - - constructor(private source: string) { - } - - getLength() { - return this.source.length; - } - - getElementAtIndex(i: number) { - return this.source.charCodeAt(i); - } -} +import { LcsDiff, IDiffChange, StringDiffSequence } from 'vs/base/common/diff/diff'; function createArray(length: number, value: T): T[] { const r: T[] = []; @@ -71,9 +57,9 @@ function assertAnswer(originalStr: string, modifiedStr: string, changes: IDiffCh } } -function lcsInnerTest(Algorithm: any, originalStr: string, modifiedStr: string, answerStr: string, onlyLength: boolean = false): void { - let diff = new Algorithm(new StringDiffSequence(originalStr), new StringDiffSequence(modifiedStr)); - let changes = diff.ComputeDiff(); +function lcsInnerTest(originalStr: string, modifiedStr: string, answerStr: string, onlyLength: boolean = false): void { + let diff = new LcsDiff(new StringDiffSequence(originalStr), new StringDiffSequence(modifiedStr)); + let changes = diff.ComputeDiff(false).changes; assertAnswer(originalStr, modifiedStr, changes, answerStr, onlyLength); } @@ -85,32 +71,28 @@ function stringPower(str: string, power: number): string { return r; } -function lcsTest(Algorithm: any, originalStr: string, modifiedStr: string, answerStr: string) { - lcsInnerTest(Algorithm, originalStr, modifiedStr, answerStr); +function lcsTest(originalStr: string, modifiedStr: string, answerStr: string) { + lcsInnerTest(originalStr, modifiedStr, answerStr); for (let i = 2; i <= 5; i++) { - lcsInnerTest(Algorithm, stringPower(originalStr, i), stringPower(modifiedStr, i), stringPower(answerStr, i), true); + lcsInnerTest(stringPower(originalStr, i), stringPower(modifiedStr, i), stringPower(answerStr, i), true); } } -function lcsTests(Algorithm: any) { - lcsTest(Algorithm, 'heLLo world', 'hello orlando', 'heo orld'); - lcsTest(Algorithm, 'abcde', 'acd', 'acd'); // simple - lcsTest(Algorithm, 'abcdbce', 'bcede', 'bcde'); // skip - lcsTest(Algorithm, 'abcdefgabcdefg', 'bcehafg', 'bceafg'); // long - lcsTest(Algorithm, 'abcde', 'fgh', ''); // no match - lcsTest(Algorithm, 'abcfabc', 'fabc', 'fabc'); - lcsTest(Algorithm, '0azby0', '9axbzby9', 'azby'); - lcsTest(Algorithm, '0abc00000', '9a1b2c399999', 'abc'); - - lcsTest(Algorithm, 'fooBar', 'myfooBar', 'fooBar'); // all insertions - lcsTest(Algorithm, 'fooBar', 'fooMyBar', 'fooBar'); // all insertions - lcsTest(Algorithm, 'fooBar', 'fooBar', 'fooBar'); // identical sequences -} - suite('Diff', () => { test('LcsDiff - different strings tests', function () { this.timeout(10000); - lcsTests(LcsDiff); + lcsTest('heLLo world', 'hello orlando', 'heo orld'); + lcsTest('abcde', 'acd', 'acd'); // simple + lcsTest('abcdbce', 'bcede', 'bcde'); // skip + lcsTest('abcdefgabcdefg', 'bcehafg', 'bceafg'); // long + lcsTest('abcde', 'fgh', ''); // no match + lcsTest('abcfabc', 'fabc', 'fabc'); + lcsTest('0azby0', '9axbzby9', 'azby'); + lcsTest('0abc00000', '9a1b2c399999', 'abc'); + + lcsTest('fooBar', 'myfooBar', 'fooBar'); // all insertions + lcsTest('fooBar', 'fooMyBar', 'fooBar'); // all insertions + lcsTest('fooBar', 'fooBar', 'fooBar'); // identical sequences }); }); @@ -123,18 +105,17 @@ suite('Diff - Ported from VS', () => { // doesn't get there first. let predicateCallCount = 0; - let diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) { + let diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) { assert.equal(predicateCallCount, 0); predicateCallCount++; - assert.equal(leftSequence.getLength(), left.length); assert.equal(leftIndex, 1); // cancel processing return false; }); - let changes = diff.ComputeDiff(true); + let changes = diff.ComputeDiff(true).changes; assert.equal(predicateCallCount, 1); @@ -144,26 +125,26 @@ suite('Diff - Ported from VS', () => { // Cancel after the first match ('c') - diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) { + diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) { assert(longestMatchSoFar <= 1); // We never see a match of length > 1 // Continue processing as long as there hasn't been a match made. return longestMatchSoFar < 1; }); - changes = diff.ComputeDiff(true); + changes = diff.ComputeDiff(true).changes; assertAnswer(left, right, changes, 'abcf'); // Cancel after the second match ('d') - diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) { + diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) { assert(longestMatchSoFar <= 2); // We never see a match of length > 2 // Continue processing as long as there hasn't been a match made. return longestMatchSoFar < 2; }); - changes = diff.ComputeDiff(true); + changes = diff.ComputeDiff(true).changes; assertAnswer(left, right, changes, 'abcdf'); @@ -171,7 +152,7 @@ suite('Diff - Ported from VS', () => { // Cancel *one iteration* after the second match ('d') let hitSecondMatch = false; - diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) { + diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) { assert(longestMatchSoFar <= 2); // We never see a match of length > 2 let hitYet = hitSecondMatch; @@ -179,20 +160,20 @@ suite('Diff - Ported from VS', () => { // Continue processing as long as there hasn't been a match made. return !hitYet; }); - changes = diff.ComputeDiff(true); + changes = diff.ComputeDiff(true).changes; assertAnswer(left, right, changes, 'abcdf'); // Cancel after the third and final match ('e') - diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, leftSequence, longestMatchSoFar) { + diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) { assert(longestMatchSoFar <= 3); // We never see a match of length > 3 // Continue processing as long as there hasn't been a match made. return longestMatchSoFar < 3; }); - changes = diff.ComputeDiff(true); + changes = diff.ComputeDiff(true).changes; assertAnswer(left, right, changes, 'abcdef'); }); diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index 09f3f6eec81..25d47dc6e00 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -350,6 +350,42 @@ suite('AsyncEmitter', function () { })); assert.ok(done); }); + + test('catch errors', async function () { + const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); + Errors.setUnexpectedErrorHandler(() => null); + + interface E extends IWaitUntil { + foo: boolean; + } + + let globalState = 0; + let emitter = new AsyncEmitter(); + + emitter.event(e => { + globalState += 1; + e.waitUntil(new Promise((_r, reject) => reject(new Error()))); + }); + + emitter.event(e => { + globalState += 1; + e.waitUntil(timeout(10)); + }); + + await emitter.fireAsync(thenables => ({ + foo: true, + waitUntil(t) { + thenables.push(t); + } + })).then(() => { + assert.equal(globalState, 2); + }).catch(e => { + console.log(e); + assert.ok(false); + }); + + Errors.setUnexpectedErrorHandler(origErrorHandler); + }); }); suite('PausableEmitter', function () { diff --git a/src/vs/base/test/common/lazy.test.ts b/src/vs/base/test/common/lazy.test.ts new file mode 100644 index 00000000000..c6a1655513f --- /dev/null +++ b/src/vs/base/test/common/lazy.test.ts @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Lazy } from 'vs/base/common/lazy'; + +suite('Lazy', () => { + + test('lazy values should only be resolved once', () => { + let counter = 0; + const value = new Lazy(() => ++counter); + + assert.strictEqual(value.hasValue(), false); + assert.strictEqual(value.getValue(), 1); + assert.strictEqual(value.hasValue(), true); + assert.strictEqual(value.getValue(), 1); // make sure we did not evaluate again + }); + + test('lazy values handle error case', () => { + let counter = 0; + const value = new Lazy(() => { throw new Error(`${++counter}`); }); + + assert.strictEqual(value.hasValue(), false); + assert.throws(() => value.getValue(), /\b1\b/); + assert.strictEqual(value.hasValue(), true); + assert.throws(() => value.getValue(), /\b1\b/); + }); + + test('map should not cause lazy values to be re-resolved', () => { + let outer = 0; + let inner = 10; + const outerLazy = new Lazy(() => ++outer); + const innerLazy = outerLazy.map(x => [x, ++inner]); + + assert.strictEqual(outerLazy.hasValue(), false); + assert.strictEqual(innerLazy.hasValue(), false); + + assert.deepEqual(innerLazy.getValue(), [1, 11]); + assert.strictEqual(outerLazy.hasValue(), true); + assert.strictEqual(innerLazy.hasValue(), true); + assert.strictEqual(outerLazy.getValue(), 1); + + // make sure we did not evaluate again + assert.strictEqual(outerLazy.getValue(), 1); + assert.deepEqual(innerLazy.getValue(), [1, 11]); + }); + + test('map should should handle error values', () => { + let outer = 0; + let inner = 10; + const outerLazy = new Lazy(() => { throw new Error(`${++outer}`); }); + const innerLazy = outerLazy.map(x => { throw new Error(`${++inner}`); }); + + assert.strictEqual(outerLazy.hasValue(), false); + assert.strictEqual(innerLazy.hasValue(), false); + + assert.throws(() => innerLazy.getValue(), /\b1\b/); // we should get result from outer + assert.strictEqual(outerLazy.hasValue(), true); + assert.strictEqual(innerLazy.hasValue(), true); + assert.throws(() => outerLazy.getValue(), /\b1\b/); + }); +}); diff --git a/src/vs/editor/browser/widget/media/tokens.css b/src/vs/base/test/common/markdownString.test.ts similarity index 55% rename from src/vs/editor/browser/widget/media/tokens.css rename to src/vs/base/test/common/markdownString.test.ts index 3b0784d077a..69d33de8f17 100644 --- a/src/vs/editor/browser/widget/media/tokens.css +++ b/src/vs/base/test/common/markdownString.test.ts @@ -3,7 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-editor .vs-whitespace { - display:inline-block; -} +import * as assert from 'assert'; +import { MarkdownString } from 'vs/base/common/htmlContent'; +suite('markdownString', () => { + + test('escape', () => { + + const mds = new MarkdownString(); + + mds.appendText('# foo\n*bar*'); + + assert.equal(mds.value, '\\# foo\n\n\\*bar\\*'); + }); +}); diff --git a/src/vs/base/test/common/resourceTree.test.ts b/src/vs/base/test/common/resourceTree.test.ts index d3050bcd990..2b2b7f68278 100644 --- a/src/vs/base/test/common/resourceTree.test.ts +++ b/src/vs/base/test/common/resourceTree.test.ts @@ -4,46 +4,70 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { ResourceTree, IBranchNode, ILeafNode } from 'vs/base/common/resourceTree'; +import { ResourceTree } from 'vs/base/common/resourceTree'; import { URI } from 'vs/base/common/uri'; suite('ResourceTree', function () { test('ctor', function () { const tree = new ResourceTree(null); - assert(ResourceTree.isBranchNode(tree.root)); - assert.equal(tree.root.size, 0); + assert.equal(tree.root.childrenCount, 0); }); test('simple', function () { const tree = new ResourceTree(null); tree.add(URI.file('/foo/bar.txt'), 'bar contents'); - assert(ResourceTree.isBranchNode(tree.root)); - assert.equal(tree.root.size, 1); + assert.equal(tree.root.childrenCount, 1); - let foo = tree.root.get('foo') as IBranchNode; + let foo = tree.root.get('foo')!; assert(foo); - assert(ResourceTree.isBranchNode(foo)); - assert.equal(foo.size, 1); + assert.equal(foo.childrenCount, 1); - let bar = foo.get('bar.txt') as ILeafNode; + let bar = foo.get('bar.txt')!; assert(bar); - assert(!ResourceTree.isBranchNode(bar)); assert.equal(bar.element, 'bar contents'); tree.add(URI.file('/hello.txt'), 'hello contents'); - assert.equal(tree.root.size, 2); + assert.equal(tree.root.childrenCount, 2); - let hello = tree.root.get('hello.txt') as ILeafNode; + let hello = tree.root.get('hello.txt')!; assert(hello); - assert(!ResourceTree.isBranchNode(hello)); assert.equal(hello.element, 'hello contents'); tree.delete(URI.file('/foo/bar.txt')); - assert.equal(tree.root.size, 1); - hello = tree.root.get('hello.txt') as ILeafNode; + assert.equal(tree.root.childrenCount, 1); + hello = tree.root.get('hello.txt')!; assert(hello); - assert(!ResourceTree.isBranchNode(hello)); assert.equal(hello.element, 'hello contents'); }); + + test('folders with data', function () { + const tree = new ResourceTree(null); + + assert.equal(tree.root.childrenCount, 0); + + tree.add(URI.file('/foo'), 'foo'); + assert.equal(tree.root.childrenCount, 1); + assert.equal(tree.root.get('foo')!.element, 'foo'); + + tree.add(URI.file('/bar'), 'bar'); + assert.equal(tree.root.childrenCount, 2); + assert.equal(tree.root.get('bar')!.element, 'bar'); + + tree.add(URI.file('/foo/file.txt'), 'file'); + assert.equal(tree.root.childrenCount, 2); + assert.equal(tree.root.get('foo')!.element, 'foo'); + assert.equal(tree.root.get('bar')!.element, 'bar'); + assert.equal(tree.root.get('foo')!.get('file.txt')!.element, 'file'); + + tree.delete(URI.file('/foo')); + assert.equal(tree.root.childrenCount, 1); + assert(!tree.root.get('foo')); + assert.equal(tree.root.get('bar')!.element, 'bar'); + + tree.delete(URI.file('/bar')); + assert.equal(tree.root.childrenCount, 0); + assert(!tree.root.get('foo')); + assert(!tree.root.get('bar')); + }); }); diff --git a/src/vs/base/test/common/resources.test.ts b/src/vs/base/test/common/resources.test.ts index cb535362222..5fdf1ba1088 100644 --- a/src/vs/base/test/common/resources.test.ts +++ b/src/vs/base/test/common/resources.test.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import { isWindows } from 'vs/base/common/platform'; import { toSlashes } from 'vs/base/common/extpath'; import { startsWith } from 'vs/base/common/strings'; -import { isAbsolute } from 'vs/base/common/path'; +import { win32, posix } from 'vs/base/common/path'; suite('Resources', () => { @@ -294,7 +294,8 @@ suite('Resources', () => { const actual = resolvePath(u1, path); assertEqualURI(actual, expected, `from ${u1.toString()} and ${path}`); - if (!isAbsolute(path)) { + const p = path.indexOf('/') !== -1 ? posix : win32; + if (!p.isAbsolute(path)) { let expectedPath = isWindows ? toSlashes(path) : path; expectedPath = startsWith(expectedPath, './') ? expectedPath.substr(2) : expectedPath; assert.equal(relativePath(u1, actual), expectedPath, `relativePath (${u1.toString()}) on actual (${actual.toString()}) should be to path (${expectedPath})`); @@ -335,6 +336,10 @@ suite('Resources', () => { assertResolve(URI.parse('foo://server/foo/bar'), 'file.js', URI.parse('foo://server/foo/bar/file.js')); assertResolve(URI.parse('foo://server/foo/bar'), './file.js', URI.parse('foo://server/foo/bar/file.js')); assertResolve(URI.parse('foo://server/foo/bar'), './file.js', URI.parse('foo://server/foo/bar/file.js')); + assertResolve(URI.parse('foo://server/foo/bar'), 'c:\\a1\\b1', URI.parse('foo://server/c:/a1/b1')); + assertResolve(URI.parse('foo://server/foo/bar'), 'c:\\', URI.parse('foo://server/c:')); + + }); test('isEqual', () => { diff --git a/src/vs/base/test/common/stream.test.ts b/src/vs/base/test/common/stream.test.ts new file mode 100644 index 00000000000..6d86fbc2eb2 --- /dev/null +++ b/src/vs/base/test/common/stream.test.ts @@ -0,0 +1,176 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { isReadableStream, newWriteableStream, Readable, consumeReadable, consumeReadableWithLimit, consumeStream, ReadableStream, toStream, toReadable, transform, consumeStreamWithLimit } from 'vs/base/common/stream'; + +suite('Stream', () => { + + test('isReadableStream', () => { + assert.ok(!isReadableStream(Object.create(null))); + assert.ok(isReadableStream(newWriteableStream(d => d))); + }); + + test('WriteableStream', () => { + const stream = newWriteableStream(strings => strings.join()); + + let error = false; + stream.on('error', e => { + error = true; + }); + + let end = false; + stream.on('end', () => { + end = true; + }); + + stream.write('Hello'); + + const chunks: string[] = []; + stream.on('data', data => { + chunks.push(data); + }); + + assert.equal(chunks[0], 'Hello'); + + stream.write('World'); + assert.equal(chunks[1], 'World'); + + assert.equal(error, false); + assert.equal(end, false); + + stream.pause(); + stream.write('1'); + stream.write('2'); + stream.write('3'); + + assert.equal(chunks.length, 2); + + stream.resume(); + + assert.equal(chunks.length, 3); + assert.equal(chunks[2], '1,2,3'); + + stream.error(new Error()); + assert.equal(error, true); + + stream.end('Final Bit'); + assert.equal(chunks.length, 4); + assert.equal(chunks[3], 'Final Bit'); + + stream.destroy(); + + stream.write('Unexpected'); + assert.equal(chunks.length, 4); + }); + + test('consumeReadable', () => { + const readable = arrayToReadable(['1', '2', '3', '4', '5']); + const consumed = consumeReadable(readable, strings => strings.join()); + assert.equal(consumed, '1,2,3,4,5'); + }); + + test('consumeReadableWithLimit', () => { + for (let i = 0; i < 5; i++) { + const readable = arrayToReadable(['1', '2', '3', '4', '5']); + + const consumedOrReadable = consumeReadableWithLimit(readable, strings => strings.join(), i); + if (typeof consumedOrReadable === 'string') { + assert.fail('Unexpected result'); + } else { + const consumed = consumeReadable(consumedOrReadable, strings => strings.join()); + assert.equal(consumed, '1,2,3,4,5'); + } + } + + let readable = arrayToReadable(['1', '2', '3', '4', '5']); + let consumedOrReadable = consumeReadableWithLimit(readable, strings => strings.join(), 5); + assert.equal(consumedOrReadable, '1,2,3,4,5'); + + readable = arrayToReadable(['1', '2', '3', '4', '5']); + consumedOrReadable = consumeReadableWithLimit(readable, strings => strings.join(), 6); + assert.equal(consumedOrReadable, '1,2,3,4,5'); + }); + + function arrayToReadable(array: T[]): Readable { + return { + read: () => array.shift() || null + }; + } + + function readableToStream(readable: Readable): ReadableStream { + const stream = newWriteableStream(strings => strings.join()); + + // Simulate async behavior + setTimeout(() => { + let chunk: string | null = null; + while ((chunk = readable.read()) !== null) { + stream.write(chunk); + } + + stream.end(); + }, 0); + + return stream; + } + + test('consumeStream', async () => { + const stream = readableToStream(arrayToReadable(['1', '2', '3', '4', '5'])); + const consumed = await consumeStream(stream, strings => strings.join()); + assert.equal(consumed, '1,2,3,4,5'); + }); + + test('consumeStreamWithLimit', async () => { + for (let i = 0; i < 5; i++) { + const readable = readableToStream(arrayToReadable(['1', '2', '3', '4', '5'])); + + const consumedOrStream = await consumeStreamWithLimit(readable, strings => strings.join(), i); + if (typeof consumedOrStream === 'string') { + assert.fail('Unexpected result'); + } else { + const consumed = await consumeStream(consumedOrStream, strings => strings.join()); + assert.equal(consumed, '1,2,3,4,5'); + } + } + + let stream = readableToStream(arrayToReadable(['1', '2', '3', '4', '5'])); + let consumedOrStream = await consumeStreamWithLimit(stream, strings => strings.join(), 5); + assert.equal(consumedOrStream, '1,2,3,4,5'); + + stream = readableToStream(arrayToReadable(['1', '2', '3', '4', '5'])); + consumedOrStream = await consumeStreamWithLimit(stream, strings => strings.join(), 6); + assert.equal(consumedOrStream, '1,2,3,4,5'); + }); + + test('toStream', async () => { + const stream = toStream('1,2,3,4,5', strings => strings.join()); + const consumed = await consumeStream(stream, strings => strings.join()); + assert.equal(consumed, '1,2,3,4,5'); + }); + + test('toReadable', async () => { + const readable = toReadable('1,2,3,4,5'); + const consumed = await consumeReadable(readable, strings => strings.join()); + assert.equal(consumed, '1,2,3,4,5'); + }); + + test('transform', async () => { + const source = newWriteableStream(strings => strings.join()); + + const result = transform(source, { data: string => string + string }, strings => strings.join()); + + // Simulate async behavior + setTimeout(() => { + source.write('1'); + source.write('2'); + source.write('3'); + source.write('4'); + source.end('5'); + }, 0); + + const consumed = await consumeStream(result, strings => strings.join()); + assert.equal(consumed, '11,22,33,44,55'); + }); +}); diff --git a/src/vs/base/test/common/strings.test.ts b/src/vs/base/test/common/strings.test.ts index 015075a90a9..ca5c6d3483e 100644 --- a/src/vs/base/test/common/strings.test.ts +++ b/src/vs/base/test/common/strings.test.ts @@ -458,4 +458,38 @@ suite('Strings', () => { assert.equal(strings.removeAccents('ñice'), 'nice'); assert.equal(strings.removeAccents('ńice'), 'nice'); }); + + test('encodeUTF8', function () { + function assertEncodeUTF8(str: string, expected: number[]): void { + const actual = strings.encodeUTF8(str); + const actualArr: number[] = []; + for (let offset = 0; offset < actual.byteLength; offset++) { + actualArr[offset] = actual[offset]; + } + assert.deepEqual(actualArr, expected); + } + + function assertDecodeUTF8(data: number[], expected: string): void { + const actual = strings.decodeUTF8(new Uint8Array(data)); + assert.deepEqual(actual, expected); + } + + function assertEncodeDecodeUTF8(str: string, buff: number[]): void { + assertEncodeUTF8(str, buff); + assertDecodeUTF8(buff, str); + } + + assertEncodeDecodeUTF8('\u0000', [0]); + assertEncodeDecodeUTF8('!', [33]); + assertEncodeDecodeUTF8('\u007F', [127]); + assertEncodeDecodeUTF8('\u0080', [194, 128]); + assertEncodeDecodeUTF8('Ɲ', [198, 157]); + assertEncodeDecodeUTF8('\u07FF', [223, 191]); + assertEncodeDecodeUTF8('\u0800', [224, 160, 128]); + assertEncodeDecodeUTF8('ஂ', [224, 174, 130]); + assertEncodeDecodeUTF8('\uffff', [239, 191, 191]); + assertEncodeDecodeUTF8('\u10000', [225, 128, 128, 48]); + assertEncodeDecodeUTF8('🧝', [240, 159, 167, 157]); + + }); }); diff --git a/src/vs/base/test/common/types.test.ts b/src/vs/base/test/common/types.test.ts index 43241b9a9c2..90e174dd000 100644 --- a/src/vs/base/test/common/types.test.ts +++ b/src/vs/base/test/common/types.test.ts @@ -169,6 +169,24 @@ suite('Types', () => { assert(types.isUndefinedOrNull(null)); }); + test('assertIsDefined / assertAreDefined', () => { + assert.throws(() => types.assertIsDefined(undefined)); + assert.throws(() => types.assertIsDefined(null)); + assert.throws(() => types.assertAllDefined(null, undefined)); + assert.throws(() => types.assertAllDefined(true, undefined)); + assert.throws(() => types.assertAllDefined(undefined, false)); + + assert.equal(types.assertIsDefined(true), true); + assert.equal(types.assertIsDefined(false), false); + assert.equal(types.assertIsDefined('Hello'), 'Hello'); + assert.equal(types.assertIsDefined(''), ''); + + const res = types.assertAllDefined(1, true, 'Hello'); + assert.equal(res[0], 1); + assert.equal(res[1], true); + assert.equal(res[2], 'Hello'); + }); + test('validateConstraints', () => { types.validateConstraints([1, 'test', true], [Number, String, Boolean]); types.validateConstraints([1, 'test', true], ['number', 'string', 'boolean']); diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index 0a72ec39876..3255575ae57 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -439,6 +439,37 @@ suite('URI', () => { assert.equal(uri.path, uri2.path); }); + + test('Links in markdown are broken if url contains encoded parameters #79474', function () { + this.skip(); + let strIn = 'https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom'; + let uri1 = URI.parse(strIn); + let strOut = uri1.toString(); + let uri2 = URI.parse(strOut); + + assert.equal(uri1.scheme, uri2.scheme); + assert.equal(uri1.authority, uri2.authority); + assert.equal(uri1.path, uri2.path); + assert.equal(uri1.query, uri2.query); + assert.equal(uri1.fragment, uri2.fragment); + assert.equal(strIn, strOut); // fails here!! + }); + + test('Uri#parse can break path-component #45515', function () { + this.skip(); + let strIn = 'https://firebasestorage.googleapis.com/v0/b/brewlangerie.appspot.com/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg?alt=media&token=0b2310c4-3ea6-4207-bbde-9c3710ba0437'; + let uri1 = URI.parse(strIn); + let strOut = uri1.toString(); + let uri2 = URI.parse(strOut); + + assert.equal(uri1.scheme, uri2.scheme); + assert.equal(uri1.authority, uri2.authority); + assert.equal(uri1.path, uri2.path); + assert.equal(uri1.query, uri2.query); + assert.equal(uri1.fragment, uri2.fragment); + assert.equal(strIn, strOut); // fails here!! + }); + test('URI - (de)serialize', function () { const values = [ diff --git a/src/vs/base/test/node/buffer.test.ts b/src/vs/base/test/node/buffer.test.ts index 65f84a66ddf..69dfb89e8a1 100644 --- a/src/vs/base/test/node/buffer.test.ts +++ b/src/vs/base/test/node/buffer.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { VSBuffer, bufferToReadable, readableToBuffer, bufferToStream, streamToBuffer, writeableBufferStream } from 'vs/base/common/buffer'; +import { VSBuffer, bufferToReadable, readableToBuffer, bufferToStream, streamToBuffer, newWriteableBufferStream } from 'vs/base/common/buffer'; import { timeout } from 'vs/base/common/async'; suite('Buffer', () => { @@ -30,7 +30,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - basics (no error)', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); let chunks: VSBuffer[] = []; stream.on('data', data => { @@ -60,7 +60,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - basics (error)', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); let chunks: VSBuffer[] = []; stream.on('data', data => { @@ -89,7 +89,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - buffers data when no listener', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); await timeout(0); stream.write(VSBuffer.fromString('Hello')); @@ -118,7 +118,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - buffers errors when no listener', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); await timeout(0); stream.write(VSBuffer.fromString('Hello')); @@ -149,7 +149,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - buffers end when no listener', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); await timeout(0); stream.write(VSBuffer.fromString('Hello')); @@ -178,7 +178,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - nothing happens after end()', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); let chunks: VSBuffer[] = []; stream.on('data', data => { @@ -222,7 +222,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - pause/resume (simple)', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); let chunks: VSBuffer[] = []; stream.on('data', data => { @@ -259,7 +259,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - pause/resume (pause after first write)', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); let chunks: VSBuffer[] = []; stream.on('data', data => { @@ -299,7 +299,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - pause/resume (error)', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); let chunks: VSBuffer[] = []; stream.on('data', data => { @@ -336,7 +336,7 @@ suite('Buffer', () => { }); test('bufferWriteableStream - destroy', async () => { - const stream = writeableBufferStream(); + const stream = newWriteableBufferStream(); let chunks: VSBuffer[] = []; stream.on('data', data => { diff --git a/src/vs/base/test/node/pfs/pfs.test.ts b/src/vs/base/test/node/pfs/pfs.test.ts index 4f09ad2b56d..aad4add0e72 100644 --- a/src/vs/base/test/node/pfs/pfs.test.ts +++ b/src/vs/base/test/node/pfs/pfs.test.ts @@ -12,10 +12,10 @@ import * as uuid from 'vs/base/common/uuid'; import * as pfs from 'vs/base/node/pfs'; import { timeout } from 'vs/base/common/async'; import { getPathFromAmdModule } from 'vs/base/common/amd'; -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'; @@ -252,7 +252,7 @@ suite('PFS', () => { } catch (error) { assert.fail(error); - return Promise.reject(error); + throw error; } }); @@ -305,23 +305,6 @@ suite('PFS', () => { return pfs.rimraf(parentDir, pfs.RimRafMode.MOVE); }); - test('mkdirp cancellation', async () => { - const id = uuid.generateUuid(); - const parentDir = path.join(os.tmpdir(), 'vsctests', id); - const newDir = path.join(parentDir, 'pfs', id); - - const source = new CancellationTokenSource(); - - const mkdirpPromise = pfs.mkdirp(newDir, 493, source.token); - source.cancel(); - - await mkdirpPromise; - - assert.ok(!fs.existsSync(newDir)); - - return pfs.rimraf(parentDir, pfs.RimRafMode.MOVE); - }); - test('readDirsInDir', async () => { const id = uuid.generateUuid(); const parentDir = path.join(os.tmpdir(), 'vsctests', id); @@ -386,6 +369,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'); @@ -499,7 +507,7 @@ suite('PFS', () => { } if (!expectedError || (expectedError).code !== 'EISDIR') { - return Promise.reject(new Error('Expected EISDIR error for writing to folder but got: ' + (expectedError ? (expectedError).code : 'no error'))); + throw new Error('Expected EISDIR error for writing to folder but got: ' + (expectedError ? (expectedError).code : 'no error')); } // verify that the stream is still consumable (for https://github.com/Microsoft/vscode/issues/42542) @@ -525,7 +533,7 @@ suite('PFS', () => { } if (!expectedError || expectedError.message !== readError) { - return Promise.reject(new Error('Expected error for writing to folder')); + throw new Error('Expected error for writing to folder'); } await pfs.rimraf(parentDir); @@ -556,7 +564,7 @@ suite('PFS', () => { } if (!expectedError || !((expectedError).code !== 'EACCES' || (expectedError).code !== 'EPERM')) { - return Promise.reject(new Error('Expected EACCES/EPERM error for writing to folder but got: ' + (expectedError ? (expectedError).code : 'no error'))); + throw new Error('Expected EACCES/EPERM error for writing to folder but got: ' + (expectedError ? (expectedError).code : 'no error')); } await pfs.rimraf(parentDir); @@ -583,7 +591,7 @@ suite('PFS', () => { } if (!expectedError) { - return Promise.reject(new Error('Expected error for writing to folder')); + throw new Error('Expected error for writing to folder'); } await pfs.rimraf(parentDir); diff --git a/src/vs/base/worker/defaultWorkerFactory.ts b/src/vs/base/worker/defaultWorkerFactory.ts index bce60b6b855..45f3b41a457 100644 --- a/src/vs/base/worker/defaultWorkerFactory.ts +++ b/src/vs/base/worker/defaultWorkerFactory.ts @@ -27,6 +27,7 @@ function getWorker(workerId: string, label: string): Worker | Promise { throw new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`); } +// ESM-comment-begin export function getWorkerBootstrapUrl(scriptPath: string, label: string): string { if (/^(http:)|(https:)|(file:)/.test(scriptPath)) { const currentUrl = String(window.location); @@ -43,6 +44,7 @@ export function getWorkerBootstrapUrl(scriptPath: string, label: string): string } return scriptPath + '#' + label; } +// ESM-comment-end function isPromiseLike(obj: any): obj is PromiseLike { if (typeof obj.then === 'function') { diff --git a/src/vs/code/browser/workbench/workbench-dev.html b/src/vs/code/browser/workbench/workbench-dev.html index 910666edf08..7ae960dbc91 100644 --- a/src/vs/code/browser/workbench/workbench-dev.html +++ b/src/vs/code/browser/workbench/workbench-dev.html @@ -7,25 +7,8 @@ - - - - + @@ -50,7 +33,6 @@ 'xterm-addon-search': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-search/lib/xterm-addon-search.js`, 'xterm-addon-web-links': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`, 'semver-umd': `${window.location.origin}/static/remote/web/node_modules/semver-umd/lib/semver-umd.js`, - '@microsoft/applicationinsights-web': `${window.location.origin}/static/remote/web/node_modules/@microsoft/applicationinsights-web/dist/applicationinsights-web.js`, } }; diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html index 97d78ce7f9e..dbcb8e490fe 100644 --- a/src/vs/code/browser/workbench/workbench.html +++ b/src/vs/code/browser/workbench/workbench.html @@ -7,25 +7,8 @@ - - - - + @@ -37,7 +20,6 @@ - @@ -55,7 +37,6 @@ 'xterm-addon-search': `${window.location.origin}/static/node_modules/xterm-addon-search/lib/xterm-addon-search.js`, 'xterm-addon-web-links': `${window.location.origin}/static/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`, 'semver-umd': `${window.location.origin}/static/node_modules/semver-umd/lib/semver-umd.js`, - '@microsoft/applicationinsights-web': `${window.location.origin}/static/node_modules/@microsoft/applicationinsights-web/dist/applicationinsights-web.js`, } }; diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 713e9e58ce2..ae0d5174b90 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -3,12 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkbenchConstructionOptions, create, URI, Event, Emitter, UriComponents, ICredentialsProvider, IURLCallbackProvider } from 'vs/workbench/workbench.web.api'; +import { IWorkbenchConstructionOptions, create, URI, Event, Emitter, UriComponents, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace } from 'vs/workbench/workbench.web.api'; import { generateUuid } from 'vs/base/common/uuid'; import { CancellationToken } from 'vs/base/common/cancellation'; import { streamToBuffer } from 'vs/base/common/buffer'; import { Disposable } from 'vs/base/common/lifecycle'; import { request } from 'vs/base/parts/request/browser/request'; +import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows'; +import { isEqual } from 'vs/base/common/resources'; +import { isStandalone } from 'vs/base/browser/browser'; interface ICredential { service: string; @@ -20,7 +23,7 @@ class LocalStorageCredentialsProvider implements ICredentialsProvider { static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider'; - private _credentials!: ICredential[]; + private _credentials: ICredential[] | undefined; private get credentials(): ICredential[] { if (!this._credentials) { try { @@ -101,10 +104,10 @@ class LocalStorageCredentialsProvider implements ICredentialsProvider { class PollingURLCallbackProvider extends Disposable implements IURLCallbackProvider { - static FETCH_INTERVAL = 500; // fetch every 500ms - static FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min + static readonly FETCH_INTERVAL = 500; // fetch every 500ms + static readonly FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min - static QUERY_KEYS = { + static readonly QUERY_KEYS = { REQUEST_ID: 'vscode-requestId', SCHEME: 'vscode-scheme', AUTHORITY: 'vscode-authority', @@ -197,22 +200,146 @@ class PollingURLCallbackProvider extends Disposable implements IURLCallbackProvi } } -const options: IWorkbenchConstructionOptions = JSON.parse(document.getElementById('vscode-workbench-web-configuration')!.getAttribute('data-settings')!); -options.urlCallbackProvider = new PollingURLCallbackProvider(); -options.credentialsProvider = new LocalStorageCredentialsProvider(); +class WorkspaceProvider implements IWorkspaceProvider { -if (options.folderUri) { - options.folderUri = URI.revive(options.folderUri); + static QUERY_PARAM_EMPTY_WINDOW = 'ew'; + static QUERY_PARAM_FOLDER = 'folder'; + static QUERY_PARAM_WORKSPACE = 'workspace'; + + static QUERY_PARAM_PAYLOAD = 'payload'; + + constructor( + public readonly workspace: IWorkspace, + public readonly payload: object + ) { } + + async open(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): Promise { + if (options?.reuse && !options.payload && this.isSame(this.workspace, workspace)) { + return; // return early if workspace and environment is not changing and we are reusing window + } + + const targetHref = this.createTargetUrl(workspace, options); + if (targetHref) { + if (options?.reuse) { + window.location.href = targetHref; + } else { + if (isStandalone) { + window.open(targetHref, '_blank', 'toolbar=no'); // ensures to open another 'standalone' window! + } else { + window.open(targetHref); + } + } + } + } + + private createTargetUrl(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): string | undefined { + + // Empty + let targetHref: string | undefined = undefined; + if (!workspace) { + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW}=true`; + } + + // Folder + else if (isFolderToOpen(workspace)) { + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${encodeURIComponent(workspace.folderUri.toString())}`; + } + + // Workspace + else if (isWorkspaceToOpen(workspace)) { + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${encodeURIComponent(workspace.workspaceUri.toString())}`; + } + + // Append payload if any + if (options?.payload) { + targetHref += `&${WorkspaceProvider.QUERY_PARAM_PAYLOAD}=${encodeURIComponent(JSON.stringify(options.payload))}`; + } + + return targetHref; + } + + private isSame(workspaceA: IWorkspace, workspaceB: IWorkspace): boolean { + if (!workspaceA || !workspaceB) { + return workspaceA === workspaceB; // both empty + } + + if (isFolderToOpen(workspaceA) && isFolderToOpen(workspaceB)) { + return isEqual(workspaceA.folderUri, workspaceB.folderUri); // same workspace + } + + if (isWorkspaceToOpen(workspaceA) && isWorkspaceToOpen(workspaceB)) { + return isEqual(workspaceA.workspaceUri, workspaceB.workspaceUri); // same workspace + } + + return false; + } } -if (options.workspaceUri) { - options.workspaceUri = URI.revive(options.workspaceUri); -} +(function () { -if (Array.isArray(options.staticExtensions)) { - options.staticExtensions.forEach(extension => { - extension.extensionLocation = URI.revive(extension.extensionLocation); + // Find config element in DOM + const configElement = document.getElementById('vscode-workbench-web-configuration'); + const configElementAttribute = configElement ? configElement.getAttribute('data-settings') : undefined; + if (!configElement || !configElementAttribute) { + throw new Error('Missing web configuration element'); + } + + // Find workspace to open and payload + let foundWorkspace = false; + let workspace: IWorkspace; + let payload = Object.create(null); + + const query = new URL(document.location.href).searchParams; + query.forEach((value, key) => { + switch (key) { + + // Folder + case WorkspaceProvider.QUERY_PARAM_FOLDER: + workspace = { folderUri: URI.parse(value) }; + foundWorkspace = true; + break; + + // Workspace + case WorkspaceProvider.QUERY_PARAM_WORKSPACE: + workspace = { workspaceUri: URI.parse(value) }; + foundWorkspace = true; + break; + + // Empty + case WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW: + workspace = undefined; + foundWorkspace = true; + break; + + // Payload + case WorkspaceProvider.QUERY_PARAM_PAYLOAD: + payload = JSON.parse(value); + break; + } }); -} -create(document.body, options); + // If no workspace is provided through the URL, check for config attribute from server + const options: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = JSON.parse(configElementAttribute); + if (!foundWorkspace) { + if (options.folderUri) { + workspace = { folderUri: URI.revive(options.folderUri) }; + } else if (options.workspaceUri) { + workspace = { workspaceUri: URI.revive(options.workspaceUri) }; + } else { + workspace = undefined; + } + } + + options.workspaceProvider = new WorkspaceProvider(workspace, payload); + options.urlCallbackProvider = new PollingURLCallbackProvider(); + options.credentialsProvider = new LocalStorageCredentialsProvider(); + + if (Array.isArray(options.staticExtensions)) { + options.staticExtensions.forEach(extension => { + extension.extensionLocation = URI.revive(extension.extensionLocation); + }); + } + + // Finally create workbench + create(document.body, options); +})(); diff --git a/src/vs/code/electron-browser/issue/issueReporterUtil.ts b/src/vs/code/common/issue/issueReporterUtil.ts similarity index 100% rename from src/vs/code/electron-browser/issue/issueReporterUtil.ts rename to src/vs/code/common/issue/issueReporterUtil.ts diff --git a/src/vs/code/electron-browser/issue/issueReporter.js b/src/vs/code/electron-browser/issue/issueReporter.js index 71c2b34a4e5..5d11dd15ae4 100644 --- a/src/vs/code/electron-browser/issue/issueReporter.js +++ b/src/vs/code/electron-browser/issue/issueReporter.js @@ -10,4 +10,4 @@ const bootstrapWindow = require('../../../../bootstrap-window'); bootstrapWindow.load(['vs/code/electron-browser/issue/issueReporterMain'], function (issueReporter, configuration) { issueReporter.startup(configuration); -}, { forceEnableDeveloperKeybindings: true }); \ No newline at end of file +}, { forceEnableDeveloperKeybindings: true, disallowReloadKeybinding: true }); diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index 0d270a52602..c553e51c8e0 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -16,6 +16,7 @@ import { debounce } from 'vs/base/common/decorators'; import * as platform from 'vs/base/common/platform'; import { Disposable } from 'vs/base/common/lifecycle'; import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; +import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; @@ -33,12 +34,12 @@ import { IssueReporterData, IssueReporterStyles, IssueType, ISettingsSearchIssue import BaseHtml from 'vs/code/electron-browser/issue/issueReporterPage'; import { LoggerChannelClient, 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 { CodiconLabel } from 'vs/base/browser/ui/codiconLabel/codiconLabel'; +import { normalizeGitHubUrl } from 'vs/code/common/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/diagnostics'; import { SpdLogService } from 'vs/platform/log/node/spdlogService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; const MAX_URL_LENGTH = 2045; @@ -230,7 +231,7 @@ export class IssueReporter extends Disposable { styleTag.innerHTML = content.join('\n'); document.head.appendChild(styleTag); - document.body.style.color = withUndefinedAsNull(styles.color); + document.body.style.color = styles.color || ''; } private handleExtensionData(extensions: IssueReporterExtensionData[]) { @@ -301,7 +302,9 @@ export class IssueReporter extends Disposable { const loggerClient = new LoggerChannelClient(mainProcessService.getChannel('logger')); this.logService = new FollowerLogService(loggerClient, logService); - const sharedProcess = mainProcessService.getChannel('sharedProcess').call('whenSharedProcessReady') + const sharedProcessService = createChannelSender(mainProcessService.getChannel('sharedProcess')); + + const sharedProcess = sharedProcessService.whenSharedProcessReady() .then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${configuration.windowId}`)); const instantiationService = new InstantiationService(serviceCollection, true); @@ -644,8 +647,8 @@ export class IssueReporter extends Disposable { issueState = $('span.issue-state'); const issueIcon = $('span.issue-icon'); - const octicon = new OcticonLabel(issueIcon); - octicon.text = issue.state === 'open' ? '$(issue-opened)' : '$(issue-closed)'; + const codicon = new CodiconLabel(issueIcon); + codicon.text = issue.state === 'open' ? '$(issue-opened)' : '$(issue-closed)'; const issueStateLabel = $('span.issue-state.label'); issueStateLabel.textContent = issue.state === 'open' ? localize('open', "Open") : localize('closed', "Closed"); diff --git a/src/vs/code/electron-browser/issue/media/issueReporter.css b/src/vs/code/electron-browser/issue/media/issueReporter.css index 6835e655b37..78e41309e48 100644 --- a/src/vs/code/electron-browser/issue/media/issueReporter.css +++ b/src/vs/code/electron-browser/issue/media/issueReporter.css @@ -352,7 +352,7 @@ a { text-overflow: ellipsis; } -.issues-container > .issue > .issue-state .octicon { +.issues-container > .issue > .issue-state .codicon { width: 16px; } diff --git a/src/vs/code/electron-browser/issue/test/testReporterModel.test.ts b/src/vs/code/electron-browser/issue/test/testReporterModel.test.ts index c6945463991..b34917961c0 100644 --- a/src/vs/code/electron-browser/issue/test/testReporterModel.test.ts +++ b/src/vs/code/electron-browser/issue/test/testReporterModel.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel'; -import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil'; +import { normalizeGitHubUrl } from 'vs/code/common/issue/issueReporterUtil'; import { IssueType } from 'vs/platform/issue/node/issue'; suite('IssueReporter', () => { diff --git a/src/vs/code/electron-browser/processExplorer/media/collapsed.svg b/src/vs/code/electron-browser/processExplorer/media/collapsed.svg old mode 100755 new mode 100644 diff --git a/src/vs/code/electron-browser/processExplorer/media/expanded.svg b/src/vs/code/electron-browser/processExplorer/media/expanded.svg old mode 100755 new mode 100644 diff --git a/src/vs/code/electron-browser/processExplorer/media/processExplorer.css b/src/vs/code/electron-browser/processExplorer/media/processExplorer.css index 4c59f4df167..69b0b9a35c9 100644 --- a/src/vs/code/electron-browser/processExplorer/media/processExplorer.css +++ b/src/vs/code/electron-browser/processExplorer/media/processExplorer.css @@ -29,8 +29,6 @@ body { padding: 0; height: 100%; width: 100%; - -webkit-touch-callout: none; - -webkit-user-select: none; user-select: none; color: #cccccc; } diff --git a/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts b/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts index 352cfe5b8a5..09ccca9b823 100644 --- a/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts +++ b/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts @@ -19,7 +19,6 @@ import { addDisposableListener } from 'vs/base/browser/dom'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; - let mapPidToWindowTitle = new Map(); const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/; @@ -374,9 +373,20 @@ function requestProcessList(totalWaitTime: number): void { }, 200); } +function createCloseListener(): void { + // Cmd/Ctrl + w closes process explorer + window.addEventListener('keydown', e => { + const cmdOrCtrlKey = platform.isMacintosh ? e.metaKey : e.ctrlKey; + if (cmdOrCtrlKey && e.keyCode === 87) { + ipcRenderer.send('vscode:closeProcessExplorer'); + } + }); +} + export function startup(data: ProcessExplorerData): void { applyStyles(data.styles); applyZoom(data.zoomLevel); + createCloseListener(); // Map window process pids to titles, annotate process names with this when rendering to distinguish between them ipcRenderer.on('vscode:windowsInfoResponse', (_event: unknown, windows: any[]) => { diff --git a/src/vs/code/electron-browser/proxy/auth.html b/src/vs/code/electron-browser/proxy/auth.html index a6b932662ae..d02876abb94 100644 --- a/src/vs/code/electron-browser/proxy/auth.html +++ b/src/vs/code/electron-browser/proxy/auth.html @@ -12,8 +12,6 @@ height: 100%; width: 100%; overflow: hidden; - -webkit-touch-callout: none; - -webkit-user-select: none; user-select: none; } @@ -117,4 +115,4 @@ - \ No newline at end of file + diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts index d3a0e9dab87..a3899b854fb 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts @@ -13,7 +13,7 @@ import { IBackupWorkspacesFormat } from 'vs/platform/backup/node/backup'; export class StorageDataCleaner extends Disposable { // Workspace/Folder storage names are MD5 hashes (128bits / 4 due to hex presentation) - private static NON_EMPTY_WORKSPACE_ID_LENGTH = 128 / 4; + private static readonly NON_EMPTY_WORKSPACE_ID_LENGTH = 128 / 4; constructor( @IEnvironmentService private readonly environmentService: IEnvironmentService diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js index b0b986e274a..2ecd5f650a8 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js @@ -14,6 +14,7 @@ bootstrap.avoidMonkeyPatchFromAppInsights(); bootstrapWindow.load(['vs/code/electron-browser/sharedProcess/sharedProcessMain'], function (sharedProcess, configuration) { sharedProcess.startup({ - machineId: configuration.machineId + machineId: configuration.machineId, + windowId: configuration.windowId }); -}); \ No newline at end of file +}); diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 5139ef1c850..9ddf3c0eca9 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -26,19 +26,17 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; -import { ActiveWindowManager } from 'vs/platform/windows/node/windows'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; +import { ActiveWindowManager } from 'vs/code/node/activeWindowTracker'; import { ipcRenderer } from 'electron'; -import { ILogService, LogLevel } from 'vs/platform/log/common/log'; +import { ILogService, LogLevel, ILoggerService } from 'vs/platform/log/common/log'; import { LoggerChannelClient, 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 { 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 { createChannelSender, createChannelReceiver } from 'vs/base/parts/ipc/node/ipc'; import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner'; import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner'; import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner'; @@ -52,14 +50,23 @@ 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/productService'; -import { IUserDataSyncService, IUserDataSyncStoreService, ISettingsMergeService, registerConfiguration } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, IUserDataSyncStoreService, ISettingsMergeService, registerConfiguration, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncService, UserDataAutoSync } from 'vs/platform/userDataSync/common/userDataSyncService'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { UserDataSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; import { SettingsMergeChannelClient } from 'vs/platform/userDataSync/common/settingsSyncIpc'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { LoggerService } from 'vs/platform/log/node/loggerService'; +import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; +import { IAuthTokenService } from 'vs/platform/auth/common/auth'; +import { AuthTokenService } from 'vs/platform/auth/common/authTokenService'; +import { AuthTokenChannel } from 'vs/platform/auth/common/authTokenIpc'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; +import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService'; export interface ISharedProcessConfiguration { readonly machineId: string; + readonly windowId: number; } export function startup(configuration: ISharedProcessConfiguration) { @@ -116,12 +123,16 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat services.set(ILogService, logService); services.set(IConfigurationService, configurationService); services.set(IRequestService, new SyncDescriptor(RequestService)); + services.set(ILoggerService, new SyncDescriptor(LoggerService)); const mainProcessService = new MainProcessService(server, mainRouter); services.set(IMainProcessService, mainProcessService); - const windowsService = new WindowsService(mainProcessService); - services.set(IWindowsService, windowsService); + const electronService = createChannelSender(mainProcessService.getChannel('electron'), { context: configuration.windowId }); + services.set(IElectronService, electronService); + + const activeWindowManager = new ActiveWindowManager(electronService); + const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); // Files const fileService = new FileService(logService); @@ -170,9 +181,9 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); - // User Data Sync Contributions - const activeWindowManager = new ActiveWindowManager(windowsService); - const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); + services.set(ICredentialsService, new SyncDescriptor(KeytarCredentialsService)); + services.set(IAuthTokenService, new SyncDescriptor(AuthTokenService)); + services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService)); const settingsMergeChannel = server.getChannel('settingsMerge', activeWindowRouter); services.set(ISettingsMergeService, new SettingsMergeChannelClient(settingsMergeChannel)); services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService)); @@ -188,13 +199,17 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat server.registerChannel('extensions', channel); const localizationsService = accessor.get(ILocalizationsService); - const localizationsChannel = new LocalizationsChannel(localizationsService); + const localizationsChannel = createChannelReceiver(localizationsService); server.registerChannel('localizations', localizationsChannel); const diagnosticsService = accessor.get(IDiagnosticsService); const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService); server.registerChannel('diagnostics', diagnosticsChannel); + const authTokenService = accessor.get(IAuthTokenService); + const authTokenChannel = new AuthTokenChannel(authTokenService); + server.registerChannel('authToken', authTokenChannel); + const userDataSyncService = accessor.get(IUserDataSyncService); const userDataSyncChannel = new UserDataSyncChannel(userDataSyncService); server.registerChannel('userDataSync', userDataSyncChannel); diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 2a2c6981c7d..022394edd75 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -33,17 +33,17 @@ bootstrapWindow.load([ return require('vs/workbench/electron-browser/desktop.main').main(configuration); }); }, { - removeDeveloperKeybindingsAfterLoad: true, - canModifyDOM: function (windowConfig) { - showPartsSplash(windowConfig); - }, - beforeLoaderConfig: function (windowConfig, loaderConfig) { - loaderConfig.recordStats = true; - }, - beforeRequire: function () { - perf.mark('willLoadWorkbenchMain'); - } - }); + removeDeveloperKeybindingsAfterLoad: true, + canModifyDOM: function (windowConfig) { + showPartsSplash(windowConfig); + }, + beforeLoaderConfig: function (windowConfig, loaderConfig) { + loaderConfig.recordStats = true; + }, + beforeRequire: function () { + perf.mark('willLoadWorkbenchMain'); + } +}); /** * @param {{ @@ -84,7 +84,7 @@ function showPartsSplash(configuration) { style.className = 'initialShellColors'; document.head.appendChild(style); document.body.className = baseTheme; - style.innerHTML = `body { background-color: ${shellBackground}; color: ${shellForeground}; }`; + style.innerHTML = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`; if (data && data.layoutInfo) { // restore parts if possible (we might not always store layout info) @@ -92,6 +92,18 @@ function showPartsSplash(configuration) { const splash = document.createElement('div'); splash.id = id; + if (layoutInfo.windowBorder) { + splash.style.position = 'relative'; + splash.style.height = 'calc(100vh - 2px)'; + splash.style.width = 'calc(100vw - 2px)'; + splash.style.border = '1px solid var(--window-border-color)'; + splash.style.setProperty('--window-border-color', colorInfo.windowBorder); + + if (layoutInfo.windowBorderRadius) { + splash.style.borderRadius = layoutInfo.windowBorderRadius; + } + } + // ensure there is enough space layoutInfo.sideBarWidth = Math.min(layoutInfo.sideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth)); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 9e88ccd42c7..e8afc9c7217 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -3,13 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, IpcMainEvent } from 'electron'; +import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, IpcMainEvent, BrowserWindow } from 'electron'; import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform'; -import { WindowsManager } from 'vs/code/electron-main/windows'; -import { IWindowsService, OpenContext, IWindowOpenable } from 'vs/platform/windows/common/windows'; -import { ActiveWindowManager } from 'vs/platform/windows/node/windows'; -import { WindowsChannel } from 'vs/platform/windows/common/windowsIpc'; -import { LegacyWindowsMainService } from 'vs/platform/windows/electron-main/legacyWindowsMainService'; +import { WindowsMainService } from 'vs/platform/windows/electron-main/windowsMainService'; +import { OpenContext, IWindowOpenable } from 'vs/platform/windows/common/windows'; +import { ActiveWindowManager } from 'vs/code/node/activeWindowTracker'; import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { getShellEnvironment } from 'vs/code/node/shellEnv'; import { IUpdateService } from 'vs/platform/update/common/update'; @@ -18,30 +16,30 @@ import { Server as ElectronIPCServer } from 'vs/base/parts/ipc/electron-main/ipc import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { Server, connect } from 'vs/base/parts/ipc/node/ipc.net'; import { SharedProcess } from 'vs/code/electron-main/sharedProcess'; -import { LaunchMainService, LaunchChannel, ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService'; +import { LaunchMainService, ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ILogService } from 'vs/platform/log/common/log'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IURLService } from 'vs/platform/url/common/url'; -import { URLHandlerChannelClient, URLServiceChannel, URLHandlerRouter } from 'vs/platform/url/common/urlIpc'; +import { IURLService, IOpenURLOptions } from 'vs/platform/url/common/url'; +import { URLHandlerChannelClient, URLHandlerRouter } from 'vs/platform/url/common/urlIpc'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; -import { SimpleServiceProxyChannel } from 'vs/platform/ipc/node/simpleIpcProxy'; +import { createChannelReceiver } from 'vs/base/parts/ipc/node/ipc'; import product from 'vs/platform/product/common/product'; import { ProxyAuthHandler } from 'vs/code/electron-main/auth'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { URI } from 'vs/base/common/uri'; -import { WorkspacesChannel } from 'vs/platform/workspaces/electron-main/workspacesIpc'; -import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; +import { hasWorkspaceFileExtension, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { WorkspacesService } from 'vs/platform/workspaces/electron-main/workspacesService'; import { getMachineId } from 'vs/base/node/id'; import { Win32UpdateService } from 'vs/platform/update/electron-main/updateService.win32'; import { LinuxUpdateService } from 'vs/platform/update/electron-main/updateService.linux'; @@ -66,7 +64,7 @@ import { GlobalStorageDatabaseChannel } from 'vs/platform/storage/node/storageIp import { startsWith } from 'vs/base/common/strings'; import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService'; import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; -import { HistoryMainService, IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; +import { WorkspacesHistoryMainService, IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; import { URLService } from 'vs/platform/url/node/urlService'; import { WorkspacesMainService, IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { statSync } from 'fs'; @@ -76,9 +74,12 @@ 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'; -import { IElectronService } from 'vs/platform/electron/node/electron'; -import { ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService'; +import { IElectronMainService, ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService'; import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService'; +import { assign } from 'vs/base/common/objects'; +import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; export class CodeApplication extends Disposable { @@ -86,6 +87,7 @@ export class CodeApplication extends Disposable { private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId'; private windowsMainService: IWindowsMainService | undefined; + private dialogMainService: IDialogMainService | undefined; constructor( private readonly mainIpcServer: Server, @@ -375,15 +377,14 @@ export class CodeApplication extends Disposable { // Create driver if (this.environmentService.driverHandle) { - const server = await serveDriver(electronIpcServer, this.environmentService.driverHandle!, this.environmentService, appInstantiationService); + const server = await serveDriver(electronIpcServer, this.environmentService.driverHandle, this.environmentService, appInstantiationService); this.logService.info('Driver started at:', this.environmentService.driverHandle); this._register(server); } // Setup Auth Handler - const authHandler = appInstantiationService.createInstance(ProxyAuthHandler); - this._register(authHandler); + this._register(new ProxyAuthHandler()); // Open Windows const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient)); @@ -449,16 +450,17 @@ export class CodeApplication extends Disposable { break; } - services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv])); + services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, this.userEnv])); + services.set(IDialogMainService, new SyncDescriptor(DialogMainService)); services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess])); - services.set(IWindowsService, new SyncDescriptor(LegacyWindowsMainService)); services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService)); const diagnosticsChannel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('diagnostics'))); services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, [diagnosticsChannel])); services.set(IIssueService, new SyncDescriptor(IssueMainService, [machineId, this.userEnv])); - services.set(IElectronService, new SyncDescriptor(ElectronMainService)); + services.set(IElectronMainService, new SyncDescriptor(ElectronMainService)); + services.set(IWorkspacesService, new SyncDescriptor(WorkspacesService)); services.set(IMenubarService, new SyncDescriptor(MenubarMainService)); const storageMainService = new StorageMainService(this.logService, this.environmentService); @@ -468,7 +470,7 @@ export class CodeApplication extends Disposable { const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService); services.set(IBackupMainService, backupMainService); - services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService)); + services.set(IWorkspacesHistoryMainService, new SyncDescriptor(WorkspacesHistoryMainService)); services.set(IURLService, new SyncDescriptor(URLService)); services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService)); @@ -504,13 +506,13 @@ export class CodeApplication extends Disposable { contentTracing.stopRecording(join(homedir(), `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`), path => { if (!timeout) { - if (this.windowsMainService) { - this.windowsMainService.showMessageBox({ + if (this.dialogMainService) { + this.dialogMainService.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()); + }, withNullAsUndefined(BrowserWindow.getFocusedWindow())); } } else { this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`); @@ -532,7 +534,7 @@ export class CodeApplication extends Disposable { // Register more Main IPC services const launchMainService = accessor.get(ILaunchMainService); - const launchChannel = new LaunchChannel(launchMainService); + const launchChannel = createChannelReceiver(launchMainService, { disableMarshalling: true }); this.mainIpcServer.registerChannel('launch', launchChannel); // Register more Electron IPC services @@ -541,32 +543,28 @@ export class CodeApplication extends Disposable { electronIpcServer.registerChannel('update', updateChannel); const issueService = accessor.get(IIssueService); - const issueChannel = new SimpleServiceProxyChannel(issueService); + const issueChannel = createChannelReceiver(issueService); electronIpcServer.registerChannel('issue', issueChannel); - const electronService = accessor.get(IElectronService); - const electronChannel = new SimpleServiceProxyChannel(electronService); + const electronMainService = accessor.get(IElectronMainService); + const electronChannel = createChannelReceiver(electronMainService); electronIpcServer.registerChannel('electron', electronChannel); + sharedProcessClient.then(client => client.registerChannel('electron', electronChannel)); const sharedProcessMainService = accessor.get(ISharedProcessMainService); - const sharedProcessChannel = new SimpleServiceProxyChannel(sharedProcessMainService); + const sharedProcessChannel = createChannelReceiver(sharedProcessMainService); electronIpcServer.registerChannel('sharedProcess', sharedProcessChannel); - const workspacesMainService = accessor.get(IWorkspacesMainService); - const workspacesChannel = new WorkspacesChannel(workspacesMainService, accessor.get(IWindowsMainService)); + const workspacesService = accessor.get(IWorkspacesService); + const workspacesChannel = createChannelReceiver(workspacesService); electronIpcServer.registerChannel('workspaces', workspacesChannel); - const windowsService = accessor.get(IWindowsService); - const windowsChannel = new WindowsChannel(windowsService); - electronIpcServer.registerChannel('windows', windowsChannel); - sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel)); - const menubarService = accessor.get(IMenubarService); - const menubarChannel = new SimpleServiceProxyChannel(menubarService); + const menubarChannel = createChannelReceiver(menubarService); electronIpcServer.registerChannel('menubar', menubarChannel); const urlService = accessor.get(IURLService); - const urlChannel = new URLServiceChannel(urlService); + const urlChannel = createChannelReceiver(urlService); electronIpcServer.registerChannel('url', urlChannel); const storageMainService = accessor.get(IStorageMainService); @@ -577,17 +575,40 @@ export class CodeApplication extends Disposable { electronIpcServer.registerChannel('logger', loggerChannel); sharedProcessClient.then(client => client.registerChannel('logger', loggerChannel)); + const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); + // ExtensionHost Debug broadcast service - electronIpcServer.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); + electronIpcServer.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ElectronExtensionHostDebugBroadcastChannel(windowsMainService)); // Signal phase: ready (services set) this.lifecycleMainService.phase = LifecycleMainPhase.Ready; // Propagate to clients - const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); + this.dialogMainService = accessor.get(IDialogMainService); + + // Create a URL handler to open file URIs in the active window + const environmentService = accessor.get(IEnvironmentService); + urlService.registerHandler({ + async handleURL(uri: URI, options?: IOpenURLOptions): Promise { + + // Catch file URLs + if (uri.authority === Schemas.file && !!uri.path) { + const cli = assign(Object.create(null), environmentService.args); + + // hey Ben, we need to convert this `code://file` URI into a `file://` URI + const urisToOpen = [{ fileUri: URI.file(uri.fsPath) }]; + + windowsMainService.open({ context: OpenContext.API, cli, urisToOpen, gotoLineMode: true }); + + return true; + } + + return false; + } + }); // Create a URL handler which forwards to the last active window - const activeWindowManager = new ActiveWindowManager(windowsService); + const activeWindowManager = new ActiveWindowManager(electronMainService); const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); const urlHandlerRouter = new URLHandlerRouter(activeWindowRouter); const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', urlHandlerRouter); @@ -596,10 +617,8 @@ export class CodeApplication extends Disposable { // On Mac, Code can be running without any open windows, so we must create a window to handle urls, // if there is none if (isMacintosh) { - const environmentService = accessor.get(IEnvironmentService); - urlService.registerHandler({ - async handleURL(uri: URI): Promise { + async handleURL(uri: URI, options?: IOpenURLOptions): Promise { if (windowsMainService.getWindowCount() === 0) { const cli = { ...environmentService.args }; const [window] = windowsMainService.open({ context: OpenContext.API, cli, forceEmpty: true, gotoLineMode: true }); @@ -646,7 +665,7 @@ export class CodeApplication extends Disposable { } // mac: open-file event received on startup - if (macOpenFiles && macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { + if (macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { return windowsMainService.open({ context: OpenContext.DOCK, cli: args, @@ -706,3 +725,28 @@ export class CodeApplication extends Disposable { }); } } + +class ElectronExtensionHostDebugBroadcastChannel extends ExtensionHostDebugBroadcastChannel { + + constructor(private windowsMainService: IWindowsMainService) { + super(); + } + + call(ctx: TContext, command: string, arg?: any): Promise { + if (command === 'openExtensionDevelopmentHostWindow') { + const env = arg[1]; + const pargs = parseArgs(arg[0], OPTIONS); + const extDevPaths = pargs.extensionDevelopmentPath; + if (extDevPaths) { + this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, { + context: OpenContext.API, + cli: pargs, + userEnv: Object.keys(env).length > 0 ? env : undefined + }); + } + return Promise.resolve(); + } else { + return super.call(ctx, command, arg); + } + } +} diff --git a/src/vs/code/electron-main/auth.ts b/src/vs/code/electron-main/auth.ts index 248a47c3033..45229b3bdd8 100644 --- a/src/vs/code/electron-main/auth.ts +++ b/src/vs/code/electron-main/auth.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; +import { Disposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { BrowserWindow, app, AuthInfo, WebContents, Event as ElectronEvent } from 'electron'; @@ -22,18 +21,21 @@ type Credentials = { password: string; }; -export class ProxyAuthHandler { +export class ProxyAuthHandler extends Disposable { _serviceBrand: undefined; private retryCount = 0; - private disposables: IDisposable[] = []; - constructor( - @IWindowsMainService private readonly windowsMainService: IWindowsMainService - ) { + constructor() { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { const onLogin = Event.fromNodeEventEmitter(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb })); - onLogin(this.onLogin, this, this.disposables); + this._register(onLogin(this.onLogin, this)); } private onLogin({ event, authInfo, cb }: LoginEvent): void { @@ -61,10 +63,9 @@ export class ProxyAuthHandler { } }; - const focusedWindow = this.windowsMainService.getFocusedWindow(); - + const focusedWindow = BrowserWindow.getFocusedWindow(); if (focusedWindow) { - opts.parent = focusedWindow.win; + opts.parent = focusedWindow; opts.modal = true; } @@ -89,8 +90,4 @@ export class ProxyAuthHandler { win.close(); }); } - - dispose(): void { - this.disposables = dispose(this.disposables); - } } diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index dc472d0ac60..bb05eddc6ce 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -6,22 +6,23 @@ import 'vs/platform/update/common/update.config.contribution'; import { app, dialog } from 'electron'; import { assign } from 'vs/base/common/objects'; -import * as platform from 'vs/base/common/platform'; +import { isWindows, IProcessEnvironment, isMacintosh } from 'vs/base/common/platform'; import product from 'vs/platform/product/common/product'; -import { parseMainProcessArgv } from 'vs/platform/environment/node/argvHelper'; -import { addArg, createWaitMarkerFile } from 'vs/platform/environment/node/argv'; +import { parseMainProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper'; +import { createWaitMarkerFile } from 'vs/platform/environment/node/waitMarkerFile'; import { mkdirp } from 'vs/base/node/pfs'; import { validatePaths } from 'vs/code/node/paths'; import { LifecycleMainService, ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { Server, serve, connect } from 'vs/base/parts/ipc/node/ipc.net'; -import { LaunchChannelClient } from 'vs/platform/launch/electron-main/launchMainService'; +import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; +import { ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ILogService, ConsoleLogMainService, MultiplexLogService, getLogLevel } from 'vs/platform/log/common/log'; import { StateService } from 'vs/platform/state/node/stateService'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { EnvironmentService, xdgRuntimeDir } from 'vs/platform/environment/node/environmentService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -131,7 +132,7 @@ class CodeMain { } } - private createServices(args: ParsedArgs, bufferLogService: BufferLogService): [IInstantiationService, typeof process.env] { + private createServices(args: ParsedArgs, bufferLogService: BufferLogService): [IInstantiationService, IProcessEnvironment] { const services = new ServiceCollection(); const environmentService = new EnvironmentService(args, process.execPath); @@ -173,16 +174,17 @@ class CodeMain { return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]); } - 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'] + private patchEnvironment(environmentService: IEnvironmentService): IProcessEnvironment { + const instanceEnvironment: IProcessEnvironment = { + VSCODE_IPC_HOOK: environmentService.mainIPCHandle }; - if (process.env['VSCODE_PORTABLE']) { - instanceEnvironment['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE']; - } + ['VSCODE_NLS_CONFIG', 'VSCODE_LOGS', 'VSCODE_PORTABLE'].forEach(key => { + const value = process.env[key]; + if (typeof value === 'string') { + instanceEnvironment[key] = value; + } + }); assign(process.env, instanceEnvironment); @@ -212,7 +214,7 @@ class CodeMain { } // Since we are the second instance, we do not want to show the dock - if (platform.isMacintosh) { + if (isMacintosh) { app.dock.hide(); } @@ -223,7 +225,7 @@ class CodeMain { } catch (error) { // Handle unexpected connection errors by showing a dialog to the user - if (!retry || platform.isWindows || error.code !== 'ECONNREFUSED') { + if (!retry || isWindows || error.code !== 'ECONNREFUSED') { if (error.code === 'EPERM') { this.showStartupWarningDialog( localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", product.nameShort), @@ -270,8 +272,7 @@ class CodeMain { }, 10000); } - const channel = client.getChannel('launch'); - const launchClient = new LaunchChannelClient(channel); + const launchService = createChannelSender(client.getChannel('launch'), { disableMarshalling: true }); // Process Info if (environmentService.args.status) { @@ -280,8 +281,8 @@ class CodeMain { 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 mainProcessInfo = await launchService.getMainProcessInfo(); + const remoteDiagnostics = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true }); const diagnostics = await diagnosticsService.getDiagnostics(mainProcessInfo, remoteDiagnostics); console.log(diagnostics); @@ -290,16 +291,16 @@ class CodeMain { } // Windows: allow to set foreground - if (platform.isWindows) { - await this.windowsAllowSetForegroundWindow(launchClient, logService); + if (isWindows) { + await this.windowsAllowSetForegroundWindow(launchService, logService); } // Send environment over... logService.trace('Sending env to running instance...'); - await launchClient.start(environmentService.args, process.env as platform.IProcessEnvironment); + await launchService.start(environmentService.args, process.env as IProcessEnvironment); // Cleanup - await client.dispose(); + client.dispose(); // Now that we started, make sure the warning dialog is prevented if (startupWarningDialogHandle) { @@ -317,7 +318,7 @@ class CodeMain { } // dock might be hidden at this case due to a retry - if (platform.isMacintosh) { + if (isMacintosh) { app.dock.show(); } @@ -358,9 +359,9 @@ class CodeMain { }); } - private async windowsAllowSetForegroundWindow(client: LaunchChannelClient, logService: ILogService): Promise { - if (platform.isWindows) { - const processId = await client.getMainProcessId(); + private async windowsAllowSetForegroundWindow(launchService: ILaunchMainService, logService: ILogService): Promise { + if (isWindows) { + const processId = await launchService.getMainProcessId(); logService.trace('Sending some foreground love to the running instance:', processId); diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts index 410db53245c..fc716c82be1 100644 --- a/src/vs/code/electron-main/sharedProcess.ts +++ b/src/vs/code/electron-main/sharedProcess.ts @@ -6,13 +6,14 @@ import { assign } from 'vs/base/common/objects'; import { memoize } from 'vs/base/common/decorators'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { BrowserWindow, ipcMain } from 'electron'; -import { ISharedProcess } from 'vs/platform/windows/electron-main/windows'; +import { BrowserWindow, ipcMain, WebContents, Event as ElectronEvent } from 'electron'; +import { ISharedProcess } from 'vs/platform/ipc/electron-main/sharedProcessMainService'; import { Barrier } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Event } from 'vs/base/common/event'; export class SharedProcess implements ISharedProcess { @@ -45,14 +46,15 @@ export class SharedProcess implements ISharedProcess { appRoot: this.environmentService.appRoot, machineId: this.machineId, nodeCachedDataDir: this.environmentService.nodeCachedDataDir, - userEnv: this.userEnv + userEnv: this.userEnv, + windowId: this.window.id }); const url = `${require.toUrl('vs/code/electron-browser/sharedProcess/sharedProcess.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; this.window.loadURL(url); // Prevent the window from dying - const onClose = (e: Event) => { + const onClose = (e: ElectronEvent) => { this.logService.trace('SharedProcess#close prevented'); // We never allow to close the shared process unless we get explicitly disposed() @@ -96,7 +98,8 @@ export class SharedProcess implements ISharedProcess { }); return new Promise(c => { - ipcMain.once('handshake:hello', ({ sender }: { sender: any }) => { + const onHello = Event.once(Event.fromNodeEventEmitter(ipcMain, 'handshake:hello', ({ sender }: { sender: WebContents }) => sender)); + disposables.add(onHello(sender => { sender.send('handshake:hey there', { sharedIPCHandle: this.environmentService.sharedIPCHandle, args: this.environmentService.args, @@ -105,7 +108,7 @@ export class SharedProcess implements ISharedProcess { disposables.add(toDisposable(() => sender.send('handshake:goodbye'))); ipcMain.once('handshake:im ready', () => c(undefined)); - }); + })); }); } diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 6a2f8b994c5..2abbdf31166 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -6,6 +6,7 @@ import * as path from 'vs/base/common/path'; import * as objects from 'vs/base/common/objects'; import * as nls from 'vs/nls'; +import { Event as CommonEvent, Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment } from 'electron'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; @@ -13,7 +14,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/product/common/product'; -import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, getTitleBarStyle } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, getTitleBarStyle, getMenuBarVisibility } 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'; @@ -27,6 +28,9 @@ import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainServ import { endsWith } from 'vs/base/common/strings'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IFileService } from 'vs/platform/files/common/files'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { mnemonicButtonLabel } from 'vs/base/common/labels'; const RUN_TEXTMATE_IN_WORKER = false; @@ -48,26 +52,37 @@ interface ITouchBarSegment extends SegmentedControlSegment { id: string; } +const enum WindowError { + UNRESPONSIVE = 1, + CRASHED = 2 +} + export class CodeWindow extends Disposable implements ICodeWindow { - private static readonly MIN_WIDTH = 200; - private static readonly MIN_HEIGHT = 120; + private static readonly MIN_WIDTH = 600; + private static readonly MIN_HEIGHT = 600; private static readonly MAX_URL_LENGTH = 2 * 1024 * 1024; // https://cs.chromium.org/chromium/src/url/url_constants.cc?l=32 - private hiddenTitleBarStyle: boolean; - private showTimeoutHandle: NodeJS.Timeout; - private _id: number; - private _win: BrowserWindow; + private readonly _onClose = this._register(new Emitter()); + readonly onClose: CommonEvent = this._onClose.event; + + private readonly _onDestroy = this._register(new Emitter()); + readonly onDestroy: CommonEvent = this._onDestroy.event; + + private readonly _onLoad = this._register(new Emitter()); + readonly onLoad: CommonEvent = this._onLoad.event; + + private hiddenTitleBarStyle: boolean | undefined; + private showTimeoutHandle: NodeJS.Timeout | undefined; private _lastFocusTime: number; private _readyState: ReadyState; private windowState: IWindowState; - private currentMenuBarVisibility: MenuBarVisibility; - private representedFilename: string; + private currentMenuBarVisibility: MenuBarVisibility | undefined; + private representedFilename: string | undefined; private readonly whenReadyCallbacks: { (window: ICodeWindow): void }[]; - private currentConfig: IWindowConfiguration; private pendingLoadConfig?: IWindowConfiguration; private marketplaceHeadersPromise: Promise; @@ -83,6 +98,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { @IThemeMainService private readonly themeMainService: IThemeMainService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, + @ITelemetryService private readonly telemetryService: ITelemetryService, + @IDialogMainService private readonly dialogMainService: IDialogMainService ) { super(); @@ -91,8 +108,111 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._readyState = ReadyState.NONE; this.whenReadyCallbacks = []; - // create browser window - this.createBrowserWindow(config); + //#region create browser window + { + // Load window 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); + + const options: BrowserWindowConstructorOptions = { + width: this.windowState.width, + height: this.windowState.height, + x: this.windowState.x, + y: this.windowState.y, + backgroundColor: this.themeMainService.getBackgroundColor(), + minWidth: CodeWindow.MIN_WIDTH, + minHeight: CodeWindow.MIN_HEIGHT, + show: !isFullscreenOrMaximized, + title: product.nameLong, + webPreferences: { + // By default if Code is in the background, intervals and timeouts get throttled, so we + // 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, + nodeIntegration: true, + nodeIntegrationInWorker: RUN_TEXTMATE_IN_WORKER, + webviewTag: true + } + }; + + if (isLinux) { + options.icon = path.join(this.environmentService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s) + } + + const windowConfig = this.configurationService.getValue('window'); + + if (isMacintosh && !this.useNativeFullScreen()) { + options.fullscreenable = false; // enables simple fullscreen mode + } + + if (isMacintosh) { + options.acceptFirstMouse = true; // enabled by default + + if (windowConfig?.clickThroughInactive === false) { + options.acceptFirstMouse = false; + } + } + + const useNativeTabs = isMacintosh && windowConfig?.nativeTabs === true; + if (useNativeTabs) { + options.tabbingIdentifier = product.nameShort; // this opts in to sierra tabs + } + + const useCustomTitleStyle = getTitleBarStyle(this.configurationService, this.environmentService, !!config.extensionDevelopmentPath) === 'custom'; + if (useCustomTitleStyle) { + options.titleBarStyle = 'hidden'; + this.hiddenTitleBarStyle = true; + if (!isMacintosh) { + options.frame = false; + } + } + + // Create the browser window. + this._win = new BrowserWindow(options); + this._id = this._win.id; + + if (isMacintosh && useCustomTitleStyle) { + 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')) { + const ensuredWindowState = this.windowState as Required; + this._win.setBounds({ + width: ensuredWindowState.width, + height: ensuredWindowState.height, + x: ensuredWindowState.x, + y: ensuredWindowState.y + }); + } + } + + if (isFullscreenOrMaximized) { + this._win.maximize(); + + if (this.windowState.mode === WindowMode.Fullscreen) { + this.setFullScreen(true); + } + + if (!this._win.isVisible()) { + this._win.show(); // to reduce flicker from the default window size to maximize, we only show after maximize + } + } + + this._lastFocusTime = Date.now(); // since we show directly, we need to set the last focus time too + } + //#endregion // respect configured menu bar visibility this.onConfigurationUpdated(); @@ -101,139 +221,26 @@ export class CodeWindow extends Disposable implements ICodeWindow { this.createTouchBar(); // Request handling - this.handleMarketplaceRequests(); + this.marketplaceHeadersPromise = resolveMarketplaceHeaders(product.version, this.environmentService, this.fileService); // Eventing this.registerListeners(); } - private createBrowserWindow(config: IWindowCreationOptions): void { + private currentConfig: IWindowConfiguration | undefined; + get config(): IWindowConfiguration | undefined { return this.currentConfig; } - // Load window state - const [state, hasMultipleDisplays] = this.restoreWindowState(config.state); - this.windowState = state; + private _id: number; + get id(): number { return this._id; } - // 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); + private _win: BrowserWindow; + get win(): BrowserWindow { return this._win; } - const options: BrowserWindowConstructorOptions = { - width: this.windowState.width, - height: this.windowState.height, - x: this.windowState.x, - y: this.windowState.y, - backgroundColor: this.themeMainService.getBackgroundColor(), - minWidth: CodeWindow.MIN_WIDTH, - minHeight: CodeWindow.MIN_HEIGHT, - show: !isFullscreenOrMaximized, - title: product.nameLong, - webPreferences: { - // By default if Code is in the background, intervals and timeouts get throttled, so we - // 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, - nodeIntegration: true, - nodeIntegrationInWorker: RUN_TEXTMATE_IN_WORKER, - webviewTag: true - } - }; + get hasHiddenTitleBarStyle(): boolean { return !!this.hiddenTitleBarStyle; } - if (isLinux) { - options.icon = path.join(this.environmentService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s) - } + get isExtensionDevelopmentHost(): boolean { return !!(this.config && this.config.extensionDevelopmentPath); } - const windowConfig = this.configurationService.getValue('window'); - - if (isMacintosh && !this.useNativeFullScreen()) { - options.fullscreenable = false; // enables simple fullscreen mode - } - - if (isMacintosh) { - options.acceptFirstMouse = true; // enabled by default - - if (windowConfig && windowConfig.clickThroughInactive === false) { - options.acceptFirstMouse = false; - } - } - - const useNativeTabs = isMacintosh && windowConfig && windowConfig.nativeTabs === true; - if (useNativeTabs) { - options.tabbingIdentifier = product.nameShort; // this opts in to sierra tabs - } - - const useCustomTitleStyle = getTitleBarStyle(this.configurationService, this.environmentService, !!config.extensionDevelopmentPath) === 'custom'; - if (useCustomTitleStyle) { - options.titleBarStyle = 'hidden'; - this.hiddenTitleBarStyle = true; - if (!isMacintosh) { - options.frame = false; - } - } - - // Create the browser window. - this._win = new BrowserWindow(options); - this._id = this._win.id; - - if (isMacintosh && useCustomTitleStyle) { - 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(); - - if (this.windowState.mode === WindowMode.Fullscreen) { - this.setFullScreen(true); - } - - if (!this._win.isVisible()) { - this._win.show(); // to reduce flicker from the default window size to maximize, we only show after maximize - } - } - - this._lastFocusTime = Date.now(); // since we show directly, we need to set the last focus time too - } - - hasHiddenTitleBarStyle(): boolean { - return this.hiddenTitleBarStyle; - } - - get isExtensionDevelopmentHost(): boolean { - return !!this.config.extensionDevelopmentPath; - } - - get isExtensionTestHost(): boolean { - return !!this.config.extensionTestsPath; - } - - get config(): IWindowConfiguration { - return this.currentConfig; - } - - get id(): number { - return this._id; - } - - get win(): BrowserWindow { - return this._win; - } + get isExtensionTestHost(): boolean { return !!(this.config && this.config.extensionTestsPath); } setRepresentedFilename(filename: string): void { if (isMacintosh) { @@ -243,7 +250,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } } - getRepresentedFilename(): string { + getRepresentedFilename(): string | undefined { if (isMacintosh) { return this.win.getRepresentedFilename(); } @@ -263,25 +270,15 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._win.focus(); } - get lastFocusTime(): number { - return this._lastFocusTime; - } + get lastFocusTime(): number { return this._lastFocusTime; } - get backupPath(): string | undefined { - return this.currentConfig ? this.currentConfig.backupPath : undefined; - } + get backupPath(): string | undefined { return this.currentConfig ? this.currentConfig.backupPath : undefined; } - get openedWorkspace(): IWorkspaceIdentifier | undefined { - return this.currentConfig ? this.currentConfig.workspace : undefined; - } + get openedWorkspace(): IWorkspaceIdentifier | undefined { return this.currentConfig ? this.currentConfig.workspace : undefined; } - get openedFolderUri(): URI | undefined { - return this.currentConfig ? this.currentConfig.folderUri : undefined; - } + get openedFolderUri(): URI | undefined { return this.currentConfig ? this.currentConfig.folderUri : undefined; } - get remoteAuthority(): string | undefined { - return this.currentConfig ? this.currentConfig.remoteAuthority : undefined; - } + get remoteAuthority(): string | undefined { return this.currentConfig ? this.currentConfig.remoteAuthority : undefined; } setReady(): void { this._readyState = ReadyState.READY; @@ -307,26 +304,34 @@ export class CodeWindow extends Disposable implements ICodeWindow { return this._readyState === ReadyState.READY; } - private handleMarketplaceRequests(): void { + get whenClosedOrLoaded(): Promise { + return new Promise(resolve => { - // Resolve marketplace headers - this.marketplaceHeadersPromise = resolveMarketplaceHeaders(product.version, this.environmentService, this.fileService); + function handle() { + closeListener.dispose(); + loadListener.dispose(); - // 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) as { [key: string]: string | undefined }; - if (!this.configurationService.getValue('extensions.disableExperimentalAzureSearch')) { - requestHeaders['Cookie'] = `${requestHeaders['Cookie'] ? requestHeaders['Cookie'] + ';' : ''}EnableExternalSearchForVSCode=true`; - } - cb({ cancel: false, requestHeaders }); - }); + resolve(); + } + + const closeListener = this.onClose(() => handle()); + const loadListener = this.onLoad(() => handle()); }); } private registerListeners(): void { + // Crashes & Unrsponsive + this._win.webContents.on('crashed', () => this.onWindowError(WindowError.CRASHED)); + this._win.on('unresponsive', () => this.onWindowError(WindowError.UNRESPONSIVE)); + + // Window close + this._win.on('closed', () => { + this._onClose.fire(); + + this.dispose(); + }); + // Prevent loading of svgs this._win.webContents.session.webRequest.onBeforeRequest(null!, (details, callback) => { if (details.url.indexOf('.svg') > 0) { @@ -376,7 +381,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { return; // disposed } - if (!this.useNativeFullScreen() && this.isFullScreen()) { + if (!this.useNativeFullScreen() && this.isFullScreen) { this.setFullScreen(false); this.setFullScreen(true); } @@ -430,13 +435,97 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Handle Workspace events this._register(this.workspacesMainService.onUntitledWorkspaceDeleted(e => this.onUntitledWorkspaceDeleted(e))); + + // 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) as { [key: string]: string | undefined }; + if (!this.configurationService.getValue('extensions.disableExperimentalAzureSearch')) { + requestHeaders['Cookie'] = `${requestHeaders['Cookie'] ? requestHeaders['Cookie'] + ';' : ''}EnableExternalSearchForVSCode=true`; + } + cb({ cancel: false, requestHeaders }); + }); + }); + } + + private onWindowError(error: WindowError): void { + this.logService.error(error === WindowError.CRASHED ? '[VS Code]: render process crashed!' : '[VS Code]: detected unresponsive'); + + 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 (this.isExtensionDevelopmentHost || this.isExtensionTestHost || (this._win && this._win.webContents && this._win.webContents.isDevToolsOpened())) { + // TODO@Ben Workaround for https://github.com/Microsoft/vscode/issues/56994 + // In certain cases the window can report unresponsiveness because a breakpoint was hit + // and the process is stopped executing. The most typical cases are: + // - devtools are opened and debugging happens + // - window is an extensions development host that is being debugged + // - window is an extension test development host that is being debugged + return; + } + + // Show Dialog + this.dialogMainService.showMessageBox({ + title: product.nameLong, + type: 'warning', + buttons: [mnemonicButtonLabel(nls.localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(nls.localize({ key: 'wait', comment: ['&& denotes a mnemonic'] }, "&&Keep Waiting")), mnemonicButtonLabel(nls.localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], + message: nls.localize('appStalled', "The window is no longer responding"), + detail: nls.localize('appStalledDetail', "You can reopen or close the window or keep waiting."), + noLink: true + }, this._win).then(result => { + if (!this._win) { + return; // Return early if the window has been going down already + } + + if (result.response === 0) { + this.reload(); + } else if (result.response === 2) { + this.destroyWindow(); + } + }); + } + + // Crashed + else { + this.dialogMainService.showMessageBox({ + title: product.nameLong, + type: 'warning', + buttons: [mnemonicButtonLabel(nls.localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(nls.localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], + message: nls.localize('appCrashed', "The window has crashed"), + detail: nls.localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."), + noLink: true + }, this._win).then(result => { + if (!this._win) { + return; // Return early if the window has been going down already + } + + if (result.response === 0) { + this.reload(); + } else if (result.response === 1) { + this.destroyWindow(); + } + }); + } + } + + private destroyWindow(): void { + this._onDestroy.fire(); // 'close' event will not be fired on destroy(), so signal crash via explicit event + this._win.destroy(); // make sure to destroy the window as it has crashed } private onUntitledWorkspaceDeleted(workspace: IWorkspaceIdentifier): void { // Make sure to update our workspace config if we detect that it // was deleted - if (this.openedWorkspace && this.openedWorkspace.id === workspace.id) { + if (this.openedWorkspace && this.openedWorkspace.id === workspace.id && this.currentConfig) { this.currentConfig.workspace = undefined; } } @@ -510,6 +599,9 @@ export class CodeWindow extends Disposable implements ICodeWindow { } }, 10000); } + + // Event + this._onLoad.fire(); } reload(configurationIn?: IWindowConfiguration, cli?: ParsedArgs): void { @@ -543,21 +635,22 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Set window ID windowConfiguration.windowId = this._win.id; + windowConfiguration.sessionId = `window:${this._win.id}`; windowConfiguration.logLevel = this.logService.getLevel(); // Set zoomlevel const windowConfig = this.configurationService.getValue('window'); - const zoomLevel = windowConfig && windowConfig.zoomLevel; + const zoomLevel = windowConfig?.zoomLevel; if (typeof zoomLevel === 'number') { windowConfiguration.zoomLevel = zoomLevel; } // Set fullscreen state - windowConfiguration.fullscreen = this.isFullScreen(); + windowConfiguration.fullscreen = this.isFullScreen; // Set Accessibility Config let autoDetectHighContrast = true; - if (windowConfig && windowConfig.autoDetectHighContrast === false) { + if (windowConfig?.autoDetectHighContrast === false) { autoDetectHighContrast = false; } windowConfiguration.highContrast = isWindows && autoDetectHighContrast && systemPreferences.isInvertedColorScheme(); @@ -565,7 +658,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Title style related windowConfiguration.maximized = this._win.isMaximized(); - windowConfiguration.frameless = this.hasHiddenTitleBarStyle() && !isMacintosh; // Dump Perf Counters windowConfiguration.perfEntries = perf.exportEntries(); @@ -611,7 +703,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } // fullscreen gets special treatment - if (this.isFullScreen()) { + if (this.isFullScreen) { const display = screen.getDisplayMatching(this.getBounds()); const defaultState = defaultWindowState(); @@ -733,7 +825,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Multi Montior (fullscreen): try to find the previously used display if (state.display && state.mode === WindowMode.Fullscreen) { const display = displays.filter(d => d.id === state.display)[0]; - if (display && display.bounds && typeof display.bounds.x === 'number' && typeof display.bounds.y === 'number') { + if (display && typeof display.bounds?.x === 'number' && typeof display.bounds?.y === 'number') { const defaults = defaultWindowState(WindowMode.Fullscreen); // make sure we have good values when the user restores the window defaults.x = display.bounds.x; // carefull to use displays x/y position so that the window ends up on the correct monitor defaults.y = display.bounds.y; @@ -786,7 +878,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } toggleFullScreen(): void { - this.setFullScreen(!this.isFullScreen()); + this.setFullScreen(!this.isFullScreen); } private setFullScreen(fullscreen: boolean): void { @@ -802,12 +894,12 @@ export class CodeWindow extends Disposable implements ICodeWindow { this.sendWhenReady(fullscreen ? 'vscode:enterFullScreen' : 'vscode:leaveFullScreen'); // Respect configured menu bar visibility or default to toggle if not set - this.setMenuBarVisibility(this.currentMenuBarVisibility, false); + if (this.currentMenuBarVisibility) { + this.setMenuBarVisibility(this.currentMenuBarVisibility, false); + } } - isFullScreen(): boolean { - return this._win.isFullScreen() || this._win.isSimpleFullScreen(); - } + get isFullScreen(): boolean { return this._win.isFullScreen() || this._win.isSimpleFullScreen(); } private setNativeFullScreen(fullscreen: boolean): void { if (this._win.isSimpleFullScreen()) { @@ -844,12 +936,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private getMenuBarVisibility(): MenuBarVisibility { - const windowConfig = this.configurationService.getValue('window'); - if (!windowConfig || !windowConfig.menuBarVisibility) { - return 'default'; - } - - let menuBarVisibility = windowConfig.menuBarVisibility; + let menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService, !!this.config?.extensionDevelopmentPath); if (['visible', 'toggle', 'hidden'].indexOf(menuBarVisibility) < 0) { menuBarVisibility = 'default'; } @@ -883,7 +970,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private doSetMenuBarVisibility(visibility: MenuBarVisibility): void { - const isFullscreen = this.isFullScreen(); + const isFullscreen = this.isFullScreen; switch (visibility) { case ('default'): diff --git a/src/vs/platform/windows/node/windows.ts b/src/vs/code/node/activeWindowTracker.ts similarity index 60% rename from src/vs/platform/windows/node/windows.ts rename to src/vs/code/node/activeWindowTracker.ts index b5e3f3f9c32..a7dbeb98bf2 100644 --- a/src/vs/platform/windows/node/windows.ts +++ b/src/vs/code/node/activeWindowTracker.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { IElectronService } from 'vs/platform/electron/node/electron'; export class ActiveWindowManager extends Disposable { @@ -14,21 +14,24 @@ export class ActiveWindowManager extends Disposable { private firstActiveWindowIdPromise: CancelablePromise | undefined; private activeWindowId: number | undefined; - private _activeWindowId: number | undefined; - constructor(@IWindowsService windowsService: IWindowsService) { + constructor(@IElectronService electronService: IElectronService) { super(); - // remember last active window id - Event.latch(Event.any(windowsService.onWindowOpen, windowsService.onWindowFocus))(id => this._activeWindowId = id, null, this.disposables); - - const onActiveWindowChange = Event.latch(Event.any(windowsService.onWindowOpen, windowsService.onWindowFocus)); + // remember last active window id upon events + const onActiveWindowChange = Event.latch(Event.any(electronService.onWindowOpen, electronService.onWindowFocus)); onActiveWindowChange(this.setActiveWindow, this, this.disposables); - this.firstActiveWindowIdPromise = createCancelablePromise(_ => this.getActiveWindowId()); - this.firstActiveWindowIdPromise - .then(id => this.activeWindowId = typeof this.activeWindowId === 'number' ? this.activeWindowId : id) - .finally(this.firstActiveWindowIdPromise = undefined); + // resolve current active window + this.firstActiveWindowIdPromise = createCancelablePromise(() => electronService.getActiveWindowId()); + (async () => { + try { + const windowId = await this.firstActiveWindowIdPromise; + this.activeWindowId = (typeof this.activeWindowId === 'number') ? this.activeWindowId : windowId; + } finally { + this.firstActiveWindowIdPromise = undefined; + } + })(); } private setActiveWindow(windowId: number | undefined) { @@ -45,8 +48,4 @@ export class ActiveWindowManager extends Disposable { return `window:${id}`; } - - private async getActiveWindowId(): Promise { - return this._activeWindowId; - } } diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 6dc1c356bac..5a6c573b36d 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -3,18 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as os from 'os'; +import * as fs from 'fs'; import { spawn, ChildProcess, SpawnOptions } from 'child_process'; -import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile, OPTIONS } from 'vs/platform/environment/node/argv'; -import { parseCLIProcessArgv } from 'vs/platform/environment/node/argvHelper'; +import { buildHelpMessage, buildVersionMessage, OPTIONS } from 'vs/platform/environment/node/argv'; +import { parseCLIProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper'; +import { createWaitMarkerFile } from 'vs/platform/environment/node/waitMarkerFile'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import product from 'vs/platform/product/common/product'; import * as paths from 'vs/base/common/path'; -import * as os from 'os'; -import * as fs from 'fs'; import { whenDeleted, writeFileSync } from 'vs/base/node/pfs'; import { findFreePort, randomPort } from 'vs/base/node/ports'; import { resolveTerminalEncoding } from 'vs/base/node/encoding'; -import * as iconv from 'iconv-lite'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { ProfilingSession, Target } from 'v8-inspect-profiler'; import { isString } from 'vs/base/common/types'; @@ -135,8 +135,8 @@ export async function main(argv: string[]): Promise { env['ELECTRON_ENABLE_LOGGING'] = '1'; processCallbacks.push(async child => { - child.stdout.on('data', (data: Buffer) => console.log(data.toString('utf8').trim())); - child.stderr.on('data', (data: Buffer) => console.log(data.toString('utf8').trim())); + child.stdout!.on('data', (data: Buffer) => console.log(data.toString('utf8').trim())); + child.stderr!.on('data', (data: Buffer) => console.log(data.toString('utf8').trim())); await new Promise(c => child.once('exit', () => c())); }); @@ -179,7 +179,8 @@ export async function main(argv: string[]): Promise { if (!stdinFileError) { // Pipe into tmp file using terminals encoding - resolveTerminalEncoding(verbose).then(encoding => { + resolveTerminalEncoding(verbose).then(async encoding => { + const iconv = await import('iconv-lite'); const converterStream = iconv.decodeStream(encoding); process.stdin.pipe(converterStream).pipe(stdinFileStream); }); diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 928b95a43b4..2ba0de50620 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -28,7 +28,7 @@ import { ConfigurationService } from 'vs/platform/configuration/node/configurati import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; import { mkdirp, writeFile } from 'vs/base/node/pfs'; import { getBaseLabel } from 'vs/base/common/labels'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { StateService } from 'vs/platform/state/node/stateService'; import { ILogService, getLogLevel } from 'vs/platform/log/common/log'; import { isPromiseCanceledError } from 'vs/base/common/errors'; diff --git a/src/vs/code/node/paths.ts b/src/vs/code/node/paths.ts index ce4e1b0227a..f605a4526f3 100644 --- a/src/vs/code/node/paths.ts +++ b/src/vs/code/node/paths.ts @@ -19,12 +19,11 @@ export function validatePaths(args: ParsedArgs): ParsedArgs { args._ = []; } - // Normalize paths and watch out for goto line mode - const paths = doValidatePaths(args._, args.goto); - - // Update environment - args._ = paths; - args.diff = args.diff && paths.length === 2; + if (!args['remote']) { + // Normalize paths and watch out for goto line mode + const paths = doValidatePaths(args._, args.goto); + args._ = paths; + } return args; } @@ -135,4 +134,4 @@ function toPath(p: IPathWithLineAndColumn): string { } return segments.join(':'); -} \ No newline at end of file +} diff --git a/src/vs/code/test/electron-main/windowsStateStorage.test.ts b/src/vs/code/test/electron-main/windowsStateStorage.test.ts index d87d855a36b..6094456c6f5 100644 --- a/src/vs/code/test/electron-main/windowsStateStorage.test.ts +++ b/src/vs/code/test/electron-main/windowsStateStorage.test.ts @@ -6,11 +6,11 @@ import * as assert from 'assert'; import * as os from 'os'; import * as path from 'vs/base/common/path'; -import { restoreWindowsState, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage'; +import { restoreWindowsState, getWindowsStateStoreData } from 'vs/platform/windows/electron-main/windowsStateStorage'; import { IWindowState as IWindowUIState, WindowMode } from 'vs/platform/windows/electron-main/windows'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; -import { IWindowsState, IWindowState } from 'vs/code/electron-main/windows'; +import { IWindowsState, IWindowState } from 'vs/platform/windows/electron-main/windowsMainService'; function getUIState(): IWindowUIState { return { @@ -288,4 +288,4 @@ suite('Windows State Storing', () => { }); -}); \ 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 59911ebc41e..79ce7d22445 100644 --- a/src/vs/code/test/node/argv.test.ts +++ b/src/vs/code/test/node/argv.test.ts @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { formatOptions, Option, addArg } from 'vs/platform/environment/node/argv'; +import { formatOptions, Option } from 'vs/platform/environment/node/argv'; +import { addArg } from 'vs/platform/environment/node/argvHelper'; suite('formatOptions', () => { diff --git a/src/vs/code/test/node/fixtures/no_vscode_folder/file.txt b/src/vs/code/test/node/fixtures/no_vscode_folder/file.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/vs/code/test/node/fixtures/vscode_folder/_vscode/settings.json b/src/vs/code/test/node/fixtures/vscode_folder/_vscode/settings.json deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/vs/code/test/node/fixtures/vscode_folder/file.txt b/src/vs/code/test/node/fixtures/vscode_folder/file.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/vs/code/test/node/fixtures/vscode_folder/nested_vscode_folder/_vscode/settings.json b/src/vs/code/test/node/fixtures/vscode_folder/nested_vscode_folder/_vscode/settings.json deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/vs/code/test/node/fixtures/vscode_home_folder/_vscode/settings.json b/src/vs/code/test/node/fixtures/vscode_home_folder/_vscode/settings.json deleted file mode 100644 index 9e26dfeeb6e..00000000000 --- a/src/vs/code/test/node/fixtures/vscode_home_folder/_vscode/settings.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/src/vs/code/test/node/fixtures/vscode_home_folder/file.txt b/src/vs/code/test/node/fixtures/vscode_home_folder/file.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/vs/editor/browser/config/charWidthReader.ts b/src/vs/editor/browser/config/charWidthReader.ts index 601a8ae8ad7..21a54663412 100644 --- a/src/vs/editor/browser/config/charWidthReader.ts +++ b/src/vs/editor/browser/config/charWidthReader.ts @@ -71,6 +71,7 @@ class DomCharWidthReader { regularDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily(); regularDomNode.style.fontWeight = this._bareFontInfo.fontWeight; regularDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px'; + regularDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings; regularDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px'; regularDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px'; container.appendChild(regularDomNode); @@ -79,6 +80,7 @@ class DomCharWidthReader { boldDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily(); boldDomNode.style.fontWeight = 'bold'; boldDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px'; + boldDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings; boldDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px'; boldDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px'; container.appendChild(boldDomNode); @@ -87,6 +89,7 @@ class DomCharWidthReader { italicDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily(); italicDomNode.style.fontWeight = this._bareFontInfo.fontWeight; italicDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px'; + italicDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings; italicDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px'; italicDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px'; italicDomNode.style.fontStyle = 'italic'; diff --git a/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts index 9078c4fe7cf..471c97e1162 100644 --- a/src/vs/editor/browser/config/configuration.ts +++ b/src/vs/editor/browser/config/configuration.ts @@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform'; import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader'; import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver'; import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, IEditorConstructionOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { IDimension } from 'vs/editor/common/editorCommon'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -79,6 +79,7 @@ export interface ISerializedFontInfo { readonly fontFamily: string; readonly fontWeight: string; readonly fontSize: number; + fontFeatureSettings: string; readonly lineHeight: number; readonly letterSpacing: number; readonly isMonospace: boolean; @@ -151,11 +152,14 @@ class CSSBasedConfiguration extends Disposable { return this._cache.getValues().filter(item => item.isTrusted); } - public restoreFontInfo(savedFontInfo: ISerializedFontInfo[]): void { + public restoreFontInfo(savedFontInfos: ISerializedFontInfo[]): void { // Take all the saved font info and insert them in the cache without the trusted flag. // The reason for this is that a font might have been installed on the OS in the meantime. - for (let i = 0, len = savedFontInfo.length; i < len; i++) { - const fontInfo = new FontInfo(savedFontInfo[i], false); + for (let i = 0, len = savedFontInfos.length; i < len; i++) { + const savedFontInfo = savedFontInfos[i]; + // compatibility with older versions of VS Code which did not store this... + savedFontInfo.fontFeatureSettings = savedFontInfo.fontFeatureSettings || EditorFontLigatures.OFF; + const fontInfo = new FontInfo(savedFontInfo, false); this._writeToCache(fontInfo, fontInfo); } } @@ -171,6 +175,7 @@ class CSSBasedConfiguration extends Disposable { fontFamily: readConfig.fontFamily, fontWeight: readConfig.fontWeight, fontSize: readConfig.fontSize, + fontFeatureSettings: readConfig.fontFeatureSettings, lineHeight: readConfig.lineHeight, letterSpacing: readConfig.letterSpacing, isMonospace: readConfig.isMonospace, @@ -249,9 +254,9 @@ class CSSBasedConfiguration extends Disposable { const maxDigitWidth = Math.max(digit0.width, digit1.width, digit2.width, digit3.width, digit4.width, digit5.width, digit6.width, digit7.width, digit8.width, digit9.width); - let isMonospace = true; + let isMonospace = (bareFontInfo.fontFeatureSettings === EditorFontLigatures.OFF); const referenceWidth = monospace[0].width; - for (let i = 1, len = monospace.length; i < len; i++) { + for (let i = 1, len = monospace.length; isMonospace && i < len; i++) { const diff = referenceWidth - monospace[i].width; if (diff < -0.001 || diff > 0.001) { isMonospace = false; @@ -276,6 +281,7 @@ class CSSBasedConfiguration extends Disposable { fontFamily: bareFontInfo.fontFamily, fontWeight: bareFontInfo.fontWeight, fontSize: bareFontInfo.fontSize, + fontFeatureSettings: bareFontInfo.fontFeatureSettings, lineHeight: bareFontInfo.lineHeight, letterSpacing: bareFontInfo.letterSpacing, isMonospace: isMonospace, @@ -294,6 +300,7 @@ export class Configuration extends CommonEditorConfiguration { domNode.style.fontFamily = fontInfo.getMassagedFontFamily(); domNode.style.fontWeight = fontInfo.fontWeight; domNode.style.fontSize = fontInfo.fontSize + 'px'; + domNode.style.fontFeatureSettings = fontInfo.fontFeatureSettings; domNode.style.lineHeight = fontInfo.lineHeight + 'px'; domNode.style.letterSpacing = fontInfo.letterSpacing + 'px'; } @@ -302,6 +309,7 @@ export class Configuration extends CommonEditorConfiguration { domNode.setFontFamily(fontInfo.getMassagedFontFamily()); domNode.setFontWeight(fontInfo.fontWeight); domNode.setFontSize(fontInfo.fontSize); + domNode.setFontFeatureSettings(fontInfo.fontFeatureSettings); domNode.setLineHeight(fontInfo.lineHeight); domNode.setLetterSpacing(fontInfo.letterSpacing); } @@ -310,13 +318,13 @@ export class Configuration extends CommonEditorConfiguration { constructor( isSimpleWidget: boolean, - options: IEditorOptions, + options: IEditorConstructionOptions, referenceDomElement: HTMLElement | null = null, private readonly accessibilityService: IAccessibilityService ) { super(isSimpleWidget, options); - this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, () => this._onReferenceDomElementSizeChanged())); + this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, options.dimension, () => this._onReferenceDomElementSizeChanged())); this._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._onCSSBasedConfigurationChanged())); diff --git a/src/vs/editor/browser/config/elementSizeObserver.ts b/src/vs/editor/browser/config/elementSizeObserver.ts index 325741e7293..16eea46d1f3 100644 --- a/src/vs/editor/browser/config/elementSizeObserver.ts +++ b/src/vs/editor/browser/config/elementSizeObserver.ts @@ -14,14 +14,14 @@ export class ElementSizeObserver extends Disposable { private width: number; private height: number; - constructor(referenceDomElement: HTMLElement | null, changeCallback: () => void) { + constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) { super(); this.referenceDomElement = referenceDomElement; this.changeCallback = changeCallback; this.measureReferenceDomElementToken = -1; this.width = -1; this.height = -1; - this.measureReferenceDomElement(false); + this.measureReferenceDomElement(false, dimension); } public dispose(): void { @@ -75,4 +75,4 @@ export class ElementSizeObserver extends Disposable { } } -} \ No newline at end of file +} diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index dd8979daabc..d1a19841028 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -17,13 +17,12 @@ import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/v import { EditorZoom } from 'vs/editor/common/config/editorZoom'; import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; -import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; +import { HorizontalPosition } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; - /** * Merges mouse events when mouse move events are throttled */ @@ -59,13 +58,13 @@ export interface IPointerHandlerHelper { */ getPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null; - visibleRangeForPosition2(lineNumber: number, column: number): HorizontalRange | null; + visibleRangeForPosition(lineNumber: number, column: number): HorizontalPosition | null; getLineWidth(lineNumber: number): number; } export class MouseHandler extends ViewEventHandler { - static MOUSE_MOVE_MINIMUM_TIME = 100; // ms + static readonly MOUSE_MOVE_MINIMUM_TIME = 100; // ms protected _context: ViewContext; protected viewController: ViewController; diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index c025c958a0f..1f737774248 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -13,7 +13,7 @@ import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/v import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range as EditorRange } from 'vs/editor/common/core/range'; -import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; +import { HorizontalPosition } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; @@ -346,8 +346,8 @@ export class HitTestContext { return this._viewHelper.getLineWidth(lineNumber); } - public visibleRangeForPosition2(lineNumber: number, column: number): HorizontalRange | null { - return this._viewHelper.visibleRangeForPosition2(lineNumber, column); + public visibleRangeForPosition(lineNumber: number, column: number): HorizontalPosition | null { + return this._viewHelper.visibleRangeForPosition(lineNumber, column); } public getPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null { @@ -743,7 +743,7 @@ export class MouseTargetFactory { return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, undefined, detail); } - const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column); + const visibleRange = ctx.visibleRangeForPosition(lineNumber, column); if (!visibleRange) { return request.fulfill(MouseTargetType.UNKNOWN, pos); @@ -761,14 +761,14 @@ export class MouseTargetFactory { const points: OffsetColumn[] = []; points.push({ offset: visibleRange.left, column: column }); if (column > 1) { - const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column - 1); + const visibleRange = ctx.visibleRangeForPosition(lineNumber, column - 1); if (visibleRange) { points.push({ offset: visibleRange.left, column: column - 1 }); } } const lineMaxColumn = ctx.model.getLineMaxColumn(lineNumber); if (column < lineMaxColumn) { - const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column + 1); + const visibleRange = ctx.visibleRangeForPosition(lineNumber, column + 1); if (visibleRange) { points.push({ offset: visibleRange.left, column: column + 1 }); } @@ -972,7 +972,7 @@ export class MouseTargetFactory { // Thank you browsers for making this so 'easy' :) - if (document.caretRangeFromPoint) { + if (typeof document.caretRangeFromPoint === 'function') { return this._doHitTestWithCaretRangeFromPoint(ctx, request); diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index e4a4a03146f..51988d09968 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -190,7 +190,7 @@ class TouchHandler extends MouseHandler { constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) { super(context, viewController, viewHelper); - Gesture.addTarget(this.viewHelper.linesContentDomNode); + this._register(Gesture.addTarget(this.viewHelper.linesContentDomNode)); 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))); diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 57f3ec804be..ec222be4354 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -11,7 +11,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import * as platform from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; import { Configuration } from 'vs/editor/browser/config/configuration'; -import { CopyOptions, ICompositionData, IPasteData, ITextAreaInputHost, TextAreaInput } from 'vs/editor/browser/controller/textAreaInput'; +import { CopyOptions, ICompositionData, IPasteData, ITextAreaInputHost, TextAreaInput, ClipboardDataToCopy } from 'vs/editor/browser/controller/textAreaInput'; import { ISimpleModel, ITypeData, PagedScreenReaderStrategy, TextAreaState } from 'vs/editor/browser/controller/textAreaState'; import { ViewController } from 'vs/editor/browser/view/viewController'; import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart'; @@ -25,13 +25,13 @@ import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { ScrollType } from 'vs/editor/common/editorCommon'; import { EndOfLinePreference } from 'vs/editor/common/model'; -import { HorizontalRange, RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; +import { RenderingContext, RestrictedRenderingContext, HorizontalPosition } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; export interface ITextAreaHandlerHelper { - visibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalRange | null; + visibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalPosition | null; } class VisibleTextAreaData { @@ -54,40 +54,6 @@ class VisibleTextAreaData { const canUseZeroSizeTextarea = (browser.isEdgeOrIE || browser.isFirefox); -interface LocalClipboardMetadata { - lastCopiedValue: string; - isFromEmptySelection: boolean; - multicursorText: string[] | null; -} - -/** - * Every time we write to the clipboard, we record a bit of extra metadata here. - * Every time we read from the cipboard, if the text matches our last written text, - * we can fetch the previous metadata. - */ -class LocalClipboardMetadataManager { - public static INSTANCE = new LocalClipboardMetadataManager(); - - private _lastState: LocalClipboardMetadata | null; - - constructor() { - this._lastState = null; - } - - public set(state: LocalClipboardMetadata | null): void { - this._lastState = state; - } - - public get(pastedText: string): LocalClipboardMetadata | null { - if (this._lastState && this._lastState.lastCopiedValue === pastedText) { - // match! - return this._lastState; - } - this._lastState = null; - return null; - } -} - export class TextAreaHandler extends ViewPart { private readonly _viewController: ViewController; @@ -152,6 +118,10 @@ export class TextAreaHandler extends ViewPart { this.textArea.setAttribute('aria-haspopup', 'false'); this.textArea.setAttribute('aria-autocomplete', 'both'); + if (platform.isWeb && options.get(EditorOption.readOnly)) { + this.textArea.setAttribute('readonly', 'true'); + } + this.textAreaCover = createFastDomNode(document.createElement('div')); this.textAreaCover.setPosition('absolute'); @@ -168,39 +138,26 @@ export class TextAreaHandler extends ViewPart { }; const textAreaInputHost: ITextAreaInputHost = { - getPlainTextToCopy: (): string => { - const rawWhatToCopy = this._context.model.getPlainTextToCopy(this._selections, this._emptySelectionClipboard, platform.isWindows); + getDataToCopy: (generateHTML: boolean): ClipboardDataToCopy => { + const rawTextToCopy = this._context.model.getPlainTextToCopy(this._selections, this._emptySelectionClipboard, platform.isWindows); const newLineCharacter = this._context.model.getEOL(); const isFromEmptySelection = (this._emptySelectionClipboard && this._selections.length === 1 && this._selections[0].isEmpty()); - const multicursorText = (Array.isArray(rawWhatToCopy) ? rawWhatToCopy : null); - const whatToCopy = (Array.isArray(rawWhatToCopy) ? rawWhatToCopy.join(newLineCharacter) : rawWhatToCopy); + const multicursorText = (Array.isArray(rawTextToCopy) ? rawTextToCopy : null); + const text = (Array.isArray(rawTextToCopy) ? rawTextToCopy.join(newLineCharacter) : rawTextToCopy); - let metadata: LocalClipboardMetadata | null = null; - if (isFromEmptySelection || multicursorText) { - // Only store the non-default metadata - - // When writing "LINE\r\n" to the clipboard and then pasting, - // Firefox pastes "LINE\n", so let's work around this quirk - const lastCopiedValue = (browser.isFirefox ? whatToCopy.replace(/\r\n/g, '\n') : whatToCopy); - metadata = { - lastCopiedValue: lastCopiedValue, - isFromEmptySelection: (this._emptySelectionClipboard && this._selections.length === 1 && this._selections[0].isEmpty()), - multicursorText: multicursorText - }; + let html: string | null | undefined = undefined; + if (generateHTML) { + if (CopyOptions.forceCopyWithSyntaxHighlighting || (this._copyWithSyntaxHighlighting && text.length < 65536)) { + html = this._context.model.getHTMLToCopy(this._selections, this._emptySelectionClipboard); + } } - - LocalClipboardMetadataManager.INSTANCE.set(metadata); - - return whatToCopy; - }, - - getHTMLToCopy: (): string | null => { - if (!this._copyWithSyntaxHighlighting && !CopyOptions.forceCopyWithSyntaxHighlighting) { - return null; - } - - return this._context.model.getHTMLToCopy(this._selections, this._emptySelectionClipboard); + return { + isFromEmptySelection, + multicursorText, + text, + html + }; }, getScreenReaderContent: (currentState: TextAreaState): TextAreaState => { @@ -251,13 +208,11 @@ export class TextAreaHandler extends ViewPart { })); this._register(this._textAreaInput.onPaste((e: IPasteData) => { - const metadata = LocalClipboardMetadataManager.INSTANCE.get(e.text); - let pasteOnNewLine = false; let multicursorText: string[] | null = null; - if (metadata) { - pasteOnNewLine = (this._emptySelectionClipboard && metadata.isFromEmptySelection); - multicursorText = metadata.multicursorText; + if (e.metadata) { + pasteOnNewLine = (this._emptySelectionClipboard && !!e.metadata.isFromEmptySelection); + multicursorText = (typeof e.metadata.multicursorText !== 'undefined' ? e.metadata.multicursorText : null); } this._viewController.paste('keyboard', e.text, pasteOnNewLine, multicursorText); })); @@ -395,6 +350,14 @@ export class TextAreaHandler extends ViewPart { this._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting); this.textArea.setAttribute('aria-label', this._getAriaLabel(options)); + if (platform.isWeb && e.hasChanged(EditorOption.readOnly)) { + if (options.get(EditorOption.readOnly)) { + this.textArea.setAttribute('readonly', 'true'); + } else { + this.textArea.removeAttribute('readonly'); + } + } + if (e.hasChanged(EditorOption.accessibilitySupport)) { this._textAreaInput.writeScreenReaderContent('strategy changed'); } @@ -445,7 +408,7 @@ export class TextAreaHandler extends ViewPart { // --- end view API - private _primaryCursorVisibleRange: HorizontalRange | null = null; + private _primaryCursorVisibleRange: HorizontalPosition | null = null; public prepareRender(ctx: RenderingContext): void { const primaryCursorPosition = new Position(this._selections[0].positionLineNumber, this._selections[0].positionColumn); @@ -464,8 +427,7 @@ export class TextAreaHandler extends ViewPart { this._visibleTextArea.top - this._scrollTop, this._contentLeft + this._visibleTextArea.left - this._scrollLeft, this._visibleTextArea.width, - this._lineHeight, - true + this._lineHeight ); return; } @@ -491,23 +453,28 @@ export class TextAreaHandler extends ViewPart { } // The primary cursor is in the viewport (at least vertically) => place textarea on the cursor + + if (platform.isMacintosh) { + // For the popup emoji input, we will make the text area as high as the line height + // We will also make the fontSize and lineHeight the correct dimensions to help with the placement of these pickers + this._renderInsideEditor( + top, left, + canUseZeroSizeTextarea ? 0 : 1, this._lineHeight + ); + return; + } + this._renderInsideEditor( top, left, - canUseZeroSizeTextarea ? 0 : 1, canUseZeroSizeTextarea ? 0 : 1, - false + canUseZeroSizeTextarea ? 0 : 1, canUseZeroSizeTextarea ? 0 : 1 ); } - private _renderInsideEditor(top: number, left: number, width: number, height: number, useEditorFont: boolean): void { + private _renderInsideEditor(top: number, left: number, width: number, height: number): void { const ta = this.textArea; const tac = this.textAreaCover; - if (useEditorFont) { - Configuration.applyFontInfo(ta, this._fontInfo); - } else { - ta.setFontSize(1); - ta.setLineHeight(this._fontInfo.lineHeight); - } + Configuration.applyFontInfo(ta, this._fontInfo); ta.setTop(top); ta.setLeft(left); diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index bfb885aa6b5..23f3d0cc2f7 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -32,11 +32,24 @@ const enum ReadFromTextArea { export interface IPasteData { text: string; + metadata: ClipboardStoredMetadata | null; +} + +export interface ClipboardDataToCopy { + isFromEmptySelection: boolean; + multicursorText: string[] | null | undefined; + text: string; + html: string | null | undefined; +} + +export interface ClipboardStoredMetadata { + version: 1; + isFromEmptySelection: boolean | undefined; + multicursorText: string[] | null | undefined; } export interface ITextAreaInputHost { - getPlainTextToCopy(): string; - getHTMLToCopy(): string | null; + getDataToCopy(html: boolean): ClipboardDataToCopy; getScreenReaderContent(currentState: TextAreaState): TextAreaState; deduceModelPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position; } @@ -59,6 +72,39 @@ interface CompositionEvent extends UIEvent { readonly locale: string; } +interface InMemoryClipboardMetadata { + lastCopiedValue: string; + data: ClipboardStoredMetadata; +} + +/** + * Every time we write to the clipboard, we record a bit of extra metadata here. + * Every time we read from the cipboard, if the text matches our last written text, + * we can fetch the previous metadata. + */ +class InMemoryClipboardMetadataManager { + public static readonly INSTANCE = new InMemoryClipboardMetadataManager(); + + private _lastState: InMemoryClipboardMetadata | null; + + constructor() { + this._lastState = null; + } + + public set(lastCopiedValue: string, data: ClipboardStoredMetadata): void { + this._lastState = { lastCopiedValue, data }; + } + + public get(pastedText: string): ClipboardStoredMetadata | null { + if (this._lastState && this._lastState.lastCopiedValue === pastedText) { + // match! + return this._lastState.data; + } + this._lastState = null; + return null; + } +} + /** * Writes screen reader content to the textarea and is able to analyze its input events to generate: * - onCut @@ -279,9 +325,7 @@ export class TextAreaInput extends Disposable { } } else { if (typeInput.text !== '') { - this._onPaste.fire({ - text: typeInput.text - }); + this._firePaste(typeInput.text, null); } this._nextCommand = ReadFromTextArea.Type; } @@ -314,11 +358,9 @@ export class TextAreaInput extends Disposable { this._textArea.setIgnoreSelectionChangeTime('received paste event'); if (ClipboardEventUtils.canUseTextData(e)) { - const pastePlainText = ClipboardEventUtils.getTextData(e); + const [pastePlainText, metadata] = ClipboardEventUtils.getTextData(e); if (pastePlainText !== '') { - this._onPaste.fire({ - text: pastePlainText - }); + this._firePaste(pastePlainText, metadata); } } else { if (this._textArea.getSelectionStart() !== this._textArea.getSelectionEnd()) { @@ -491,19 +533,38 @@ export class TextAreaInput extends Disposable { } private _ensureClipboardGetsEditorSelection(e: ClipboardEvent): void { - const copyPlainText = this._host.getPlainTextToCopy(); + const dataToCopy = this._host.getDataToCopy(ClipboardEventUtils.canUseTextData(e) && browser.hasClipboardSupport()); + const storedMetadata: ClipboardStoredMetadata = { + version: 1, + isFromEmptySelection: dataToCopy.isFromEmptySelection, + multicursorText: dataToCopy.multicursorText + }; + InMemoryClipboardMetadataManager.INSTANCE.set( + // When writing "LINE\r\n" to the clipboard and then pasting, + // Firefox pastes "LINE\n", so let's work around this quirk + (browser.isFirefox ? dataToCopy.text.replace(/\r\n/g, '\n') : dataToCopy.text), + storedMetadata + ); + if (!ClipboardEventUtils.canUseTextData(e)) { // Looks like an old browser. The strategy is to place the text // we'd like to be copied to the clipboard in the textarea and select it. - this._setAndWriteTextAreaState('copy or cut', TextAreaState.selectedText(copyPlainText)); + this._setAndWriteTextAreaState('copy or cut', TextAreaState.selectedText(dataToCopy.text)); return; } - let copyHTML: string | null = null; - if (browser.hasClipboardSupport() && (copyPlainText.length < 65536 || CopyOptions.forceCopyWithSyntaxHighlighting)) { - copyHTML = this._host.getHTMLToCopy(); + ClipboardEventUtils.setTextData(e, dataToCopy.text, dataToCopy.html, storedMetadata); + } + + private _firePaste(text: string, metadata: ClipboardStoredMetadata | null): void { + if (!metadata) { + // try the in-memory store + metadata = InMemoryClipboardMetadataManager.INSTANCE.get(text); } - ClipboardEventUtils.setTextData(e, copyPlainText, copyHTML); + this._onPaste.fire({ + text: text, + metadata: metadata + }); } } @@ -519,10 +580,25 @@ class ClipboardEventUtils { return false; } - public static getTextData(e: ClipboardEvent): string { + public static getTextData(e: ClipboardEvent): [string, ClipboardStoredMetadata | null] { if (e.clipboardData) { e.preventDefault(); - return e.clipboardData.getData('text/plain'); + + const text = e.clipboardData.getData('text/plain'); + let metadata: ClipboardStoredMetadata | null = null; + const rawmetadata = e.clipboardData.getData('vscode-editor-data'); + if (typeof rawmetadata === 'string') { + try { + metadata = JSON.parse(rawmetadata); + if (metadata.version !== 1) { + metadata = null; + } + } catch (err) { + // no problem! + } + } + + return [text, metadata]; } if ((window).clipboardData) { @@ -533,12 +609,13 @@ class ClipboardEventUtils { throw new Error('ClipboardEventUtils.getTextData: Cannot use text data!'); } - public static setTextData(e: ClipboardEvent, text: string, richText: string | null): void { + public static setTextData(e: ClipboardEvent, text: string, html: string | null | undefined, metadata: ClipboardStoredMetadata): void { if (e.clipboardData) { e.clipboardData.setData('text/plain', text); - if (richText !== null) { - e.clipboardData.setData('text/html', richText); + if (typeof html === 'string') { + e.clipboardData.setData('text/html', html); } + e.clipboardData.setData('vscode-editor-data', JSON.stringify(metadata)); e.preventDefault(); return; } diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 3a05cd5c8f4..50eed2efb08 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -18,6 +18,7 @@ import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguag import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService'; /** * A view zone is a full horizontal rectangle that 'pushes' text down. @@ -834,6 +835,15 @@ export interface IDiffLineInformation { readonly equivalentLineNumber: number; } +/** + * @internal + */ +export const enum DiffEditorState { + Idle, + ComputingDiff, + DiffComputed +} + /** * A rich diff editor. */ @@ -854,6 +864,11 @@ export interface IDiffEditor extends editorCommon.IEditor { * @internal */ readonly renderIndicators: boolean; + /** + * Timeout in milliseconds after which diff computation is cancelled. + * @internal + */ + readonly maxComputationTime: number; /** * @see ICodeEditor.getDomNode @@ -906,6 +921,12 @@ export interface IDiffEditor extends editorCommon.IEditor { */ getLineChanges(): editorCommon.ILineChange[] | null; + /** + * Get the computed diff information. + * @internal + */ + getDiffComputationResult(): IDiffComputationResult | null; + /** * Get information based on computed diff about a line number from the original model. * If the diff computation is not finished or the model is missing, will return null. diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index e7494cc7a97..8f2d7c90482 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -6,28 +6,35 @@ import { IPosition } from 'vs/base/browser/ui/contextview/contextview'; import { illegalArgument } from 'vs/base/common/errors'; import { URI } from 'vs/base/common/uri'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { Position } from 'vs/editor/common/core/position'; -import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { IEditorContribution, IDiffEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IConstructorSignature1, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { withNullAsUndefined } from 'vs/base/common/types'; -export type ServicesAccessor = ServicesAccessor; +export type ServicesAccessor = InstantiationServicesAccessor; export type IEditorContributionCtor = IConstructorSignature1; -export type EditorTelemetryDataFragment = { - target: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - snippet: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; -}; +export type IDiffEditorContributionCtor = IConstructorSignature1; + +export interface IEditorContributionDescription { + id: string; + ctor: IEditorContributionCtor; +} + +export interface IDiffEditorContributionDescription { + id: string; + ctor: IDiffEditorContributionCtor; +} //#region Command @@ -224,8 +231,8 @@ export abstract class EditorAction extends EditorCommand { protected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) { type EditorActionInvokedClassification = { - name: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + name: { classification: 'SystemMetaData', purpose: 'FeatureInsight', }; + id: { classification: 'SystemMetaData', purpose: 'FeatureInsight', }; }; type EditorActionInvokedEvent = { name: string; @@ -241,7 +248,7 @@ export abstract class EditorAction extends EditorCommand { // --- Registration of commands and actions -export function registerLanguageCommand(id: string, handler: (accessor: ServicesAccessor, args: { [n: string]: any }) => any) { +export function registerLanguageCommand(id: string, handler: (accessor: ServicesAccessor, args: Args) => any) { CommandsRegistry.registerCommand(id, (accessor, args) => handler(accessor, args || {})); } @@ -296,8 +303,12 @@ export function registerInstantiatedEditorAction(editorAction: EditorAction): vo EditorContributionRegistry.INSTANCE.registerEditorAction(editorAction); } -export function registerEditorContribution(ctor: IEditorContributionCtor): void { - EditorContributionRegistry.INSTANCE.registerEditorContribution(ctor); +export function registerEditorContribution(id: string, ctor: IEditorContributionCtor): void { + EditorContributionRegistry.INSTANCE.registerEditorContribution(id, ctor); +} + +export function registerDiffEditorContribution(id: string, ctor: IDiffEditorContributionCtor): void { + EditorContributionRegistry.INSTANCE.registerDiffEditorContribution(id, ctor); } export namespace EditorExtensionsRegistry { @@ -310,9 +321,17 @@ export namespace EditorExtensionsRegistry { return EditorContributionRegistry.INSTANCE.getEditorActions(); } - export function getEditorContributions(): IEditorContributionCtor[] { + export function getEditorContributions(): IEditorContributionDescription[] { return EditorContributionRegistry.INSTANCE.getEditorContributions(); } + + export function getSomeEditorContributions(ids: string[]): IEditorContributionDescription[] { + return EditorContributionRegistry.INSTANCE.getEditorContributions().filter(c => ids.indexOf(c.id) >= 0); + } + + export function getDiffEditorContributions(): IDiffEditorContributionDescription[] { + return EditorContributionRegistry.INSTANCE.getDiffEditorContributions(); + } } // Editor extension points @@ -324,18 +343,32 @@ class EditorContributionRegistry { public static readonly INSTANCE = new EditorContributionRegistry(); - private readonly editorContributions: IEditorContributionCtor[]; + private readonly editorContributions: IEditorContributionDescription[]; + private readonly diffEditorContributions: IDiffEditorContributionDescription[]; private readonly editorActions: EditorAction[]; private readonly editorCommands: { [commandId: string]: EditorCommand; }; constructor() { this.editorContributions = []; + this.diffEditorContributions = []; this.editorActions = []; this.editorCommands = Object.create(null); } - public registerEditorContribution(ctor: IEditorContributionCtor): void { - this.editorContributions.push(ctor); + public registerEditorContribution(id: string, ctor: IEditorContributionCtor): void { + this.editorContributions.push({ id, ctor }); + } + + public getEditorContributions(): IEditorContributionDescription[] { + return this.editorContributions.slice(0); + } + + public registerDiffEditorContribution(id: string, ctor: IDiffEditorContributionCtor): void { + this.diffEditorContributions.push({ id, ctor }); + } + + public getDiffEditorContributions(): IDiffEditorContributionDescription[] { + return this.diffEditorContributions.slice(0); } public registerEditorAction(action: EditorAction) { @@ -343,10 +376,6 @@ class EditorContributionRegistry { this.editorActions.push(action); } - public getEditorContributions(): IEditorContributionCtor[] { - return this.editorContributions.slice(0); - } - public getEditorActions(): EditorAction[] { return this.editorActions.slice(0); } diff --git a/src/vs/editor/browser/services/abstractCodeEditorService.ts b/src/vs/editor/browser/services/abstractCodeEditorService.ts index fbe1edfb8f4..53c5bac6f28 100644 --- a/src/vs/editor/browser/services/abstractCodeEditorService.ts +++ b/src/vs/editor/browser/services/abstractCodeEditorService.ts @@ -70,8 +70,8 @@ export abstract class AbstractCodeEditorService extends Disposable implements IC return Object.keys(this._diffEditors).map(id => this._diffEditors[id]); } - getFocusedCodeEditor(): ICodeEditor | undefined { - let editorWithWidgetFocus: ICodeEditor | undefined; + getFocusedCodeEditor(): ICodeEditor | null { + let editorWithWidgetFocus: ICodeEditor | null = null; const editors = this.listCodeEditors(); for (const editor of editors) { @@ -124,8 +124,8 @@ export abstract class AbstractCodeEditorService extends Disposable implements IC delete this._transientWatchers[w.uri]; } - abstract getActiveCodeEditor(): ICodeEditor | undefined; - abstract openCodeEditor(input: IResourceInput, source: ICodeEditor | undefined, sideBySide?: boolean): Promise; + abstract getActiveCodeEditor(): ICodeEditor | null; + abstract openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; } export class ModelTransientSettingWatcher { diff --git a/src/vs/editor/browser/services/codeEditorService.ts b/src/vs/editor/browser/services/codeEditorService.ts index c0998a6a33a..0cfba7fd7fb 100644 --- a/src/vs/editor/browser/services/codeEditorService.ts +++ b/src/vs/editor/browser/services/codeEditorService.ts @@ -33,10 +33,9 @@ export interface ICodeEditorService { listDiffEditors(): readonly IDiffEditor[]; /** - * Returns the current focused code editor (if the focus is in the editor or in an editor widget) or - * `undefined` if none. + * Returns the current focused code editor (if the focus is in the editor or in an editor widget) or null. */ - getFocusedCodeEditor(): ICodeEditor | undefined; + getFocusedCodeEditor(): ICodeEditor | null; registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void; removeDecorationType(key: string): void; @@ -45,6 +44,6 @@ export interface ICodeEditorService { setTransientModelProperty(model: ITextModel, key: string, value: any): void; getTransientModelProperty(model: ITextModel, key: string): any; - getActiveCodeEditor(): ICodeEditor | undefined; - openCodeEditor(input: IResourceInput, source: ICodeEditor | undefined, sideBySide?: boolean): Promise; + getActiveCodeEditor(): ICodeEditor | null; + openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; } diff --git a/src/vs/editor/browser/services/codeEditorServiceImpl.ts b/src/vs/editor/browser/services/codeEditorServiceImpl.ts index f5f03117b9b..c7cf1da3f45 100644 --- a/src/vs/editor/browser/services/codeEditorServiceImpl.ts +++ b/src/vs/editor/browser/services/codeEditorServiceImpl.ts @@ -65,8 +65,8 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { return provider.getOptions(this, writable); } - abstract getActiveCodeEditor(): ICodeEditor | undefined; - abstract openCodeEditor(input: IResourceInput, source: ICodeEditor | undefined, sideBySide?: boolean): Promise; + abstract getActiveCodeEditor(): ICodeEditor | null; + abstract openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; } interface IModelDecorationOptionsProvider extends IDisposable { diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 52b38930401..9902634b3e2 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -14,6 +14,7 @@ import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions } from 'vs/platform/opener/common/opener'; +import { EditorOpenContext } from 'vs/platform/editor/common/editor'; export class OpenerService extends Disposable implements IOpenerService { @@ -32,20 +33,24 @@ export class OpenerService extends Disposable implements IOpenerService { registerOpener(opener: IOpener): IDisposable { const remove = this._openers.push(opener); + return { dispose: remove }; } registerValidator(validator: IValidator): IDisposable { const remove = this._validators.push(validator); + return { dispose: remove }; } registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable { const remove = this._resolvers.push(resolver); + return { dispose: remove }; } async open(resource: URI, options?: OpenOptions): Promise { + // no scheme ?!? if (!resource.scheme) { return Promise.resolve(false); @@ -70,21 +75,21 @@ export class OpenerService extends Disposable implements IOpenerService { return this._doOpen(resource, options); } - public async resolveExternalUri(resource: URI, options?: { readonly allowTunneling?: boolean }): Promise<{ resolved: URI, dispose(): void }> { + async resolveExternalUri(resource: URI, options?: { readonly allowTunneling?: boolean }): Promise<{ resolved: URI, dispose(): void }> { for (const resolver of this._resolvers.toArray()) { const result = await resolver.resolveExternalUri(resource, options); if (result) { return result; } } + return { resolved: resource, dispose: () => { } }; } - private _doOpen(resource: URI, options: OpenOptions | undefined): Promise { - + private async _doOpen(resource: URI, options: OpenOptions | undefined): Promise { const { scheme, path, query, fragment } = resource; - if (equalsIgnoreCase(scheme, Schemas.mailto) || (options && options.openExternal)) { + if (equalsIgnoreCase(scheme, Schemas.mailto) || options?.openExternal) { // open default mail application return this._doOpenExternal(resource, options); } @@ -92,10 +97,12 @@ export class OpenerService extends Disposable implements IOpenerService { if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { // open link in default browser return this._doOpenExternal(resource, options); - } else if (equalsIgnoreCase(scheme, Schemas.command)) { + } + + if (equalsIgnoreCase(scheme, Schemas.command)) { // run command or bail out if command isn't known if (!CommandsRegistry.getCommand(path)) { - return Promise.reject(`command '${path}' NOT known`); + throw new Error(`command '${path}' NOT known`); } // execute as command let args: any = []; @@ -105,40 +112,46 @@ export class OpenerService extends Disposable implements IOpenerService { args = [args]; } } catch (e) { - // - } - return this._commandService.executeCommand(path, ...args).then(() => true); - - } else { - let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; - const match = /^L?(\d+)(?:,(\d+))?/.exec(fragment); - if (match) { - // support file:///some/file.js#73,84 - // support file:///some/file.js#L73 - selection = { - startLineNumber: parseInt(match[1]), - startColumn: match[2] ? parseInt(match[2]) : 1 - }; - // remove fragment - resource = resource.with({ fragment: '' }); + // ignore error } - if (resource.scheme === Schemas.file) { - resource = resources.normalizePath(resource); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) - } + await this._commandService.executeCommand(path, ...args); - return this._editorService.openCodeEditor( - { resource, options: { selection, } }, - this._editorService.getFocusedCodeEditor(), - options && options.openToSide - ).then(() => true); + return true; } + + // finally open in editor + let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; + const match = /^L?(\d+)(?:,(\d+))?/.exec(fragment); + if (match) { + // support file:///some/file.js#73,84 + // support file:///some/file.js#L73 + selection = { + startLineNumber: parseInt(match[1]), + startColumn: match[2] ? parseInt(match[2]) : 1 + }; + // remove fragment + resource = resource.with({ fragment: '' }); + } + + if (resource.scheme === Schemas.file) { + resource = resources.normalizePath(resource); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + } + + await this._editorService.openCodeEditor( + { resource, options: { selection, context: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API } }, + this._editorService.getFocusedCodeEditor(), + options?.openToSide + ); + + return true; } private async _doOpenExternal(resource: URI, options: OpenOptions | undefined): Promise { const { resolved } = await this.resolveExternalUri(resource, options); dom.windowOpenNoOpener(encodeURI(resolved.toString(true))); - return Promise.resolve(true); + + return true; } dispose() { diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index 3cbd1cc286f..9057fdfbe22 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -13,6 +13,7 @@ import { IConfiguration } from 'vs/editor/common/editorCommon'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import * as platform from 'vs/base/common/platform'; export interface IMouseDispatchData { position: Position; @@ -132,7 +133,8 @@ export class ViewController { } public dispatchMouse(data: IMouseDispatchData): void { - if (data.middleButton) { + const selectionClipboardIsOn = (platform.isLinux && this.configuration.options.get(EditorOption.selectionClipboard)); + if (data.middleButton && !selectionClipboardIsOn) { this._columnSelect(data.position, data.mouseColumn, data.inSelectionMode); } else if (data.startedOnLineNumbers) { // If the dragging started on the gutter, then have operations work on the entire line diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 9f2e96a1a38..15f286d6abe 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -17,8 +17,7 @@ import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents'; import { ContentViewOverlays, MarginViewOverlays } from 'vs/editor/browser/view/viewOverlays'; import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart'; import { ViewContentWidgets } from 'vs/editor/browser/viewParts/contentWidgets/contentWidgets'; -import { CurrentLineHighlightOverlay } from 'vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight'; -import { CurrentLineMarginHighlightOverlay } from 'vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight'; +import { CurrentLineHighlightOverlay, CurrentLineMarginHighlightOverlay } from 'vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight'; import { DecorationsOverlay } from 'vs/editor/browser/viewParts/decorations/decorations'; import { EditorScrollbar } from 'vs/editor/browser/viewParts/editorScrollbar/editorScrollbar'; import { GlyphMarginOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin'; @@ -261,7 +260,7 @@ export class View extends ViewEventHandler { return this.viewLines.getPositionFromDOMInfo(spanNode, offset); }, - visibleRangeForPosition2: (lineNumber: number, column: number) => { + visibleRangeForPosition: (lineNumber: number, column: number) => { this._flushAccumulatedAndRenderNow(); return this.viewLines.visibleRangeForPosition(new Position(lineNumber, column)); }, diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index 3a962f22ea2..e98cea19e9c 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -9,7 +9,7 @@ import { ContentWidgetPositionPreference, IContentWidget } from 'vs/editor/brows import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; @@ -380,7 +380,7 @@ class Widget { belowLeft = absoluteBelowLeft; } - return { fitsAbove, aboveTop, aboveLeft, fitsBelow, belowTop, belowLeft }; + return { fitsAbove, aboveTop: Math.max(aboveTop, TOP_PADDING), aboveLeft, fitsBelow, belowTop, belowLeft }; } private _prepareRenderWidgetAtExactPositionOverflowing(topLeft: Coordinate): Coordinate { diff --git a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css index 80ec19b898c..2a0e39dffa7 100644 --- a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css +++ b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css @@ -9,4 +9,16 @@ left: 0; top: 0; box-sizing: border-box; -} \ No newline at end of file +} + +.monaco-editor .margin-view-overlays .current-line { + display: block; + position: absolute; + left: 0; + top: 0; + box-sizing: border-box; +} + +.monaco-editor .margin-view-overlays .current-line.current-line-margin.current-line-margin-both { + border-right: 0; +} diff --git a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts index 820b7c30e29..cb3e355d8c6 100644 --- a/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts +++ b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts @@ -9,18 +9,23 @@ import { editorLineHighlight, editorLineHighlightBorder } from 'vs/editor/common import { RenderingContext } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import * as arrays from 'vs/base/common/arrays'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { Selection } from 'vs/editor/common/core/selection'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +let isRenderedUsingBorder = true; -export class CurrentLineHighlightOverlay extends DynamicViewOverlay { +export abstract class AbstractLineHighlightOverlay extends DynamicViewOverlay { private readonly _context: ViewContext; - private _lineHeight: number; - private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; - private _contentWidth: number; - private _selectionIsEmpty: boolean; - private _primaryCursorLineNumber: number; - private _scrollWidth: number; + protected _lineHeight: number; + protected _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; + protected _contentLeft: number; + protected _contentWidth: number; + protected _selectionIsEmpty: boolean; + private _cursorLineNumbers: number[]; + private _selections: Selection[]; + private _renderData: string[] | null; constructor(context: ViewContext) { super(); @@ -28,15 +33,14 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay { const options = this._context.configuration.options; const layoutInfo = options.get(EditorOption.layoutInfo); - this._lineHeight = options.get(EditorOption.lineHeight); this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentLeft = layoutInfo.contentLeft; this._contentWidth = layoutInfo.contentWidth; - this._selectionIsEmpty = true; - this._primaryCursorLineNumber = 1; - this._scrollWidth = 0; - + this._cursorLineNumbers = []; + this._selections = []; + this._renderData = null; this._context.addEventHandler(this); } @@ -46,33 +50,44 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay { super.dispose(); } - // --- begin event handlers + private _readFromSelections(): boolean { + let hasChanged = false; + // Only render the first selection when using border + const renderSelections = isRenderedUsingBorder ? this._selections.slice(0, 1) : this._selections; + + const cursorsLineNumbers = renderSelections.map(s => s.positionLineNumber); + cursorsLineNumbers.sort(); + if (!arrays.equals(this._cursorLineNumbers, cursorsLineNumbers)) { + this._cursorLineNumbers = cursorsLineNumbers; + hasChanged = true; + } + + const selectionIsEmpty = renderSelections.every(s => s.isEmpty()); + if (this._selectionIsEmpty !== selectionIsEmpty) { + this._selectionIsEmpty = selectionIsEmpty; + hasChanged = true; + } + + return hasChanged; + } + + // --- begin event handlers + public onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean { + return this._readFromSelections(); + } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { const options = this._context.configuration.options; const layoutInfo = options.get(EditorOption.layoutInfo); - this._lineHeight = options.get(EditorOption.lineHeight); this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); + this._contentLeft = layoutInfo.contentLeft; this._contentWidth = layoutInfo.contentWidth; return true; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { - let hasChanged = false; - - const primaryCursorLineNumber = e.selections[0].positionLineNumber; - if (this._primaryCursorLineNumber !== primaryCursorLineNumber) { - this._primaryCursorLineNumber = primaryCursorLineNumber; - hasChanged = true; - } - - const selectionIsEmpty = e.selections[0].isEmpty(); - if (this._selectionIsEmpty !== selectionIsEmpty) { - this._selectionIsEmpty = selectionIsEmpty; - return true; - } - - return hasChanged; + this._selections = e.selections; + return this._readFromSelections(); } public onFlushed(e: viewEvents.ViewFlushedEvent): boolean { return true; @@ -84,7 +99,7 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay { return true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { - return e.scrollWidthChanged; + return e.scrollWidthChanged || e.scrollTopChanged; } public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean { return true; @@ -92,55 +107,99 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay { // --- end event handlers public prepareRender(ctx: RenderingContext): void { - this._scrollWidth = ctx.scrollWidth; + if (!this._shouldRenderThis()) { + this._renderData = null; + return; + } + const renderedLine = this._renderOne(ctx); + const visibleStartLineNumber = ctx.visibleRange.startLineNumber; + const visibleEndLineNumber = ctx.visibleRange.endLineNumber; + const len = this._cursorLineNumbers.length; + let index = 0; + const renderData: string[] = []; + for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) { + const lineIndex = lineNumber - visibleStartLineNumber; + while (index < len && this._cursorLineNumbers[index] < lineNumber) { + index++; + } + if (index < len && this._cursorLineNumbers[index] === lineNumber) { + renderData[lineIndex] = renderedLine; + } else { + renderData[lineIndex] = ''; + } + } + this._renderData = renderData; } public render(startLineNumber: number, lineNumber: number): string { - if (lineNumber === this._primaryCursorLineNumber) { - if (this._shouldShowCurrentLine()) { - const paintedInMargin = this._willRenderMarginCurrentLine(); - const className = 'current-line' + (paintedInMargin ? ' current-line-both' : ''); - return ( - '
' - ); - } else { - return ''; - } + if (!this._renderData) { + return ''; } - return ''; + const lineIndex = lineNumber - startLineNumber; + if (lineIndex >= this._renderData.length) { + return ''; + } + return this._renderData[lineIndex]; } - private _shouldShowCurrentLine(): boolean { + protected abstract _shouldRenderThis(): boolean; + protected abstract _shouldRenderOther(): boolean; + protected abstract _renderOne(ctx: RenderingContext): string; +} + +export class CurrentLineHighlightOverlay extends AbstractLineHighlightOverlay { + + protected _renderOne(ctx: RenderingContext): string { + const className = 'current-line' + (this._shouldRenderOther() ? ' current-line-both' : ''); + return `
`; + } + protected _shouldRenderThis(): boolean { return ( (this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all') && this._selectionIsEmpty ); } - - private _willRenderMarginCurrentLine(): boolean { + protected _shouldRenderOther(): boolean { return ( (this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all') ); } } +export class CurrentLineMarginHighlightOverlay extends AbstractLineHighlightOverlay { + protected _renderOne(ctx: RenderingContext): string { + const className = 'current-line current-line-margin' + (this._shouldRenderOther() ? ' current-line-margin-both' : ''); + return `
`; + } + protected _shouldRenderThis(): boolean { + return ( + (this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all') + ); + } + protected _shouldRenderOther(): boolean { + return ( + (this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all') + && this._selectionIsEmpty + ); + } +} + registerThemingParticipant((theme, collector) => { + isRenderedUsingBorder = false; const lineHighlight = theme.getColor(editorLineHighlight); if (lineHighlight) { collector.addRule(`.monaco-editor .view-overlays .current-line { background-color: ${lineHighlight}; }`); + collector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { background-color: ${lineHighlight}; border: none; }`); } if (!lineHighlight || lineHighlight.isTransparent() || theme.defines(editorLineHighlightBorder)) { const lineHighlightBorder = theme.getColor(editorLineHighlightBorder); if (lineHighlightBorder) { + isRenderedUsingBorder = true; collector.addRule(`.monaco-editor .view-overlays .current-line { border: 2px solid ${lineHighlightBorder}; }`); + collector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { border: 2px solid ${lineHighlightBorder}; }`); if (theme.type === 'hc') { collector.addRule(`.monaco-editor .view-overlays .current-line { border-width: 1px; }`); + collector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { border-width: 1px; }`); } } } diff --git a/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts b/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts deleted file mode 100644 index f07b024aca1..00000000000 --- a/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.ts +++ /dev/null @@ -1,139 +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!./currentLineMarginHighlight'; -import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay'; -import { editorLineHighlight, editorLineHighlightBorder } from 'vs/editor/common/view/editorColorRegistry'; -import { RenderingContext } from 'vs/editor/common/view/renderingContext'; -import { ViewContext } from 'vs/editor/common/view/viewContext'; -import * as viewEvents from 'vs/editor/common/view/viewEvents'; -import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; - - -export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay { - private readonly _context: ViewContext; - private _lineHeight: number; - private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all'; - private _contentLeft: number; - private _selectionIsEmpty: boolean; - private _primaryCursorLineNumber: number; - - constructor(context: ViewContext) { - super(); - this._context = context; - - const options = this._context.configuration.options; - const layoutInfo = options.get(EditorOption.layoutInfo); - - this._lineHeight = options.get(EditorOption.lineHeight); - this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); - this._contentLeft = layoutInfo.contentLeft; - - this._selectionIsEmpty = true; - this._primaryCursorLineNumber = 1; - - this._context.addEventHandler(this); - } - - public dispose(): void { - this._context.removeEventHandler(this); - super.dispose(); - } - - // --- begin event handlers - - public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean { - const options = this._context.configuration.options; - const layoutInfo = options.get(EditorOption.layoutInfo); - - this._lineHeight = options.get(EditorOption.lineHeight); - this._renderLineHighlight = options.get(EditorOption.renderLineHighlight); - this._contentLeft = layoutInfo.contentLeft; - return true; - } - public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { - let hasChanged = false; - - const primaryCursorLineNumber = e.selections[0].positionLineNumber; - if (this._primaryCursorLineNumber !== primaryCursorLineNumber) { - this._primaryCursorLineNumber = primaryCursorLineNumber; - hasChanged = true; - } - - const selectionIsEmpty = e.selections[0].isEmpty(); - if (this._selectionIsEmpty !== selectionIsEmpty) { - this._selectionIsEmpty = selectionIsEmpty; - return true; - } - - return hasChanged; - } - public onFlushed(e: viewEvents.ViewFlushedEvent): boolean { - return true; - } - public onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean { - return true; - } - public onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean { - return true; - } - public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean { - return true; - } - // --- end event handlers - - public prepareRender(ctx: RenderingContext): void { - } - - public render(startLineNumber: number, lineNumber: number): string { - if (lineNumber === this._primaryCursorLineNumber) { - let className = 'current-line'; - if (this._shouldShowCurrentLine()) { - const paintedInContent = this._willRenderContentCurrentLine(); - className = 'current-line current-line-margin' + (paintedInContent ? ' current-line-margin-both' : ''); - } - - return ( - '
' - ); - } - return ''; - } - - private _shouldShowCurrentLine(): boolean { - return ( - (this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all') - ); - } - - private _willRenderContentCurrentLine(): boolean { - return ( - (this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all') - && this._selectionIsEmpty - ); - } -} - -registerThemingParticipant((theme, collector) => { - const lineHighlight = theme.getColor(editorLineHighlight); - if (lineHighlight) { - collector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { background-color: ${lineHighlight}; border: none; }`); - } else { - const lineHighlightBorder = theme.getColor(editorLineHighlightBorder); - if (lineHighlightBorder) { - collector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { border: 2px solid ${lineHighlightBorder}; }`); - } - if (theme.type === 'hc') { - collector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { border-width: 1px; }`); - } - } -}); diff --git a/src/vs/editor/browser/viewParts/decorations/decorations.ts b/src/vs/editor/browser/viewParts/decorations/decorations.ts index 7ba28975519..e8b5e779862 100644 --- a/src/vs/editor/browser/viewParts/decorations/decorations.ts +++ b/src/vs/editor/browser/viewParts/decorations/decorations.ts @@ -195,6 +195,9 @@ export class DecorationsOverlay extends DynamicViewOverlay { for (let j = 0, lenJ = linesVisibleRanges.length; j < lenJ; j++) { const lineVisibleRanges = linesVisibleRanges[j]; + if (lineVisibleRanges.outsideRenderedLine) { + continue; + } const lineIndex = lineVisibleRanges.lineNumber - visibleStartLineNumber; if (showIfCollapsed && lineVisibleRanges.ranges.length === 1) { diff --git a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css index c05287861d9..17f7d5defd5 100644 --- a/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css +++ b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css @@ -14,4 +14,7 @@ */ .monaco-editor .margin-view-overlays .cgmr { position: absolute; + display: flex; + align-items: center; + justify-content: center; } diff --git a/src/vs/editor/browser/viewParts/lines/rangeUtil.ts b/src/vs/editor/browser/viewParts/lines/rangeUtil.ts index 5344effa706..f84a79df8d4 100644 --- a/src/vs/editor/browser/viewParts/lines/rangeUtil.ts +++ b/src/vs/editor/browser/viewParts/lines/rangeUtil.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; class FloatHorizontalRange { diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index 4e0016d5fac..655b93462d3 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -10,13 +10,13 @@ import { IVisibleLine } from 'vs/editor/browser/view/viewLayer'; import { RangeUtil } from 'vs/editor/browser/viewParts/lines/rangeUtil'; import { IStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { IConfiguration } from 'vs/editor/common/editorCommon'; -import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; +import { HorizontalRange, VisibleRanges } from 'vs/editor/common/view/renderingContext'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; 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'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; const canUseFastRenderedViewLine = (function () { if (platform.isNative) { @@ -77,7 +77,7 @@ export class ViewLineOptions { public readonly canUseHalfwidthRightwardsArrow: boolean; public readonly lineHeight: number; public readonly stopRenderingLineAfter: number; - public readonly fontLigatures: boolean; + public readonly fontLigatures: string; constructor(config: IConfiguration, themeType: ThemeType) { this.themeType = themeType; @@ -89,7 +89,6 @@ export class ViewLineOptions { this.useMonospaceOptimizations = ( fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) - && !options.get(EditorOption.fontLigatures) ); this.canUseHalfwidthRightwardsArrow = fontInfo.canUseHalfwidthRightwardsArrow; this.lineHeight = options.get(EditorOption.lineHeight); @@ -218,7 +217,7 @@ export class ViewLine implements IVisibleLine { options.stopRenderingLineAfter, options.renderWhitespace, options.renderControlCharacters, - options.fontLigatures, + options.fontLigatures !== EditorFontLigatures.OFF, selectionsOnLine ); @@ -296,7 +295,7 @@ export class ViewLine implements IVisibleLine { return this._renderedViewLine.getWidthIsFast(); } - public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null { + public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): VisibleRanges | null { if (!this._renderedViewLine) { return null; } @@ -307,21 +306,27 @@ export class ViewLine implements IVisibleLine { endColumn = Math.min(this._renderedViewLine.input.lineContent.length + 1, Math.max(1, endColumn)); const stopRenderingLineAfter = this._renderedViewLine.input.stopRenderingLineAfter | 0; // @perf + let outsideRenderedLine = false; - if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter && endColumn > stopRenderingLineAfter) { + if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter + 1 && endColumn > stopRenderingLineAfter + 1) { // This range is obviously not visible - return null; + outsideRenderedLine = true; } - if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter) { - startColumn = stopRenderingLineAfter; + if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter + 1) { + startColumn = stopRenderingLineAfter + 1; } - if (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter) { - endColumn = stopRenderingLineAfter; + if (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter + 1) { + endColumn = stopRenderingLineAfter + 1; } - return this._renderedViewLine.getVisibleRangesForRange(startColumn, endColumn, context); + const horizontalRanges = this._renderedViewLine.getVisibleRangesForRange(startColumn, endColumn, context); + if (horizontalRanges && horizontalRanges.length > 0) { + return new VisibleRanges(outsideRenderedLine, horizontalRanges); + } + + return null; } public getColumnOfNodeOffset(lineNumber: number, spanNode: HTMLElement, offset: number): number { diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.css b/src/vs/editor/browser/viewParts/lines/viewLines.css index fee7f696501..b6b58faacb6 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.css +++ b/src/vs/editor/browser/viewParts/lines/viewLines.css @@ -17,12 +17,9 @@ .monaco-editor.no-user-select .lines-content, .monaco-editor.no-user-select .view-line, .monaco-editor.no-user-select .view-lines { + user-select: none; -webkit-user-select: none; -ms-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -o-user-select: none; - user-select: none; } .monaco-editor .view-lines { @@ -45,4 +42,4 @@ float: none; min-height: inherit; margin-left: inherit; -}*/ \ No newline at end of file +}*/ diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index eb524a41b69..852d6125985 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -12,14 +12,14 @@ import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/v import { DomReadingContext, ViewLine, ViewLineOptions } from 'vs/editor/browser/viewParts/lines/viewLine'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { Selection } from 'vs/editor/common/core/selection'; import { ScrollType } from 'vs/editor/common/editorCommon'; -import { HorizontalRange, IViewLines, LineVisibleRanges } from 'vs/editor/common/view/renderingContext'; +import { IViewLines, LineVisibleRanges, VisibleRanges, HorizontalPosition } from 'vs/editor/common/view/renderingContext'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { Viewport } from 'vs/editor/common/viewModel/viewModel'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { Constants } from 'vs/base/common/uint'; class LastRenderedData { @@ -73,8 +73,8 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, private _typicalHalfwidthCharacterWidth: number; private _isViewportWrapping: boolean; private _revealHorizontalRightPadding: number; - private _selections: Selection[]; private _cursorSurroundingLines: number; + private _cursorSurroundingLinesStyle: 'default' | 'all'; private _canUseLayerHinting: boolean; private _viewLineOptions: ViewLineOptions; @@ -102,9 +102,9 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, this._isViewportWrapping = wrappingInfo.isViewportWrapping; this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding); this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); + this._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle); this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); this._viewLineOptions = new ViewLineOptions(conf, this._context.theme.type); - this._selections = []; PartFingerprints.write(this.domNode, PartFingerprint.ViewLines); this.domNode.setClassName('view-lines'); @@ -155,6 +155,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, this._isViewportWrapping = wrappingInfo.isViewportWrapping; this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding); this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); + this._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle); this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); Configuration.applyFontInfo(this.domNode, fontInfo); @@ -185,7 +186,6 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, return false; } public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean { - this._selections = e.selections; const rendStartLineNumber = this._visibleLines.getStartLineNumber(); const rendEndLineNumber = this._visibleLines.getEndLineNumber(); let r = false; @@ -389,7 +389,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, const endColumn = lineNumber === range.endLineNumber ? range.endColumn : this._context.model.getLineMaxColumn(lineNumber); const visibleRangesForLine = this._visibleLines.getVisibleLine(lineNumber).getVisibleRangesForRange(startColumn, endColumn, domReadingContext); - if (!visibleRangesForLine || visibleRangesForLine.length === 0) { + if (!visibleRangesForLine) { continue; } @@ -398,11 +398,11 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, nextLineModelLineNumber = this._context.model.coordinatesConverter.convertViewPositionToModelPosition(new Position(lineNumber + 1, 1)).lineNumber; if (currentLineModelLineNumber !== nextLineModelLineNumber) { - visibleRangesForLine[visibleRangesForLine.length - 1].width += this._typicalHalfwidthCharacterWidth; + visibleRangesForLine.ranges[visibleRangesForLine.ranges.length - 1].width += this._typicalHalfwidthCharacterWidth; } } - visibleRanges[visibleRangesLen++] = new LineVisibleRanges(lineNumber, visibleRangesForLine); + visibleRanges[visibleRangesLen++] = new LineVisibleRanges(visibleRangesForLine.outsideRenderedLine, lineNumber, visibleRangesForLine.ranges); } if (visibleRangesLen === 0) { @@ -412,54 +412,26 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, return visibleRanges; } - private visibleRangesForRange2(_range: Range): HorizontalRange[] | null { - + private _visibleRangesForLineRange(lineNumber: number, startColumn: number, endColumn: number): VisibleRanges | null { if (this.shouldRender()) { // Cannot read from the DOM because it is dirty // i.e. the model & the dom are out of sync, so I'd be reading something stale return null; } - const range = Range.intersectRanges(_range, this._lastRenderedData.getCurrentVisibleRange()); - if (!range) { + if (lineNumber < this._visibleLines.getStartLineNumber() || lineNumber > this._visibleLines.getEndLineNumber()) { return null; } - let result: HorizontalRange[] = []; - const domReadingContext = new DomReadingContext(this.domNode.domNode, this._textRangeRestingSpot); - - const rendStartLineNumber = this._visibleLines.getStartLineNumber(); - const rendEndLineNumber = this._visibleLines.getEndLineNumber(); - for (let lineNumber = range.startLineNumber; lineNumber <= range.endLineNumber; lineNumber++) { - - if (lineNumber < rendStartLineNumber || lineNumber > rendEndLineNumber) { - continue; - } - - const startColumn = lineNumber === range.startLineNumber ? range.startColumn : 1; - const endColumn = lineNumber === range.endLineNumber ? range.endColumn : this._context.model.getLineMaxColumn(lineNumber); - const visibleRangesForLine = this._visibleLines.getVisibleLine(lineNumber).getVisibleRangesForRange(startColumn, endColumn, domReadingContext); - - if (!visibleRangesForLine || visibleRangesForLine.length === 0) { - continue; - } - - result = result.concat(visibleRangesForLine); - } - - if (result.length === 0) { - return null; - } - - return result; + return this._visibleLines.getVisibleLine(lineNumber).getVisibleRangesForRange(startColumn, endColumn, new DomReadingContext(this.domNode.domNode, this._textRangeRestingSpot)); } - public visibleRangeForPosition(position: Position): HorizontalRange | null { - const visibleRanges = this.visibleRangesForRange2(new Range(position.lineNumber, position.column, position.lineNumber, position.column)); + public visibleRangeForPosition(position: Position): HorizontalPosition | null { + const visibleRanges = this._visibleRangesForLineRange(position.lineNumber, position.column, position.column); if (!visibleRanges) { return null; } - return visibleRanges[0]; + return new HorizontalPosition(visibleRanges.outsideRenderedLine, visibleRanges.ranges[0].left); } // --- implementation @@ -598,10 +570,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, boxStartY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.startLineNumber); boxEndY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.endLineNumber) + this._lineHeight; - const shouldIgnoreScrollOff = source === 'mouse' && ( - this._selections.length > 1 // scroll off might trigger scrolling and mess up with multi cursor - || (this._selections.length > 0 && this._selections[0].isEmpty()) // we don't want to single click triggering selection - ); + const shouldIgnoreScrollOff = source === 'mouse' && this._cursorSurroundingLinesStyle === 'default'; if (!shouldIgnoreScrollOff) { const context = Math.min((viewportHeight / this._lineHeight) / 2, this._cursorSurroundingLines); @@ -616,7 +585,10 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, let newScrollTop: number; - if (verticalType === viewEvents.VerticalRevealType.Center || verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport) { + if (boxEndY - boxStartY > viewportHeight) { + // the box is larger than the viewport ... scroll to its top + newScrollTop = boxStartY; + } else if (verticalType === viewEvents.VerticalRevealType.Center || verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport) { if (verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport && viewportStartY <= boxStartY && boxEndY <= viewportEndY) { // Box is already in the viewport... do nothing newScrollTop = viewportStartY; @@ -640,8 +612,8 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, const viewportStartX = viewport.left; const viewportEndX = viewportStartX + viewport.width; - const visibleRanges = this.visibleRangesForRange2(new Range(lineNumber, startColumn, lineNumber, endColumn)); - let boxStartX = Number.MAX_VALUE; + const visibleRanges = this._visibleRangesForLineRange(lineNumber, startColumn, endColumn); + let boxStartX = Constants.MAX_SAFE_SMALL_INTEGER; let boxEndX = 0; if (!visibleRanges) { @@ -652,7 +624,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, }; } - for (const visibleRange of visibleRanges) { + for (const visibleRange of visibleRanges.ranges) { if (visibleRange.left < boxStartX) { boxStartX = visibleRange.left; } diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index a9cc144fe33..146ce38adc4 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -18,9 +18,10 @@ import { Range } from 'vs/editor/common/core/range'; import { RGBA8 } from 'vs/editor/common/core/rgba'; import { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon'; import { ColorId } from 'vs/editor/common/modes'; -import { Constants, MinimapCharRenderer, MinimapTokensColorTracker } from 'vs/editor/common/view/minimapCharRenderer'; +import { MinimapCharRenderer } from 'vs/editor/browser/viewParts/minimap/minimapCharRenderer'; +import { Constants } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet'; +import { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; -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'; @@ -29,33 +30,23 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel'; import { Selection } from 'vs/editor/common/core/selection'; import { Color } from 'vs/base/common/color'; +import { GestureEvent, EventType, Gesture } from 'vs/base/browser/touch'; +import { MinimapCharRendererFactory } from 'vs/editor/browser/viewParts/minimap/minimapCharRendererFactory'; -function getMinimapLineHeight(renderMinimap: RenderMinimap): number { - if (renderMinimap === RenderMinimap.Large) { - return Constants.x2_CHAR_HEIGHT; +function getMinimapLineHeight(renderMinimap: RenderMinimap, scale: number): number { + if (renderMinimap === RenderMinimap.Text) { + return Constants.BASE_CHAR_HEIGHT * scale; } - if (renderMinimap === RenderMinimap.LargeBlocks) { - return Constants.x2_CHAR_HEIGHT + 2; - } - if (renderMinimap === RenderMinimap.Small) { - return Constants.x1_CHAR_HEIGHT; - } - // RenderMinimap.SmallBlocks - return Constants.x1_CHAR_HEIGHT + 1; + // RenderMinimap.Blocks + return (Constants.BASE_CHAR_HEIGHT + 1) * scale; } -function getMinimapCharWidth(renderMinimap: RenderMinimap): number { - if (renderMinimap === RenderMinimap.Large) { - return Constants.x2_CHAR_WIDTH; +function getMinimapCharWidth(renderMinimap: RenderMinimap, scale: number): number { + if (renderMinimap === RenderMinimap.Text) { + return Constants.BASE_CHAR_WIDTH * scale; } - if (renderMinimap === RenderMinimap.LargeBlocks) { - return Constants.x2_CHAR_WIDTH; - } - if (renderMinimap === RenderMinimap.Small) { - return Constants.x1_CHAR_WIDTH; - } - // RenderMinimap.SmallBlocks - return Constants.x1_CHAR_WIDTH; + // RenderMinimap.Blocks + return Constants.BASE_CHAR_WIDTH * scale; } /** @@ -77,6 +68,10 @@ class MinimapOptions { public readonly lineHeight: number; + public readonly fontScale: number; + + public readonly charRenderer: MinimapCharRenderer; + /** * container dom node left position (in CSS px) */ @@ -118,6 +113,8 @@ class MinimapOptions { this.scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine); const minimapOpts = options.get(EditorOption.minimap); this.showSlider = minimapOpts.showSlider; + this.fontScale = Math.round(minimapOpts.scale * pixelRatio); + this.charRenderer = MinimapCharRendererFactory.create(this.fontScale, fontInfo.fontFamily); this.pixelRatio = pixelRatio; this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; this.lineHeight = options.get(EditorOption.lineHeight); @@ -139,6 +136,7 @@ class MinimapOptions { && this.pixelRatio === other.pixelRatio && this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth && this.lineHeight === other.lineHeight + && this.fontScale === other.fontScale && this.minimapLeft === other.minimapLeft && this.minimapWidth === other.minimapWidth && this.minimapHeight === other.minimapHeight @@ -208,6 +206,10 @@ class MinimapLayout { return Math.round(desiredSliderPosition / this._computedSliderRatio); } + public getDesiredScrollTopFromTouchLocation(pageY: number): number { + return Math.round((pageY - this.sliderHeight / 2) / this._computedSliderRatio); + } + public static create( options: MinimapOptions, viewportStartLineNumber: number, @@ -220,7 +222,7 @@ class MinimapLayout { previousLayout: MinimapLayout | null ): MinimapLayout { const pixelRatio = options.pixelRatio; - const minimapLineHeight = getMinimapLineHeight(options.renderMinimap); + const minimapLineHeight = getMinimapLineHeight(options.renderMinimap, options.fontScale); const minimapLinesFitting = Math.floor(options.canvasInnerHeight / minimapLineHeight); const lineHeight = options.lineHeight; @@ -451,12 +453,17 @@ export class Minimap extends ViewPart { private readonly _mouseDownListener: IDisposable; private readonly _sliderMouseMoveMonitor: GlobalMouseMoveMonitor; private readonly _sliderMouseDownListener: IDisposable; + private readonly _gestureDisposable: IDisposable; + private readonly _sliderTouchStartListener: IDisposable; + private readonly _sliderTouchMoveListener: IDisposable; + private readonly _sliderTouchEndListener: IDisposable; private _options: MinimapOptions; private _lastRenderData: RenderData | null; private _selections: Selection[] = []; private _selectionColor: Color | undefined; private _renderDecorations: boolean = false; + private _gestureInProgress: boolean = false; private _buffers: MinimapBuffers | null; constructor(context: ViewContext) { @@ -514,7 +521,7 @@ export class Minimap extends ViewPart { if (!this._lastRenderData) { return; } - const minimapLineHeight = getMinimapLineHeight(renderMinimap); + const minimapLineHeight = getMinimapLineHeight(renderMinimap, this._options.fontScale); const internalOffsetY = this._options.pixelRatio * e.browserEvent.offsetY; const lineIndex = Math.floor(internalOffsetY / minimapLineHeight); @@ -566,12 +573,50 @@ export class Minimap extends ViewPart { ); } }); + + this._gestureDisposable = Gesture.addTarget(this._domNode.domNode); + this._sliderTouchStartListener = dom.addDisposableListener(this._domNode.domNode, EventType.Start, (e: GestureEvent) => { + e.preventDefault(); + e.stopPropagation(); + if (this._lastRenderData) { + this._slider.toggleClassName('active', true); + this._gestureInProgress = true; + this.scrollDueToTouchEvent(e); + } + }); + + this._sliderTouchMoveListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.Change, (e: GestureEvent) => { + e.preventDefault(); + e.stopPropagation(); + if (this._lastRenderData && this._gestureInProgress) { + this.scrollDueToTouchEvent(e); + } + }); + + this._sliderTouchEndListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.End, (e: GestureEvent) => { + e.preventDefault(); + e.stopPropagation(); + this._gestureInProgress = false; + this._slider.toggleClassName('active', false); + }); + } + + private scrollDueToTouchEvent(touch: GestureEvent) { + const startY = this._domNode.domNode.getBoundingClientRect().top; + const scrollTop = this._lastRenderData!.renderedLayout.getDesiredScrollTopFromTouchLocation(touch.pageY - startY); + this._context.viewLayout.setScrollPositionNow({ + scrollTop: scrollTop + }); } public dispose(): void { this._mouseDownListener.dispose(); this._sliderMouseMoveMonitor.dispose(); this._sliderMouseDownListener.dispose(); + this._gestureDisposable.dispose(); + this._sliderTouchStartListener.dispose(); + this._sliderTouchMoveListener.dispose(); + this._sliderTouchEndListener.dispose(); super.dispose(); } @@ -730,7 +775,7 @@ export class Minimap extends ViewPart { // Compute horizontal slider coordinates const scrollLeftChars = renderingCtx.scrollLeft / this._options.typicalHalfwidthCharacterWidth; - const horizontalSliderLeft = Math.min(this._options.minimapWidth, Math.round(scrollLeftChars * getMinimapCharWidth(this._options.renderMinimap) / this._options.pixelRatio)); + const horizontalSliderLeft = Math.min(this._options.minimapWidth, Math.round(scrollLeftChars * getMinimapCharWidth(this._options.renderMinimap, this._options.fontScale) / this._options.pixelRatio)); this._sliderHorizontal.setLeft(horizontalSliderLeft); this._sliderHorizontal.setWidth(this._options.minimapWidth - horizontalSliderLeft); this._sliderHorizontal.setTop(0); @@ -746,8 +791,8 @@ export class Minimap extends ViewPart { 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 lineHeight = getMinimapLineHeight(renderMinimap, this._options.fontScale); + const characterWidth = getMinimapCharWidth(renderMinimap, this._options.fontScale); const tabSize = this._context.model.getOptions().tabSize; const canvasContext = this._decorationsCanvas.domNode.getContext('2d')!; @@ -842,7 +887,7 @@ export class Minimap extends ViewPart { const renderMinimap = this._options.renderMinimap; const startLineNumber = layout.startLineNumber; const endLineNumber = layout.endLineNumber; - const minimapLineHeight = getMinimapLineHeight(renderMinimap); + const minimapLineHeight = getMinimapLineHeight(renderMinimap, this._options.fontScale); // Check if nothing changed w.r.t. lines from last frame if (this._lastRenderData && this._lastRenderData.linesEquals(layout)) { @@ -881,10 +926,11 @@ export class Minimap extends ViewPart { useLighterFont, renderMinimap, this._tokensColorTracker, - getOrCreateMinimapCharRenderer(), + this._options.charRenderer, dy, tabSize, - lineInfo.data[lineIndex]! + lineInfo.data[lineIndex]!, + this._options.fontScale ); } renderedLines[lineIndex] = new MinimapLine(dy); @@ -1008,11 +1054,12 @@ export class Minimap extends ViewPart { minimapCharRenderer: MinimapCharRenderer, dy: number, tabSize: number, - lineData: ViewLineData + lineData: ViewLineData, + fontScale: number ): void { const content = lineData.content; const tokens = lineData.tokens; - const charWidth = getMinimapCharWidth(renderMinimap); + const charWidth = getMinimapCharWidth(renderMinimap, fontScale); const maxDx = target.width - charWidth; let dx = 0; @@ -1044,16 +1091,12 @@ export class Minimap extends ViewPart { const count = strings.isFullWidthCharacter(charCode) ? 2 : 1; for (let i = 0; i < count; i++) { - if (renderMinimap === RenderMinimap.Large) { - minimapCharRenderer.x2RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont); - } else if (renderMinimap === RenderMinimap.Small) { - minimapCharRenderer.x1RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont); - } else if (renderMinimap === RenderMinimap.LargeBlocks) { - minimapCharRenderer.x2BlockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont); - } else { - // RenderMinimap.SmallBlocks - minimapCharRenderer.x1BlockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont); + if (renderMinimap === RenderMinimap.Blocks) { + minimapCharRenderer.blockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont); + } else { // RenderMinimap.Text + minimapCharRenderer.renderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont); } + dx += charWidth; if (dx > maxDx) { diff --git a/src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts b/src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts new file mode 100644 index 00000000000..e1136ab6c28 --- /dev/null +++ b/src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts @@ -0,0 +1,121 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { RGBA8 } from 'vs/editor/common/core/rgba'; +import { Constants, getCharIndex } from './minimapCharSheet'; + +export class MinimapCharRenderer { + _minimapCharRendererBrand: void; + + private readonly charDataNormal: Uint8ClampedArray; + private readonly charDataLight: Uint8ClampedArray; + + constructor(charData: Uint8ClampedArray, public readonly scale: number) { + this.charDataNormal = MinimapCharRenderer.soften(charData, 12 / 15); + this.charDataLight = MinimapCharRenderer.soften(charData, 50 / 60); + } + + private static soften(input: Uint8ClampedArray, ratio: number): Uint8ClampedArray { + let result = new Uint8ClampedArray(input.length); + for (let i = 0, len = input.length; i < len; i++) { + result[i] = input[i] * ratio; + } + return result; + } + + public renderChar( + target: ImageData, + dx: number, + dy: number, + chCode: number, + color: RGBA8, + backgroundColor: RGBA8, + useLighterFont: boolean + ): void { + const charWidth = Constants.BASE_CHAR_WIDTH * this.scale; + const charHeight = Constants.BASE_CHAR_HEIGHT * this.scale; + if (dx + charWidth > target.width || dy + charHeight > target.height) { + console.warn('bad render request outside image data'); + return; + } + + const charData = useLighterFont ? this.charDataLight : this.charDataNormal; + const charIndex = getCharIndex(chCode); + + const destWidth = target.width * Constants.RGBA_CHANNELS_CNT; + + const backgroundR = backgroundColor.r; + const backgroundG = backgroundColor.g; + const backgroundB = backgroundColor.b; + + const deltaR = color.r - backgroundR; + const deltaG = color.g - backgroundG; + const deltaB = color.b - backgroundB; + + const dest = target.data; + let sourceOffset = charIndex * charWidth * charHeight; + + let row = dy * destWidth + dx * Constants.RGBA_CHANNELS_CNT; + for (let y = 0; y < charHeight; y++) { + let column = row; + for (let x = 0; x < charWidth; x++) { + const c = charData[sourceOffset++] / 255; + dest[column++] = backgroundR + deltaR * c; + dest[column++] = backgroundG + deltaG * c; + dest[column++] = backgroundB + deltaB * c; + column++; + } + + row += destWidth; + } + } + + public blockRenderChar( + target: ImageData, + dx: number, + dy: number, + color: RGBA8, + backgroundColor: RGBA8, + useLighterFont: boolean + ): void { + const charWidth = Constants.BASE_CHAR_WIDTH * this.scale; + const charHeight = Constants.BASE_CHAR_HEIGHT * this.scale; + if (dx + charWidth > target.width || dy + charHeight > target.height) { + console.warn('bad render request outside image data'); + return; + } + + const destWidth = target.width * Constants.RGBA_CHANNELS_CNT; + + const c = 0.5; + + const backgroundR = backgroundColor.r; + const backgroundG = backgroundColor.g; + const backgroundB = backgroundColor.b; + + const deltaR = color.r - backgroundR; + const deltaG = color.g - backgroundG; + const deltaB = color.b - backgroundB; + + const colorR = backgroundR + deltaR * c; + const colorG = backgroundG + deltaG * c; + const colorB = backgroundB + deltaB * c; + + const dest = target.data; + + let row = dy * destWidth + dx * Constants.RGBA_CHANNELS_CNT; + for (let y = 0; y < charHeight; y++) { + let column = row; + for (let x = 0; x < charWidth; x++) { + dest[column++] = colorR; + dest[column++] = colorG; + dest[column++] = colorB; + column++; + } + + row += destWidth; + } + } +} diff --git a/src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts b/src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts new file mode 100644 index 00000000000..b0b91e2bca0 --- /dev/null +++ b/src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts @@ -0,0 +1,161 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { MinimapCharRenderer } from 'vs/editor/browser/viewParts/minimap/minimapCharRenderer'; +import { allCharCodes } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet'; +import { Constants } from './minimapCharSheet'; + +/** + * Creates character renderers. It takes a 'scale' that determines how large + * characters should be drawn. Using this, it draws data into a canvas and + * then downsamples the characters as necessary for the current display. + * This makes rendering more efficient, rather than drawing a full (tiny) + * font, or downsampling in real-time. + */ +export class MinimapCharRendererFactory { + private static lastCreated?: MinimapCharRenderer; + private static lastFontFamily?: string; + + /** + * Creates a new character renderer factory with the given scale. + */ + public static create(scale: number, fontFamily: string) { + // renderers are immutable. By default we'll 'create' a new minimap + // character renderer whenever we switch editors, no need to do extra work. + if (this.lastCreated && scale === this.lastCreated.scale && fontFamily === this.lastFontFamily) { + return this.lastCreated; + } + + const factory = MinimapCharRendererFactory.createFromSampleData( + MinimapCharRendererFactory.createSampleData(fontFamily).data, + scale + ); + this.lastFontFamily = fontFamily; + this.lastCreated = factory; + return factory; + } + + /** + * Creates the font sample data, writing to a canvas. + */ + public static createSampleData(fontFamily: string): ImageData { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d')!; + + canvas.style.height = `${Constants.SAMPLED_CHAR_HEIGHT}px`; + canvas.height = Constants.SAMPLED_CHAR_HEIGHT; + canvas.width = Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH; + canvas.style.width = Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH + 'px'; + + ctx.fillStyle = '#ffffff'; + ctx.font = `bold ${Constants.SAMPLED_CHAR_HEIGHT}px ${fontFamily}`; + ctx.textBaseline = 'middle'; + + let x = 0; + for (const code of allCharCodes) { + ctx.fillText(String.fromCharCode(code), x, Constants.SAMPLED_CHAR_HEIGHT / 2); + x += Constants.SAMPLED_CHAR_WIDTH; + } + + return ctx.getImageData(0, 0, Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH, Constants.SAMPLED_CHAR_HEIGHT); + } + + /** + * Creates a character renderer from the canvas sample data. + */ + public static createFromSampleData(source: Uint8ClampedArray, scale: number): MinimapCharRenderer { + const expectedLength = + Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT; + if (source.length !== expectedLength) { + throw new Error('Unexpected source in MinimapCharRenderer'); + } + + let charData = MinimapCharRendererFactory._downsample(source, scale); + return new MinimapCharRenderer(charData, scale); + } + + private static _downsampleChar( + source: Uint8ClampedArray, + sourceOffset: number, + dest: Uint8ClampedArray, + destOffset: number, + scale: number + ): number { + const width = Constants.BASE_CHAR_WIDTH * scale; + const height = Constants.BASE_CHAR_HEIGHT * scale; + + let targetIndex = destOffset; + let brightest = 0; + + // This is essentially an ad-hoc rescaling algorithm. Standard approaches + // like bicubic interpolation are awesome for scaling between image sizes, + // but don't work so well when scaling to very small pixel values, we end + // up with blurry, indistinct forms. + // + // The approach taken here is simply mapping each source pixel to the target + // pixels, and taking the weighted values for all pixels in each, and then + // averaging them out. Finally we apply an intensity boost in _downsample, + // since when scaling to the smallest pixel sizes there's more black space + // which causes characters to be much less distinct. + for (let y = 0; y < height; y++) { + // 1. For this destination pixel, get the source pixels we're sampling + // from (x1, y1) to the next pixel (x2, y2) + const sourceY1 = (y / height) * Constants.SAMPLED_CHAR_HEIGHT; + const sourceY2 = ((y + 1) / height) * Constants.SAMPLED_CHAR_HEIGHT; + + for (let x = 0; x < width; x++) { + const sourceX1 = (x / width) * Constants.SAMPLED_CHAR_WIDTH; + const sourceX2 = ((x + 1) / width) * Constants.SAMPLED_CHAR_WIDTH; + + // 2. Sample all of them, summing them up and weighting them. Similar + // to bilinear interpolation. + let value = 0; + let samples = 0; + for (let sy = sourceY1; sy < sourceY2; sy++) { + const sourceRow = sourceOffset + Math.floor(sy) * Constants.RGBA_SAMPLED_ROW_WIDTH; + const yBalance = 1 - (sy - Math.floor(sy)); + for (let sx = sourceX1; sx < sourceX2; sx++) { + const xBalance = 1 - (sx - Math.floor(sx)); + const sourceIndex = sourceRow + Math.floor(sx) * Constants.RGBA_CHANNELS_CNT; + + const weight = xBalance * yBalance; + samples += weight; + value += ((source[sourceIndex] * source[sourceIndex + 3]) / 255) * weight; + } + } + + const final = value / samples; + brightest = Math.max(brightest, final); + dest[targetIndex++] = final; + } + } + + return brightest; + } + + private static _downsample(data: Uint8ClampedArray, scale: number): Uint8ClampedArray { + const pixelsPerCharacter = Constants.BASE_CHAR_HEIGHT * scale * Constants.BASE_CHAR_WIDTH * scale; + const resultLen = pixelsPerCharacter * Constants.CHAR_COUNT; + const result = new Uint8ClampedArray(resultLen); + + let resultOffset = 0; + let sourceOffset = 0; + let brightest = 0; + for (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) { + brightest = Math.max(brightest, this._downsampleChar(data, sourceOffset, result, resultOffset, scale)); + resultOffset += pixelsPerCharacter; + sourceOffset += Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT; + } + + if (brightest > 0) { + const adjust = 255 / brightest; + for (let i = 0; i < resultLen; i++) { + result[i] *= adjust; + } + } + + return result; + } +} diff --git a/src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts b/src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts new file mode 100644 index 00000000000..af7b0eae4f8 --- /dev/null +++ b/src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export const enum Constants { + START_CH_CODE = 32, // Space + END_CH_CODE = 126, // Tilde (~) + UNKNOWN_CODE = 65533, // UTF placeholder code + CHAR_COUNT = END_CH_CODE - START_CH_CODE + 2, + + SAMPLED_CHAR_HEIGHT = 16, + SAMPLED_CHAR_WIDTH = 10, + + BASE_CHAR_HEIGHT = 2, + BASE_CHAR_WIDTH = 1, + + RGBA_CHANNELS_CNT = 4, + RGBA_SAMPLED_ROW_WIDTH = RGBA_CHANNELS_CNT * CHAR_COUNT * SAMPLED_CHAR_WIDTH +} + +export const allCharCodes: ReadonlyArray = (() => { + const v: number[] = []; + for (let i = Constants.START_CH_CODE; i <= Constants.END_CH_CODE; i++) { + v.push(i); + } + + v.push(Constants.UNKNOWN_CODE); + return v; +})(); + +export const getCharIndex = (chCode: number) => { + chCode -= Constants.START_CH_CODE; + if (chCode < 0 || chCode > Constants.CHAR_COUNT) { + return Constants.CHAR_COUNT - 1; // unknown symbol + } + + return chCode; +}; diff --git a/src/vs/editor/browser/viewParts/selections/selections.ts b/src/vs/editor/browser/viewParts/selections/selections.ts index f059e95dbb1..fa2dd722033 100644 --- a/src/vs/editor/browser/viewParts/selections/selections.ts +++ b/src/vs/editor/browser/viewParts/selections/selections.ts @@ -278,13 +278,17 @@ export class SelectionsOverlay extends DynamicViewOverlay { ); } - private _actualRenderOneSelection(output2: string[], visibleStartLineNumber: number, hasMultipleSelections: boolean, visibleRanges: LineVisibleRangesWithStyle[]): void { - const visibleRangesHaveStyle = (visibleRanges.length > 0 && visibleRanges[0].ranges[0].startStyle); + private _actualRenderOneSelection(output2: [string, string][], visibleStartLineNumber: number, hasMultipleSelections: boolean, visibleRanges: LineVisibleRangesWithStyle[]): void { + if (visibleRanges.length === 0) { + return; + } + + const visibleRangesHaveStyle = !!visibleRanges[0].ranges[0].startStyle; const fullLineHeight = (this._lineHeight).toString(); const reducedLineHeight = (this._lineHeight - 1).toString(); - const firstLineNumber = (visibleRanges.length > 0 ? visibleRanges[0].lineNumber : 0); - const lastLineNumber = (visibleRanges.length > 0 ? visibleRanges[visibleRanges.length - 1].lineNumber : 0); + const firstLineNumber = visibleRanges[0].lineNumber; + const lastLineNumber = visibleRanges[visibleRanges.length - 1].lineNumber; for (let i = 0, len = visibleRanges.length; i < len; i++) { const lineVisibleRanges = visibleRanges[i]; @@ -294,7 +298,8 @@ export class SelectionsOverlay extends DynamicViewOverlay { const lineHeight = hasMultipleSelections ? (lineNumber === lastLineNumber || lineNumber === firstLineNumber ? reducedLineHeight : fullLineHeight) : fullLineHeight; const top = hasMultipleSelections ? (lineNumber === firstLineNumber ? 1 : 0) : 0; - let lineOutput = ''; + let innerCornerOutput = ''; + let restOfSelectionOutput = ''; for (let j = 0, lenJ = lineVisibleRanges.ranges.length; j < lenJ; j++) { const visibleRange = lineVisibleRanges.ranges[j]; @@ -306,7 +311,7 @@ export class SelectionsOverlay extends DynamicViewOverlay { // Reverse rounded corner to the left // First comes the selection (blue layer) - lineOutput += this._createSelectionPiece(top, lineHeight, SelectionsOverlay.SELECTION_CLASS_NAME, visibleRange.left - SelectionsOverlay.ROUNDED_PIECE_WIDTH, SelectionsOverlay.ROUNDED_PIECE_WIDTH); + innerCornerOutput += this._createSelectionPiece(top, lineHeight, SelectionsOverlay.SELECTION_CLASS_NAME, visibleRange.left - SelectionsOverlay.ROUNDED_PIECE_WIDTH, SelectionsOverlay.ROUNDED_PIECE_WIDTH); // Second comes the background (white layer) with inverse border radius let className = SelectionsOverlay.EDITOR_BACKGROUND_CLASS_NAME; @@ -316,13 +321,13 @@ export class SelectionsOverlay extends DynamicViewOverlay { if (startStyle.bottom === CornerStyle.INTERN) { className += ' ' + SelectionsOverlay.SELECTION_BOTTOM_RIGHT; } - lineOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left - SelectionsOverlay.ROUNDED_PIECE_WIDTH, SelectionsOverlay.ROUNDED_PIECE_WIDTH); + innerCornerOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left - SelectionsOverlay.ROUNDED_PIECE_WIDTH, SelectionsOverlay.ROUNDED_PIECE_WIDTH); } if (endStyle.top === CornerStyle.INTERN || endStyle.bottom === CornerStyle.INTERN) { // Reverse rounded corner to the right // First comes the selection (blue layer) - lineOutput += this._createSelectionPiece(top, lineHeight, SelectionsOverlay.SELECTION_CLASS_NAME, visibleRange.left + visibleRange.width, SelectionsOverlay.ROUNDED_PIECE_WIDTH); + innerCornerOutput += this._createSelectionPiece(top, lineHeight, SelectionsOverlay.SELECTION_CLASS_NAME, visibleRange.left + visibleRange.width, SelectionsOverlay.ROUNDED_PIECE_WIDTH); // Second comes the background (white layer) with inverse border radius let className = SelectionsOverlay.EDITOR_BACKGROUND_CLASS_NAME; @@ -332,7 +337,7 @@ export class SelectionsOverlay extends DynamicViewOverlay { if (endStyle.bottom === CornerStyle.INTERN) { className += ' ' + SelectionsOverlay.SELECTION_BOTTOM_LEFT; } - lineOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left + visibleRange.width, SelectionsOverlay.ROUNDED_PIECE_WIDTH); + innerCornerOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left + visibleRange.width, SelectionsOverlay.ROUNDED_PIECE_WIDTH); } } @@ -353,22 +358,26 @@ export class SelectionsOverlay extends DynamicViewOverlay { className += ' ' + SelectionsOverlay.SELECTION_BOTTOM_RIGHT; } } - lineOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left, visibleRange.width); + restOfSelectionOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left, visibleRange.width); } - output2[lineIndex] += lineOutput; + output2[lineIndex][0] += innerCornerOutput; + output2[lineIndex][1] += restOfSelectionOutput; } } private _previousFrameVisibleRangesWithStyle: (LineVisibleRangesWithStyle[] | null)[] = []; public prepareRender(ctx: RenderingContext): void { - const output: string[] = []; + // Build HTML for inner corners separate from HTML for the the rest of selections, + // as the inner corner HTML can interfere with that of other selections. + // In final render, make sure to place the inner corner HTML before the rest of selection HTML. See issue #77777. + const output: [string, string][] = []; const visibleStartLineNumber = ctx.visibleRange.startLineNumber; const visibleEndLineNumber = ctx.visibleRange.endLineNumber; for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) { const lineIndex = lineNumber - visibleStartLineNumber; - output[lineIndex] = ''; + output[lineIndex] = ['', '']; } const thisFrameVisibleRangesWithStyle: (LineVisibleRangesWithStyle[] | null)[] = []; @@ -385,7 +394,7 @@ export class SelectionsOverlay extends DynamicViewOverlay { } this._previousFrameVisibleRangesWithStyle = thisFrameVisibleRangesWithStyle; - this._renderResult = output; + this._renderResult = output.map(([internalCorners, restOfSelection]) => internalCorners + restOfSelection); } public render(startLineNumber: number, lineNumber: number): string { diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts index 09648af24a8..6173ba7a6fa 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts @@ -118,49 +118,57 @@ export class ViewCursor { private _prepareRender(ctx: RenderingContext): ViewCursorRenderData | null { let textContent = ''; - let textContentClassName = ''; if (this._cursorStyle === TextEditorCursorStyle.Line || this._cursorStyle === TextEditorCursorStyle.LineThin) { const visibleRange = ctx.visibleRangeForPosition(this._position); - if (!visibleRange) { + if (!visibleRange || visibleRange.outsideRenderedLine) { // Outside viewport return null; } + let width: number; if (this._cursorStyle === TextEditorCursorStyle.Line) { width = dom.computeScreenAwareSize(this._lineCursorWidth > 0 ? this._lineCursorWidth : 2); if (width > 2) { const lineContent = this._context.model.getLineContent(this._position.lineNumber); - textContent = lineContent.charAt(this._position.column - 1); + const nextCharLength = strings.nextCharLength(lineContent, this._position.column - 1); + textContent = lineContent.substr(this._position.column - 1, nextCharLength); } } else { width = dom.computeScreenAwareSize(1); } + let left = visibleRange.left; if (width >= 2 && left >= 1) { // try to center cursor left -= 1; } + const top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta; - return new ViewCursorRenderData(top, left, width, this._lineHeight, textContent, textContentClassName); + return new ViewCursorRenderData(top, left, width, this._lineHeight, textContent, ''); } - const visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(this._position.lineNumber, this._position.column, this._position.lineNumber, this._position.column + 1), false); - - if (!visibleRangeForCharacter || visibleRangeForCharacter.length === 0 || visibleRangeForCharacter[0].ranges.length === 0) { + const lineContent = this._context.model.getLineContent(this._position.lineNumber); + const nextCharLength = strings.nextCharLength(lineContent, this._position.column - 1); + const visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(this._position.lineNumber, this._position.column, this._position.lineNumber, this._position.column + nextCharLength), false); + if (!visibleRangeForCharacter || visibleRangeForCharacter.length === 0) { // Outside viewport return null; } - const range = visibleRangeForCharacter[0].ranges[0]; + const firstVisibleRangeForCharacter = visibleRangeForCharacter[0]; + if (firstVisibleRangeForCharacter.outsideRenderedLine || firstVisibleRangeForCharacter.ranges.length === 0) { + // Outside viewport + return null; + } + + const range = firstVisibleRangeForCharacter.ranges[0]; const width = range.width < 1 ? this._typicalHalfwidthCharacterWidth : range.width; + let textContentClassName = ''; if (this._cursorStyle === TextEditorCursorStyle.Block) { const lineData = this._context.model.getViewLineData(this._position.lineNumber); - textContent = lineData.content.charAt(this._position.column - 1); - if (strings.isHighSurrogate(lineData.content.charCodeAt(this._position.column - 1))) { - textContent += lineData.content.charAt(this._position.column); - } + textContent = lineContent.substr(this._position.column - 1, nextCharLength); const tokenIndex = lineData.tokens.findTokenIndexAtOffset(this._position.column - 1); textContentClassName = lineData.tokens.getClassName(tokenIndex); } diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts index c60e020b56f..a703cbafd2b 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts @@ -18,7 +18,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic export class ViewCursors extends ViewPart { - static BLINK_INTERVAL = 500; + static readonly BLINK_INTERVAL = 500; private _readOnly: boolean; private _cursorBlinking: TextEditorCursorBlinkingStyle; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 02bf4c731fd..f387c1308e8 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/editor'; -import 'vs/css!./media/tokens'; import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -18,12 +17,12 @@ import { Schemas } from 'vs/base/common/network'; import { Configuration } from 'vs/editor/browser/config/configuration'; import { CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; -import { EditorExtensionsRegistry, IEditorContributionCtor } from 'vs/editor/browser/editorExtensions'; +import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ICommandDelegate } from 'vs/editor/browser/view/viewController'; import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl'; import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents'; -import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions'; import { Cursor, CursorStateChangedEvent } from 'vs/editor/common/controller/cursor'; import { CursorColumns, ICursors } from 'vs/editor/common/controller/cursorCommon'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -67,7 +66,7 @@ export interface ICodeEditorWidgetOptions { * Contributions to instantiate. * Defaults to EditorExtensionsRegistry.getEditorContributions(). */ - contributions?: IEditorContributionCtor[]; + contributions?: IEditorContributionDescription[]; /** * Telemetry data associated with this CodeEditorWidget. @@ -236,7 +235,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE constructor( domElement: HTMLElement, - options: IEditorOptions, + options: IEditorConstructionOptions, codeEditorWidgetOptions: ICodeEditorWidgetOptions, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @@ -294,17 +293,16 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._contentWidgets = {}; this._overlayWidgets = {}; - let contributions: IEditorContributionCtor[]; + let contributions: IEditorContributionDescription[]; if (Array.isArray(codeEditorWidgetOptions.contributions)) { contributions = codeEditorWidgetOptions.contributions; } else { contributions = EditorExtensionsRegistry.getEditorContributions(); } - for (let i = 0, len = contributions.length; i < len; i++) { - const ctor = contributions[i]; + for (const desc of contributions) { try { - const contribution = this._instantiationService.createInstance(ctor, this); - this._contributions[contribution.getId()] = contribution; + const contribution = this._instantiationService.createInstance(desc.ctor, this); + this._contributions[desc.id] = contribution; } catch (err) { onUnexpectedError(err); } @@ -329,7 +327,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._codeEditorService.addCodeEditor(this); } - protected _createConfiguration(options: IEditorOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration { + protected _createConfiguration(options: IEditorConstructionOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration { return new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService); } @@ -500,6 +498,17 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return CursorColumns.visibleColumnFromColumn(this._modelData.model.getLineContent(position.lineNumber), position.column, tabSize) + 1; } + public getStatusbarColumn(rawPosition: IPosition): number { + if (!this._modelData) { + return rawPosition.column; + } + + const position = this._modelData.model.validatePosition(rawPosition); + const tabSize = this._modelData.model.getOptions().tabSize; + + return CursorColumns.toStatusbarColumn(this._modelData.model.getLineContent(position.lineNumber), position.column, tabSize); + } + public getPosition(): Position | null { if (!this._modelData) { return null; @@ -1361,6 +1370,9 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const e2: ICursorSelectionChangedEvent = { selection: e.selections[0], secondarySelections: e.selections.slice(1), + modelVersionId: e.modelVersionId, + oldSelections: e.oldSelections, + oldModelVersionId: e.oldModelVersionId, source: e.source, reason: e.reason }; diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index ef815de2219..0bd9f2788ff 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -20,7 +20,7 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffReview } from 'vs/editor/browser/widget/diffReview'; -import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions, EditorFontLigatures } 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 { ISelection, Selection } from 'vs/editor/common/core/selection'; @@ -43,6 +43,10 @@ import { ITheme, IThemeService, getThemeTypeSelector, registerThemingParticipant import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IDiffLinesChange, InlineDiffMargin } from 'vs/editor/browser/widget/inlineDiffMargin'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { Constants } from 'vs/base/common/uint'; +import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; interface IEditorDiffDecorations { decorations: IModelDeltaDecoration[]; @@ -164,6 +168,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE public readonly onDidUpdateDiff: Event = this._onDidUpdateDiff.event; private readonly id: number; + private _state: editorBrowser.DiffEditorState; + private _updatingDiffProgress: IProgressRunner | null; private readonly _domElement: HTMLElement; protected readonly _containerDomElement: HTMLElement; @@ -197,6 +203,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE private _originalIsEditable: boolean; private _renderSideBySide: boolean; + private _maxComputationTime: number; private _renderIndicators: boolean; private _enableSplitViewResizing: boolean; private _strategy!: IDiffEditorWidgetStyle; @@ -222,6 +229,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE @IThemeService themeService: IThemeService, @INotificationService notificationService: INotificationService, @IContextMenuService contextMenuService: IContextMenuService, + @IEditorProgressService private readonly _editorProgressService: IEditorProgressService ) { super(); @@ -233,6 +241,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._notificationService = notificationService; this.id = (++DIFF_EDITOR_ID); + this._state = editorBrowser.DiffEditorState.Idle; + this._updatingDiffProgress = null; this._domElement = domElement; options = options || {}; @@ -243,6 +253,12 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._renderSideBySide = options.renderSideBySide; } + // maxComputationTime + this._maxComputationTime = 5000; + if (typeof options.maxComputationTime !== 'undefined') { + this._maxComputationTime = options.maxComputationTime; + } + // ignoreTrimWhitespace this._ignoreTrimWhitespace = true; if (typeof options.ignoreTrimWhitespace !== 'undefined') { @@ -364,6 +380,15 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getTheme(), this._renderSideBySide); })); + const contributions: IDiffEditorContributionDescription[] = EditorExtensionsRegistry.getDiffEditorContributions(); + for (const desc of contributions) { + try { + this._register(instantiationService.createInstance(desc.ctor, this)); + } catch (err) { + onUnexpectedError(err); + } + } + this._codeEditorService.addDiffEditor(this); } @@ -375,10 +400,30 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return this._renderSideBySide; } + public get maxComputationTime(): number { + return this._maxComputationTime; + } + public get renderIndicators(): boolean { return this._renderIndicators; } + private _setState(newState: editorBrowser.DiffEditorState): void { + if (this._state === newState) { + return; + } + this._state = newState; + + if (this._updatingDiffProgress) { + this._updatingDiffProgress.done(); + this._updatingDiffProgress = null; + } + + if (this._state === editorBrowser.DiffEditorState.ComputingDiff) { + this._updatingDiffProgress = this._editorProgressService.show(true, 1000); + } + } + public hasWidgetFocus(): boolean { return dom.isAncestor(document.activeElement, this._domElement); } @@ -491,6 +536,12 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } })); + this._register(editor.onDidChangeModelOptions((e) => { + if (e.tabSize) { + this._updateDecorationsRunner.schedule(); + } + })); + return editor; } @@ -560,6 +611,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return this._diffComputationResult.changes; } + public getDiffComputationResult(): IDiffComputationResult | null { + return this._diffComputationResult; + } + public getOriginalEditor(): editorBrowser.ICodeEditor { return this.originalEditor; } @@ -579,6 +634,13 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } } + if (typeof newOptions.maxComputationTime !== 'undefined') { + this._maxComputationTime = newOptions.maxComputationTime; + if (this._isVisible) { + this._beginUpdateDecorationsSoon(); + } + } + let beginUpdateDecorations = false; if (typeof newOptions.ignoreTrimWhitespace !== 'undefined') { @@ -646,6 +708,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this.modifiedEditor.setModel(model ? model.modified : null); this._updateDecorationsRunner.cancel(); + // this.originalEditor.onDidChangeModelOptions + if (model) { this.originalEditor.setScrollTop(0); this.modifiedEditor.setScrollTop(0); @@ -654,14 +718,13 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE // Disable any diff computations that will come in this._diffComputationResult = null; this._diffComputationToken++; + this._setState(editorBrowser.DiffEditorState.Idle); if (model) { this._recreateOverviewRulers(); // Begin comparing this._beginUpdateDecorations(); - } else { - this._diffComputationResult = null; } this._layoutOverviewViewport(); @@ -675,6 +738,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return this.modifiedEditor.getVisibleColumnFromPosition(position); } + public getStatusbarColumn(position: IPosition): number { + return this.modifiedEditor.getStatusbarColumn(position); + } + public getPosition(): Position | null { return this.modifiedEditor.getPosition(); } @@ -909,6 +976,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE // yet supported, so using tokens for now. this._diffComputationToken++; let currentToken = this._diffComputationToken; + this._setState(editorBrowser.DiffEditorState.ComputingDiff); if (!this._editorWorkerService.canComputeDiff(currentOriginalModel.uri, currentModifiedModel.uri)) { if ( @@ -922,11 +990,12 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return; } - this._editorWorkerService.computeDiff(currentOriginalModel.uri, currentModifiedModel.uri, this._ignoreTrimWhitespace).then((result) => { + this._editorWorkerService.computeDiff(currentOriginalModel.uri, currentModifiedModel.uri, this._ignoreTrimWhitespace, this._maxComputationTime).then((result) => { if (currentToken === this._diffComputationToken && currentOriginalModel === this.originalEditor.getModel() && currentModifiedModel === this.modifiedEditor.getModel() ) { + this._setState(editorBrowser.DiffEditorState.DiffComputed); this._diffComputationResult = result; this._updateDecorationsRunner.schedule(); this._onDidUpdateDiff.fire(); @@ -936,6 +1005,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE && currentOriginalModel === this.originalEditor.getModel() && currentModifiedModel === this.modifiedEditor.getModel() ) { + this._setState(editorBrowser.DiffEditorState.DiffComputed); this._diffComputationResult = null; this._updateDecorationsRunner.schedule(); } @@ -989,7 +1059,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE private _adjustOptionsForLeftHandSide(options: IDiffEditorOptions, isEditable: boolean): IEditorOptions { let result = this._adjustOptionsForSubEditor(options); result.readOnly = !isEditable; - result.overviewRulerLanes = 1; result.extraEditorClassName = 'original-in-monaco-diff-editor'; return result; } @@ -1122,7 +1191,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE while (min < max) { let mid = Math.floor((min + max) / 2); let midStart = startLineNumberExtractor(lineChanges[mid]); - let midEnd = (mid + 1 <= max ? startLineNumberExtractor(lineChanges[mid + 1]) : Number.MAX_VALUE); + let midEnd = (mid + 1 <= max ? startLineNumberExtractor(lineChanges[mid + 1]) : Constants.MAX_SAFE_SMALL_INTEGER); if (lineNumber < midStart) { max = mid - 1; @@ -1562,7 +1631,7 @@ const DECORATIONS = { class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle, IVerticalSashLayoutProvider { - static MINIMUM_EDITOR_WIDTH = 100; + static readonly MINIMUM_EDITOR_WIDTH = 100; private _disableSash: boolean; private readonly _sash: Sash; @@ -1682,11 +1751,11 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffE if (isChangeOrDelete(lineChange)) { result.decorations.push({ - range: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Number.MAX_VALUE), + range: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER), options: (renderIndicators ? DECORATIONS.lineDeleteWithSign : DECORATIONS.lineDelete) }); if (!isChangeOrInsert(lineChange) || !lineChange.charChanges) { - result.decorations.push(createDecoration(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Number.MAX_VALUE, DECORATIONS.charDeleteWholeLine)); + result.decorations.push(createDecoration(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charDeleteWholeLine)); } result.overviewZones.push(new OverviewRulerZone( @@ -1743,11 +1812,11 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffE if (isChangeOrInsert(lineChange)) { result.decorations.push({ - range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Number.MAX_VALUE), + range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER), options: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert) }); if (!isChangeOrDelete(lineChange) || !lineChange.charChanges) { - result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Number.MAX_VALUE, DECORATIONS.charInsertWholeLine)); + result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charInsertWholeLine)); } result.overviewZones.push(new OverviewRulerZone( lineChange.modifiedStartLineNumber, @@ -1861,7 +1930,7 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito // Add overview zones in the overview ruler if (isChangeOrDelete(lineChange)) { result.decorations.push({ - range: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Number.MAX_VALUE), + range: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER), options: DECORATIONS.lineDeleteMargin }); @@ -1892,7 +1961,7 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito // Add decorations & overview zones if (isChangeOrInsert(lineChange)) { result.decorations.push({ - range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Number.MAX_VALUE), + range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER), options: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert) }); @@ -1928,7 +1997,7 @@ class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEdito } } } else { - result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Number.MAX_VALUE, DECORATIONS.charInsertWholeLine)); + result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charInsertWholeLine)); } } } @@ -2060,7 +2129,7 @@ class InlineViewZonesComputer extends ViewZonesComputer { const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL()); const output = renderViewLine(new RenderLineInput( - (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)), + (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)), fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, @@ -2074,7 +2143,7 @@ class InlineViewZonesComputer extends ViewZonesComputer { options.get(EditorOption.stopRenderingLineAfter), options.get(EditorOption.renderWhitespace), options.get(EditorOption.renderControlCharacters), - options.get(EditorOption.fontLigatures), + options.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF, null // Send no selections, original line cannot be selected ), sb); diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index 0f71723805c..8a915a659ff 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -17,7 +17,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; -import { IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { IComputedEditorOptions, EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { Position } from 'vs/editor/common/core/position'; import { ILineChange, ScrollType } from 'vs/editor/common/editorCommon'; @@ -770,7 +770,7 @@ export class DiffReview extends Disposable { const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL()); const r = renderViewLine(new RenderLineInput( - (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)), + (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)), fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, @@ -784,7 +784,7 @@ export class DiffReview extends Disposable { options.get(EditorOption.stopRenderingLineAfter), options.get(EditorOption.renderWhitespace), options.get(EditorOption.renderControlCharacters), - options.get(EditorOption.fontLigatures), + options.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF, null )); diff --git a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts index ef5e39e306e..09a18fcf097 100644 --- a/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts +++ b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts @@ -18,6 +18,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; export class EmbeddedCodeEditorWidget extends CodeEditorWidget { @@ -78,9 +79,10 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget { @IThemeService themeService: IThemeService, @INotificationService notificationService: INotificationService, @IContextMenuService contextMenuService: IContextMenuService, - @IClipboardService clipboardService: IClipboardService + @IClipboardService clipboardService: IClipboardService, + @IEditorProgressService editorProgressService: IEditorProgressService, ) { - super(domElement, parentEditor.getRawOptions(), clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService); + super(domElement, parentEditor.getRawOptions(), clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, editorProgressService); this._parentEditor = parentEditor; this._overwriteOptions = options; diff --git a/src/vs/editor/browser/widget/media/diffReview.css b/src/vs/editor/browser/widget/media/diffReview.css index 4cf9f7b83a4..f8db5bb1c67 100644 --- a/src/vs/editor/browser/widget/media/diffReview.css +++ b/src/vs/editor/browser/widget/media/diffReview.css @@ -10,12 +10,9 @@ .monaco-diff-editor .diff-review { position: absolute; + user-select: none; -webkit-user-select: none; -ms-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -o-user-select: none; - user-select: none; } .monaco-diff-editor .diff-review-summary { @@ -67,4 +64,4 @@ .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-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 fb9e5f5e8b8..7936ff11ad8 100644 --- a/src/vs/editor/browser/widget/media/editor.css +++ b/src/vs/editor/browser/widget/media/editor.css @@ -21,12 +21,6 @@ position: relative; overflow: visible; -webkit-text-size-adjust: 100%; - -webkit-font-feature-settings: "liga" off, "calt" off; - font-feature-settings: "liga" off, "calt" off; -} -.monaco-editor.enable-ligatures { - -webkit-font-feature-settings: "liga" on, "calt" on; - font-feature-settings: "liga" on, "calt" on; } /* -------------------- Misc -------------------- */ diff --git a/src/vs/editor/common/commands/replaceCommand.ts b/src/vs/editor/common/commands/replaceCommand.ts index 6cd736b2adf..4ae44cf28c1 100644 --- a/src/vs/editor/common/commands/replaceCommand.ts +++ b/src/vs/editor/common/commands/replaceCommand.ts @@ -36,6 +36,27 @@ export class ReplaceCommand implements ICommand { } } +export class ReplaceCommandThatSelectsText implements ICommand { + + private readonly _range: Range; + private readonly _text: string; + + constructor(range: Range, text: string) { + this._range = range; + this._text = text; + } + + public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void { + builder.addTrackedEditOperation(this._range, this._text); + } + + public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection { + const inverseEditOperations = helper.getInverseEditOperations(); + const srcRange = inverseEditOperations[0].range; + return new Selection(srcRange.startLineNumber, srcRange.startColumn, srcRange.endLineNumber, srcRange.endColumn); + } +} + export class ReplaceCommandWithoutChangingPosition implements ICommand { private readonly _range: Range; diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index af4f2074ea8..7698dd70ef9 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -15,6 +15,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { forEach } from 'vs/base/common/collections'; /** * Control what pressing Tab does. @@ -197,6 +198,43 @@ function migrateOptions(options: IEditorOptions): void { options.tabCompletion = 'onlySnippets'; } + const suggest = options.suggest; + if (suggest && typeof (suggest).filteredTypes === 'object' && (suggest).filteredTypes) { + const mapping: Record = {}; + mapping['method'] = 'showMethods'; + mapping['function'] = 'showFunctions'; + mapping['constructor'] = 'showConstructors'; + mapping['field'] = 'showFields'; + mapping['variable'] = 'showVariables'; + mapping['class'] = 'showClasses'; + mapping['struct'] = 'showStructs'; + mapping['interface'] = 'showInterfaces'; + mapping['module'] = 'showModules'; + mapping['property'] = 'showProperties'; + mapping['event'] = 'showEvents'; + mapping['operator'] = 'showOperators'; + mapping['unit'] = 'showUnits'; + mapping['value'] = 'showValues'; + mapping['constant'] = 'showConstants'; + mapping['enum'] = 'showEnums'; + mapping['enumMember'] = 'showEnumMembers'; + mapping['keyword'] = 'showKeywords'; + mapping['text'] = 'showWords'; + mapping['color'] = 'showColors'; + mapping['file'] = 'showFiles'; + mapping['reference'] = 'showReferences'; + mapping['folder'] = 'showFolders'; + mapping['typeParameter'] = 'showTypeParameters'; + mapping['snippet'] = 'showSnippets'; + forEach(mapping, entry => { + const value = (suggest).filteredTypes[entry.key]; + if (value === false) { + (suggest)[entry.value] = value; + } + }); + // delete (suggest).filteredTypes; + } + const hover = options.hover; if (hover === true) { options.hover = { @@ -207,6 +245,17 @@ function migrateOptions(options: IEditorOptions): void { enabled: false }; } + + const parameterHints = options.parameterHints; + if (parameterHints === true) { + options.parameterHints = { + enabled: true + }; + } else if (parameterHints === false) { + options.parameterHints = { + enabled: false + }; + } } function deepCloneAndMigrateOptions(_options: IEditorOptions): IEditorOptions { @@ -463,6 +512,11 @@ const editorConfiguration: IConfigurationNode = { default: 750, description: nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled.") }, + 'diffEditor.maxComputationTime': { + type: 'number', + default: 5000, + description: nls.localize('maxComputationTime', "Timeout in milliseconds after which diff computation is cancelled. Use 0 for no timeout.") + }, 'diffEditor.renderSideBySide': { type: 'boolean', default: true, diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 4b9206e1cdd..74c45b792de 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -7,11 +7,11 @@ import * as nls from 'vs/nls'; import * as platform from 'vs/base/common/platform'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; -import { isObject } from 'vs/base/common/types'; import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; +import { IDimension } from 'vs/editor/common/editorCommon'; //#region typed options @@ -70,6 +70,12 @@ export interface IEditorOptions { * Defaults to 0. */ cursorSurroundingLines?: number; + /** + * Controls when `cursorSurroundingLines` should be enforced + * Defaults to `default`, `cursorSurroundingLines` is not enforced when cursor position is changed + * by mouse. + */ + cursorSurroundingLinesStyle?: 'default' | 'all'; /** * Render last line number when the file ends with a newline. * Defaults to true. @@ -136,7 +142,7 @@ export interface IEditorOptions { fixedOverflowWidgets?: boolean; /** * The number of vertical lanes the overview ruler should render. - * Defaults to 2. + * Defaults to 3. */ overviewRulerLanes?: number; /** @@ -177,7 +183,7 @@ export interface IEditorOptions { * Enable font ligatures. * Defaults to false. */ - fontLigatures?: boolean; + fontLigatures?: boolean | string; /** * Disable the use of `will-change` for the editor margin and lines layers. * The usage of `will-change` acts as a hint for browsers to create an extra layer. @@ -516,6 +522,13 @@ export interface IEditorOptions { showUnused?: boolean; } +export interface IEditorConstructionOptions extends IEditorOptions { + /** + * The initial editor dimension (to avoid measuring the container). + */ + dimension?: IDimension; +} + /** * Configuration options for the diff editor. */ @@ -530,6 +543,11 @@ export interface IDiffEditorOptions extends IEditorOptions { * Defaults to true. */ renderSideBySide?: boolean; + /** + * Timeout in milliseconds after which diff computation is cancelled. + * Defaults to 5000. + */ + maxComputationTime?: number; /** * Compute the diff by ignoring leading/trailing whitespace * Defaults to true. @@ -633,6 +651,9 @@ export interface IEditorOption { type PossibleKeyName0 = { [K in keyof IEditorOptions]: IEditorOptions[K] extends V | undefined ? K : never }[keyof IEditorOptions]; type PossibleKeyName = NonNullable>; +/** + * @internal + */ abstract class BaseEditorOption implements IEditorOption { public readonly id: K1; @@ -1036,7 +1057,7 @@ function _cursorStyleFromString(cursorStyle: 'line' | 'block' | 'underline' | 'l class EditorClassName extends ComputedEditorOption { constructor() { - super(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.fontLigatures, EditorOption.extraEditorClassName]); + super(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.extraEditorClassName]); } public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string { @@ -1047,9 +1068,6 @@ class EditorClassName extends ComputedEditorOption constructor() { const defaults: EditorFindOptions = { seedSearchStringFromSelection: true, - autoFindInSelection: false, + autoFindInSelection: 'never', globalFindClipboard: false, addExtraSpaceOnTop: true }; @@ -1124,8 +1142,14 @@ class EditorFind extends BaseEditorOption description: nls.localize('find.seedSearchStringFromSelection', "Controls whether the search string in the Find Widget is seeded from the editor selection.") }, 'editor.find.autoFindInSelection': { - type: 'boolean', + type: 'string', + enum: ['never', 'always', 'multiline'], default: defaults.autoFindInSelection, + enumDescriptions: [ + nls.localize('editor.find.autoFindInSelection.never', 'Never turn on Find in selection automatically (default)'), + nls.localize('editor.find.autoFindInSelection.always', 'Always turn on Find in selection automatically'), + nls.localize('editor.find.autoFindInSelection.multiline', 'Turn on Find in selection automatically when multiple lines of content are selected.') + ], description: nls.localize('find.autoFindInSelection', "Controls whether the find operation is carried out on selected text or the entire file in the editor.") }, 'editor.find.globalFindClipboard': { @@ -1150,7 +1174,9 @@ class EditorFind extends BaseEditorOption const input = _input as IEditorFindOptions; return { seedSearchStringFromSelection: EditorBooleanOption.boolean(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection), - autoFindInSelection: EditorBooleanOption.boolean(input.autoFindInSelection, this.defaultValue.autoFindInSelection), + autoFindInSelection: typeof _input.autoFindInSelection === 'boolean' + ? (_input.autoFindInSelection ? 'always' : 'never') + : EditorStringEnumOption.stringSet<'never' | 'always' | 'multiline'>(input.autoFindInSelection, this.defaultValue.autoFindInSelection, ['never', 'always', 'multiline']), globalFindClipboard: EditorBooleanOption.boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard), addExtraSpaceOnTop: EditorBooleanOption.boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop) }; @@ -1159,6 +1185,58 @@ class EditorFind extends BaseEditorOption //#endregion +//#region fontLigatures + +/** + * @internal + */ +export class EditorFontLigatures extends BaseEditorOption { + + public static OFF = '"liga" off, "calt" off'; + public static ON = '"liga" on, "calt" on'; + + constructor() { + super( + EditorOption.fontLigatures, 'fontLigatures', EditorFontLigatures.OFF, + { + anyOf: [ + { + type: 'boolean', + description: nls.localize('fontLigatures', "Enables/Disables font ligatures."), + }, + { + type: 'string', + description: nls.localize('fontFeatureSettings', "Explicit font-feature-settings.") + } + ], + description: nls.localize('fontLigaturesGeneral', "Configures font ligatures."), + default: false + } + ); + } + + public validate(input: any): string { + if (typeof input === 'undefined') { + return this.defaultValue; + } + if (typeof input === 'string') { + if (input === 'false') { + return EditorFontLigatures.OFF; + } + if (input === 'true') { + return EditorFontLigatures.ON; + } + return input; + } + if (Boolean(input)) { + return EditorFontLigatures.ON; + } + return EditorFontLigatures.OFF; + } +} + +//#endregion + //#region fontInfo class EditorFontInfo extends ComputedEditorOption { @@ -1183,6 +1261,8 @@ class EditorFontSize extends SimpleEditorOption { EditorOption.fontSize, 'fontSize', EDITOR_FONT_DEFAULTS.fontSize, { type: 'number', + minimum: 6, + maximum: 100, default: EDITOR_FONT_DEFAULTS.fontSize, description: nls.localize('fontSize', "Controls the font size in pixels.") } @@ -1194,7 +1274,7 @@ class EditorFontSize extends SimpleEditorOption { if (r === 0) { return EDITOR_FONT_DEFAULTS.fontSize; } - return EditorFloatOption.clamp(r, 8, 100); + return EditorFloatOption.clamp(r, 6, 100); } public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number { // The final fontSize respects the editor zoom level. @@ -1350,10 +1430,8 @@ export interface OverviewRulerPosition { export const enum RenderMinimap { None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4, + Text = 1, + Blocks = 2, } /** @@ -1509,6 +1587,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption= 2 ? Math.round(minimap.scale * 2) : minimap.scale); const minimapMaxColumn = minimap.maxColumn | 0; const scrollbar = options.get(EditorOption.scrollbar); @@ -1559,14 +1638,10 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption= 2) { - renderMinimap = minimapRenderCharacters ? RenderMinimap.Large : RenderMinimap.LargeBlocks; - minimapCharWidth = 2 / pixelRatio; - } else { - renderMinimap = minimapRenderCharacters ? RenderMinimap.Small : RenderMinimap.SmallBlocks; - minimapCharWidth = 1 / pixelRatio; - } + // The minimapScale is also the pixel width of each character. Adjust + // for the pixel ratio of the screen. + const minimapCharWidth = minimapScale / pixelRatio; + renderMinimap = minimapRenderCharacters ? RenderMinimap.Text : RenderMinimap.Blocks; // Given: // (leaving 2px for the cursor to have space after the last character) @@ -1742,6 +1817,11 @@ export interface IEditorMinimapOptions { * Defaults to 120. */ maxColumn?: number; + + /** + * Relative size of the font in the minimap. Defaults to 1. + */ + scale?: number; } export type EditorMinimapOptions = Readonly>; @@ -1755,6 +1835,7 @@ class EditorMinimap extends BaseEditorOption(input.side, this.defaultValue.side, ['right', 'left']), showSlider: EditorStringEnumOption.stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']), renderCharacters: EditorBooleanOption.boolean(input.renderCharacters, this.defaultValue.renderCharacters), + scale: EditorIntOption.clampedInt(input.scale, 1, 1, 3), maxColumn: EditorIntOption.clampedInt(input.maxColumn, this.defaultValue.maxColumn, 1, 10000), }; } @@ -1946,6 +2035,7 @@ class EditorQuickSuggestions extends BaseEditorOption; + showMethods?: boolean; + /** + * Show function-suggestions. + */ + showFunctions?: boolean; + /** + * Show constructor-suggestions. + */ + showConstructors?: boolean; + /** + * Show field-suggestions. + */ + showFields?: boolean; + /** + * Show variable-suggestions. + */ + showVariables?: boolean; + /** + * Show class-suggestions. + */ + showClasses?: boolean; + /** + * Show struct-suggestions. + */ + showStructs?: boolean; + /** + * Show interface-suggestions. + */ + showInterfaces?: boolean; + /** + * Show module-suggestions. + */ + showModules?: boolean; + /** + * Show property-suggestions. + */ + showProperties?: boolean; + /** + * Show event-suggestions. + */ + showEvents?: boolean; + /** + * Show operator-suggestions. + */ + showOperators?: boolean; + /** + * Show unit-suggestions. + */ + showUnits?: boolean; + /** + * Show value-suggestions. + */ + showValues?: boolean; + /** + * Show constant-suggestions. + */ + showConstants?: boolean; + /** + * Show enum-suggestions. + */ + showEnums?: boolean; + /** + * Show enumMember-suggestions. + */ + showEnumMembers?: boolean; + /** + * Show keyword-suggestions. + */ + showKeywords?: boolean; + /** + * Show text-suggestions. + */ + showWords?: boolean; + /** + * Show color-suggestions. + */ + showColors?: boolean; + /** + * Show file-suggestions. + */ + showFiles?: boolean; + /** + * Show reference-suggestions. + */ + showReferences?: boolean; + /** + * Show folder-suggestions. + */ + showFolders?: boolean; + /** + * Show typeParameter-suggestions. + */ + showTypeParameters?: boolean; + /** + * Show snippet-suggestions. + */ + showSnippets?: boolean; } export type InternalSuggestOptions = Readonly>; @@ -2248,17 +2438,47 @@ class EditorSuggest extends BaseEditorOption = this._register(new Emitter()); public readonly onDidReachMaxCursorCount: Event = this._onDidReachMaxCursorCount.event; @@ -173,6 +188,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _isHandling: boolean; private _isDoingComposition: boolean; + private _selectionsWhenCompositionStarted: Selection[] | null; private _columnSelectData: IColumnSelectData | null; private _autoClosedActions: AutoClosedAction[]; private _prevEditOperationType: EditOperationType; @@ -188,6 +204,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isHandling = false; this._isDoingComposition = false; + this._selectionsWhenCompositionStarted = null; this._columnSelectData = null; this._autoClosedActions = []; this._prevEditOperationType = EditOperationType.Other; @@ -538,7 +555,9 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { || oldState.cursorState.length !== newState.cursorState.length || newState.cursorState.some((newCursorState, i) => !newCursorState.modelState.equals(oldState.cursorState[i].modelState)) ) { - this._onDidChange.fire(new CursorStateChangedEvent(selections, source || 'keyboard', reason)); + const oldSelections = oldState ? oldState.cursorState.map(s => s.modelState.selection) : null; + const oldModelVersionId = oldState ? oldState.modelVersionId : 0; + this._onDidChange.fire(new CursorStateChangedEvent(selections, newState.modelVersionId, oldSelections, oldModelVersionId, source || 'keyboard', reason)); } return true; @@ -667,6 +686,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { if (handlerId === H.CompositionStart) { this._isDoingComposition = true; + this._selectionsWhenCompositionStarted = this.getSelections().slice(0); return; } @@ -757,7 +777,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { if (!this._isDoingComposition && source === 'keyboard') { // composition finishes, let's check if we need to auto complete if necessary. const autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions); - this._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters)); + this._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this._selectionsWhenCompositionStarted, this.getSelections(), autoClosedCharacters)); + this._selectionsWhenCompositionStarted = null; } } @@ -765,19 +786,17 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { if (!this._isDoingComposition && source === 'keyboard') { // If this event is coming straight from the keyboard, look for electric characters and enter - for (let i = 0, len = text.length; i < len; i++) { - let charCode = text.charCodeAt(i); - let chr: string; - if (strings.isHighSurrogate(charCode) && i + 1 < len) { - chr = text.charAt(i) + text.charAt(i + 1); - i++; - } else { - chr = text.charAt(i); - } + const len = text.length; + let offset = 0; + while (offset < len) { + const charLength = strings.nextCharLength(text, offset); + const chr = text.substr(offset, charLength); // Here we must interpret each typed character individually const autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions); this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters, chr)); + + offset += charLength; } } else { diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index f5c581c86d0..009744c4ee7 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -19,6 +19,7 @@ import { IAutoClosingPair, StandardAutoClosingPairConditional } from 'vs/editor/ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; +import { Constants } from 'vs/base/common/uint'; export interface IColumnSelectData { isReal: boolean; @@ -509,44 +510,54 @@ export class EditOperationResult { */ export class CursorColumns { - public static isLowSurrogate(model: ICursorSimpleModel, lineNumber: number, charOffset: number): boolean { - let lineContent = model.getLineContent(lineNumber); - if (charOffset < 0 || charOffset >= lineContent.length) { - return false; - } - return strings.isLowSurrogate(lineContent.charCodeAt(charOffset)); - } - - public static isHighSurrogate(model: ICursorSimpleModel, lineNumber: number, charOffset: number): boolean { - let lineContent = model.getLineContent(lineNumber); - if (charOffset < 0 || charOffset >= lineContent.length) { - return false; - } - return strings.isHighSurrogate(lineContent.charCodeAt(charOffset)); - } - - public static isInsideSurrogatePair(model: ICursorSimpleModel, lineNumber: number, column: number): boolean { - return this.isHighSurrogate(model, lineNumber, column - 2); - } - public static visibleColumnFromColumn(lineContent: string, column: number, tabSize: number): number { - let endOffset = lineContent.length; - if (endOffset > column - 1) { - endOffset = column - 1; - } + const lineContentLength = lineContent.length; + const endOffset = column - 1 < lineContentLength ? column - 1 : lineContentLength; let result = 0; - for (let i = 0; i < endOffset; i++) { - let charCode = lineContent.charCodeAt(i); - if (charCode === CharCode.Tab) { - result = this.nextRenderTabStop(result, tabSize); - } else if (strings.isFullWidthCharacter(charCode)) { - result = result + 2; + let i = 0; + while (i < endOffset) { + const codePoint = strings.getNextCodePoint(lineContent, endOffset, i); + i += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + if (codePoint === CharCode.Tab) { + result = CursorColumns.nextRenderTabStop(result, tabSize); + } else { + while (i < endOffset) { + const nextCodePoint = strings.getNextCodePoint(lineContent, endOffset, i); + if (!strings.isUnicodeMark(nextCodePoint)) { + break; + } + i += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) { + result = result + 2; + } else { + result = result + 1; + } + } + } + return result; + } + + public static toStatusbarColumn(lineContent: string, column: number, tabSize: number): number { + const lineContentLength = lineContent.length; + const endOffset = column - 1 < lineContentLength ? column - 1 : lineContentLength; + + let result = 0; + let i = 0; + while (i < endOffset) { + const codePoint = strings.getNextCodePoint(lineContent, endOffset, i); + i += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + if (codePoint === CharCode.Tab) { + result = CursorColumns.nextRenderTabStop(result, tabSize); } else { result = result + 1; } } - return result; + + return result + 1; } public static visibleColumnFromColumn2(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): number { @@ -561,29 +572,43 @@ export class CursorColumns { const lineLength = lineContent.length; let beforeVisibleColumn = 0; - for (let i = 0; i < lineLength; i++) { - let charCode = lineContent.charCodeAt(i); + let beforeColumn = 1; + let i = 0; + while (i < lineLength) { + const codePoint = strings.getNextCodePoint(lineContent, lineLength, i); + i += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); let afterVisibleColumn: number; - if (charCode === CharCode.Tab) { - afterVisibleColumn = this.nextRenderTabStop(beforeVisibleColumn, tabSize); - } else if (strings.isFullWidthCharacter(charCode)) { - afterVisibleColumn = beforeVisibleColumn + 2; + if (codePoint === CharCode.Tab) { + afterVisibleColumn = CursorColumns.nextRenderTabStop(beforeVisibleColumn, tabSize); } else { - afterVisibleColumn = beforeVisibleColumn + 1; + while (i < lineLength) { + const nextCodePoint = strings.getNextCodePoint(lineContent, lineLength, i); + if (!strings.isUnicodeMark(nextCodePoint)) { + break; + } + i += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) { + afterVisibleColumn = beforeVisibleColumn + 2; + } else { + afterVisibleColumn = beforeVisibleColumn + 1; + } } + const afterColumn = i + 1; if (afterVisibleColumn >= visibleColumn) { - let prevDelta = visibleColumn - beforeVisibleColumn; - let afterDelta = afterVisibleColumn - visibleColumn; - if (afterDelta < prevDelta) { - return i + 2; + const beforeDelta = visibleColumn - beforeVisibleColumn; + const afterDelta = afterVisibleColumn - visibleColumn; + if (afterDelta < beforeDelta) { + return afterColumn; } else { - return i + 1; + return beforeColumn; } } beforeVisibleColumn = afterVisibleColumn; + beforeColumn = afterColumn; } // walked the entire string diff --git a/src/vs/editor/common/controller/cursorEvents.ts b/src/vs/editor/common/controller/cursorEvents.ts index a873c2ed70c..eb3418b993f 100644 --- a/src/vs/editor/common/controller/cursorEvents.ts +++ b/src/vs/editor/common/controller/cursorEvents.ts @@ -72,6 +72,18 @@ export interface ICursorSelectionChangedEvent { * The secondary selections. */ readonly secondarySelections: Selection[]; + /** + * The model version id. + */ + readonly modelVersionId: number; + /** + * The old selections. + */ + readonly oldSelections: Selection[] | null; + /** + * The model version id the that `oldSelections` refer to. + */ + readonly oldModelVersionId: number; /** * Source of the call that caused the event. */ diff --git a/src/vs/editor/common/controller/cursorMoveCommands.ts b/src/vs/editor/common/controller/cursorMoveCommands.ts index 938d59028a4..759ad0e19fd 100644 --- a/src/vs/editor/common/controller/cursorMoveCommands.ts +++ b/src/vs/editor/common/controller/cursorMoveCommands.ts @@ -122,20 +122,19 @@ export class CursorMoveCommands { for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - const viewSelection = cursor.viewState.selection; - const startLineNumber = viewSelection.startLineNumber; - const lineCount = context.viewModel.getLineCount(); + const startLineNumber = cursor.modelState.selection.startLineNumber; + const lineCount = context.model.getLineCount(); - let endLineNumber = viewSelection.endLineNumber; + let endLineNumber = cursor.modelState.selection.endLineNumber; let endColumn: number; if (endLineNumber === lineCount) { - endColumn = context.viewModel.getLineMaxColumn(lineCount); + endColumn = context.model.getLineMaxColumn(lineCount); } else { endLineNumber++; endColumn = 1; } - result[i] = CursorState.fromViewState(new SingleCursorState( + result[i] = CursorState.fromModelState(new SingleCursorState( new Range(startLineNumber, 1, startLineNumber, 1), 0, new Position(endLineNumber, endColumn), 0 )); diff --git a/src/vs/editor/common/controller/cursorMoveOperations.ts b/src/vs/editor/common/controller/cursorMoveOperations.ts index 65ad93791b8..1d414dd1f32 100644 --- a/src/vs/editor/common/controller/cursorMoveOperations.ts +++ b/src/vs/editor/common/controller/cursorMoveOperations.ts @@ -6,6 +6,7 @@ import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState } from 'vs/editor/common/controller/cursorCommon'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; +import * as strings from 'vs/base/common/strings'; export class CursorPosition { _cursorPositionBrand: void; @@ -23,21 +24,19 @@ export class CursorPosition { export class MoveOperations { - public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { - + public static leftPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position { if (column > model.getLineMinColumn(lineNumber)) { - if (CursorColumns.isLowSurrogate(model, lineNumber, column - 2)) { - // character before column is a low surrogate - column = column - 2; - } else { - column = column - 1; - } + column = column - strings.prevCharLength(model.getLineContent(lineNumber), column - 1); } else if (lineNumber > 1) { lineNumber = lineNumber - 1; column = model.getLineMaxColumn(lineNumber); } + return new Position(lineNumber, column); + } - return new CursorPosition(lineNumber, column, 0); + public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { + const pos = MoveOperations.leftPosition(model, lineNumber, column); + return new CursorPosition(pos.lineNumber, pos.column, 0); } public static moveLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState { @@ -57,21 +56,19 @@ export class MoveOperations { return cursor.move(inSelectionMode, lineNumber, column, 0); } - public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { - + public static rightPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position { if (column < model.getLineMaxColumn(lineNumber)) { - if (CursorColumns.isHighSurrogate(model, lineNumber, column - 1)) { - // character after column is a high surrogate - column = column + 2; - } else { - column = column + 1; - } + column = column + strings.nextCharLength(model.getLineContent(lineNumber), column - 1); } else if (lineNumber < model.getLineCount()) { lineNumber = lineNumber + 1; column = model.getLineMinColumn(lineNumber); } + return new Position(lineNumber, column); + } - return new CursorPosition(lineNumber, column, 0); + public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { + const pos = MoveOperations.rightPosition(model, lineNumber, column); + return new CursorPosition(pos.lineNumber, pos.column, 0); } public static moveRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState { @@ -102,15 +99,9 @@ export class MoveOperations { column = model.getLineMaxColumn(lineNumber); } else { column = Math.min(model.getLineMaxColumn(lineNumber), column); - if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } } } else { column = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, currentVisibleColumn); - if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } } leftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize); @@ -160,15 +151,9 @@ export class MoveOperations { column = model.getLineMinColumn(lineNumber); } else { column = Math.min(model.getLineMaxColumn(lineNumber), column); - if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } } } else { column = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, currentVisibleColumn); - if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } } leftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize); diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index 9fc69bc842e..ba0be3d5317 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -6,7 +6,7 @@ import { CharCode } from 'vs/base/common/charCode'; import { onUnexpectedError } from 'vs/base/common/errors'; import * as strings from 'vs/base/common/strings'; -import { ReplaceCommand, ReplaceCommandWithOffsetCursorState, ReplaceCommandWithoutChangingPosition } from 'vs/editor/common/commands/replaceCommand'; +import { ReplaceCommand, ReplaceCommandWithOffsetCursorState, ReplaceCommandWithoutChangingPosition, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand'; import { ShiftCommand } from 'vs/editor/common/commands/shiftCommand'; import { SurroundSelectionCommand } from 'vs/editor/common/commands/surroundSelectionCommand'; import { CursorColumns, CursorConfiguration, EditOperationResult, EditOperationType, ICursorSimpleModel, isQuote } from 'vs/editor/common/controller/cursorCommon'; @@ -81,20 +81,17 @@ export class TypeOperations { const selection = selections[i]; let position = selection.getPosition(); + if (pasteOnNewLine && !selection.isEmpty()) { + pasteOnNewLine = false; + } if (pasteOnNewLine && text.indexOf('\n') !== text.length - 1) { pasteOnNewLine = false; } - if (pasteOnNewLine && selection.startLineNumber !== selection.endLineNumber) { - pasteOnNewLine = false; - } - if (pasteOnNewLine && selection.startColumn === model.getLineMinColumn(selection.startLineNumber) && selection.endColumn === model.getLineMaxColumn(selection.startLineNumber)) { - pasteOnNewLine = false; - } if (pasteOnNewLine) { // Paste entire line at the beginning of line let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, 1); - commands[i] = new ReplaceCommand(typeSelection, text); + commands[i] = new ReplaceCommandThatPreservesSelection(typeSelection, text, selection); } else { commands[i] = new ReplaceCommand(selection, text); } @@ -462,6 +459,12 @@ export class TypeOperations { return false; } + // Do not over-type after a backslash + const beforeCharacter = position.column > 2 ? lineText.charCodeAt(position.column - 2) : CharCode.Null; + if (beforeCharacter === CharCode.Backslash) { + return false; + } + // Must over-type a closing character typed by the editor if (config.autoClosingOvertype === 'auto') { let found = false; @@ -752,7 +755,12 @@ export class TypeOperations { /** * This is very similar with typing, but the character is already in the text buffer! */ - public static compositionEndWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[]): EditOperationResult | null { + public static compositionEndWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selectionsWhenCompositionStarted: Selection[] | null, selections: Selection[], autoClosedCharacters: Range[]): EditOperationResult | null { + if (!selectionsWhenCompositionStarted || Selection.selectionsArrEqual(selectionsWhenCompositionStarted, selections)) { + // no content was typed + return null; + } + let ch: string | null = null; // extract last typed character for (const selection of selections) { diff --git a/src/vs/editor/common/core/characterClassifier.ts b/src/vs/editor/common/core/characterClassifier.ts index 9d448641d17..214bb2abf05 100644 --- a/src/vs/editor/common/core/characterClassifier.ts +++ b/src/vs/editor/common/core/characterClassifier.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { toUint8 } from 'vs/editor/common/core/uint'; +import { toUint8 } from 'vs/base/common/uint'; /** * A fast character classifier that uses a compact array for ASCII values. diff --git a/src/vs/editor/common/core/rgba.ts b/src/vs/editor/common/core/rgba.ts index 0ce94359f31..3a19425bc4d 100644 --- a/src/vs/editor/common/core/rgba.ts +++ b/src/vs/editor/common/core/rgba.ts @@ -10,7 +10,7 @@ export class RGBA8 { _rgba8Brand: void; - static Empty = new RGBA8(0, 0, 0, 0); + static readonly Empty = new RGBA8(0, 0, 0, 0); /** * Red: integer in [0-255] diff --git a/src/vs/editor/common/core/selection.ts b/src/vs/editor/common/core/selection.ts index 80143cdf97a..8f192adcb93 100644 --- a/src/vs/editor/common/core/selection.ts +++ b/src/vs/editor/common/core/selection.ts @@ -73,13 +73,6 @@ export class Selection extends Range { this.positionColumn = positionColumn; } - /** - * Clone this selection. - */ - public clone(): Selection { - return new Selection(this.selectionStartLineNumber, this.selectionStartColumn, this.positionLineNumber, this.positionColumn); - } - /** * Transform to a human-readable representation. */ diff --git a/src/vs/editor/common/diff/diffComputer.ts b/src/vs/editor/common/diff/diffComputer.ts index 67ccd7e5c4e..ebf854605ee 100644 --- a/src/vs/editor/common/diff/diffComputer.ts +++ b/src/vs/editor/common/diff/diffComputer.ts @@ -3,83 +3,63 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDiffChange, ISequence, LcsDiff } from 'vs/base/common/diff/diff'; +import { IDiffChange, ISequence, LcsDiff, IDiffResult } from 'vs/base/common/diff/diff'; import * as strings from 'vs/base/common/strings'; import { ICharChange, ILineChange } from 'vs/editor/common/editorCommon'; -const MAXIMUM_RUN_TIME = 5000; // 5 seconds const MINIMUM_MATCHING_CHARACTER_LENGTH = 3; -function computeDiff(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: () => boolean, pretty: boolean): IDiffChange[] { +export interface IDiffComputerResult { + quitEarly: boolean; + changes: ILineChange[]; +} + +function computeDiff(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: () => boolean, pretty: boolean): IDiffResult { const diffAlgo = new LcsDiff(originalSequence, modifiedSequence, continueProcessingPredicate); return diffAlgo.ComputeDiff(pretty); } -class LineMarkerSequence implements ISequence { +class LineSequence implements ISequence { - private readonly _lines: string[]; + public readonly lines: string[]; private readonly _startColumns: number[]; private readonly _endColumns: number[]; constructor(lines: string[]) { - let startColumns: number[] = []; - let endColumns: number[] = []; + const startColumns: number[] = []; + const endColumns: number[] = []; for (let i = 0, length = lines.length; i < length; i++) { - startColumns[i] = LineMarkerSequence._getFirstNonBlankColumn(lines[i], 1); - endColumns[i] = LineMarkerSequence._getLastNonBlankColumn(lines[i], 1); + startColumns[i] = getFirstNonBlankColumn(lines[i], 1); + endColumns[i] = getLastNonBlankColumn(lines[i], 1); } - this._lines = lines; + this.lines = lines; this._startColumns = startColumns; this._endColumns = endColumns; } - public getLength(): number { - return this._lines.length; - } - - public getElementAtIndex(i: number): string { - return this._lines[i].substring(this._startColumns[i] - 1, this._endColumns[i] - 1); + public getElements(): Int32Array | number[] | string[] { + const elements: string[] = []; + for (let i = 0, len = this.lines.length; i < len; i++) { + elements[i] = this.lines[i].substring(this._startColumns[i] - 1, this._endColumns[i] - 1); + } + return elements; } public getStartLineNumber(i: number): number { return i + 1; } - public getStartColumn(i: number): number { - return this._startColumns[i]; - } - public getEndLineNumber(i: number): number { return i + 1; } - public getEndColumn(i: number): number { - return this._endColumns[i]; - } - - public static _getFirstNonBlankColumn(txt: string, defaultValue: number): number { - const r = strings.firstNonWhitespaceIndex(txt); - if (r === -1) { - return defaultValue; - } - return r + 1; - } - - public static _getLastNonBlankColumn(txt: string, defaultValue: number): number { - const r = strings.lastNonWhitespaceIndex(txt); - if (r === -1) { - return defaultValue; - } - return r + 2; - } - - public getCharSequence(shouldIgnoreTrimWhitespace: boolean, startIndex: number, endIndex: number): CharSequence { - let charCodes: number[] = []; - let lineNumbers: number[] = []; - let columns: number[] = []; + public createCharSequence(shouldIgnoreTrimWhitespace: boolean, startIndex: number, endIndex: number): CharSequence { + const charCodes: number[] = []; + const lineNumbers: number[] = []; + const columns: number[] = []; let len = 0; for (let index = startIndex; index <= endIndex; index++) { - const lineContent = this._lines[index]; + const lineContent = this.lines[index]; const startColumn = (shouldIgnoreTrimWhitespace ? this._startColumns[index] : 1); const endColumn = (shouldIgnoreTrimWhitespace ? this._endColumns[index] : lineContent.length + 1); for (let col = startColumn; col < endColumn; col++) { @@ -105,12 +85,8 @@ class CharSequence implements ISequence { this._columns = columns; } - public getLength(): number { - return this._charCodes.length; - } - - public getElementAtIndex(i: number): number { - return this._charCodes[i]; + public getElements(): Int32Array | number[] | string[] { + return this._charCodes; } public getStartLineNumber(i: number): number { @@ -208,7 +184,7 @@ function postProcessCharChanges(rawChanges: IDiffChange[]): IDiffChange[] { return rawChanges; } - let result = [rawChanges[0]]; + const result = [rawChanges[0]]; let prevChange = result[0]; for (let i = 1, len = rawChanges.length; i < len; i++) { @@ -254,7 +230,7 @@ class LineChange implements ILineChange { this.charChanges = charChanges; } - public static createFromDiffResult(shouldIgnoreTrimWhitespace: boolean, diffChange: IDiffChange, originalLineSequence: LineMarkerSequence, modifiedLineSequence: LineMarkerSequence, continueProcessingPredicate: () => boolean, shouldComputeCharChanges: boolean, shouldPostProcessCharChanges: boolean): LineChange { + public static createFromDiffResult(shouldIgnoreTrimWhitespace: boolean, diffChange: IDiffChange, originalLineSequence: LineSequence, modifiedLineSequence: LineSequence, continueCharDiff: () => boolean, shouldComputeCharChanges: boolean, shouldPostProcessCharChanges: boolean): LineChange { let originalStartLineNumber: number; let originalEndLineNumber: number; let modifiedStartLineNumber: number; @@ -277,11 +253,12 @@ class LineChange implements ILineChange { modifiedEndLineNumber = modifiedLineSequence.getEndLineNumber(diffChange.modifiedStart + diffChange.modifiedLength - 1); } - if (shouldComputeCharChanges && diffChange.originalLength !== 0 && diffChange.modifiedLength !== 0 && continueProcessingPredicate()) { - const originalCharSequence = originalLineSequence.getCharSequence(shouldIgnoreTrimWhitespace, diffChange.originalStart, diffChange.originalStart + diffChange.originalLength - 1); - const modifiedCharSequence = modifiedLineSequence.getCharSequence(shouldIgnoreTrimWhitespace, diffChange.modifiedStart, diffChange.modifiedStart + diffChange.modifiedLength - 1); + if (shouldComputeCharChanges && diffChange.originalLength > 0 && diffChange.originalLength < 20 && diffChange.modifiedLength > 0 && diffChange.modifiedLength < 20 && continueCharDiff()) { + // Compute character changes for diff chunks of at most 20 lines... + const originalCharSequence = originalLineSequence.createCharSequence(shouldIgnoreTrimWhitespace, diffChange.originalStart, diffChange.originalStart + diffChange.originalLength - 1); + const modifiedCharSequence = modifiedLineSequence.createCharSequence(shouldIgnoreTrimWhitespace, diffChange.modifiedStart, diffChange.modifiedStart + diffChange.modifiedLength - 1); - let rawChanges = computeDiff(originalCharSequence, modifiedCharSequence, continueProcessingPredicate, true); + let rawChanges = computeDiff(originalCharSequence, modifiedCharSequence, continueCharDiff, true).changes; if (shouldPostProcessCharChanges) { rawChanges = postProcessCharChanges(rawChanges); @@ -302,6 +279,7 @@ export interface IDiffComputerOpts { shouldPostProcessCharChanges: boolean; shouldIgnoreTrimWhitespace: boolean; shouldMakePrettyDiff: boolean; + maxComputationTime: number; } export class DiffComputer { @@ -310,88 +288,96 @@ export class DiffComputer { private readonly shouldPostProcessCharChanges: boolean; private readonly shouldIgnoreTrimWhitespace: boolean; private readonly shouldMakePrettyDiff: boolean; - private readonly maximumRunTimeMs: number; private readonly originalLines: string[]; private readonly modifiedLines: string[]; - private readonly original: LineMarkerSequence; - private readonly modified: LineMarkerSequence; - - private computationStartTime: number; + private readonly original: LineSequence; + private readonly modified: LineSequence; + private readonly continueLineDiff: () => boolean; + private readonly continueCharDiff: () => boolean; constructor(originalLines: string[], modifiedLines: string[], opts: IDiffComputerOpts) { this.shouldComputeCharChanges = opts.shouldComputeCharChanges; this.shouldPostProcessCharChanges = opts.shouldPostProcessCharChanges; this.shouldIgnoreTrimWhitespace = opts.shouldIgnoreTrimWhitespace; this.shouldMakePrettyDiff = opts.shouldMakePrettyDiff; - this.maximumRunTimeMs = MAXIMUM_RUN_TIME; this.originalLines = originalLines; this.modifiedLines = modifiedLines; - this.original = new LineMarkerSequence(originalLines); - this.modified = new LineMarkerSequence(modifiedLines); + this.original = new LineSequence(originalLines); + this.modified = new LineSequence(modifiedLines); - this.computationStartTime = (new Date()).getTime(); + this.continueLineDiff = createContinueProcessingPredicate(opts.maxComputationTime); + this.continueCharDiff = createContinueProcessingPredicate(opts.maxComputationTime === 0 ? 0 : Math.min(opts.maxComputationTime, 5000)); // never run after 5s for character changes... } - public computeDiff(): ILineChange[] { + public computeDiff(): IDiffComputerResult { - if (this.original.getLength() === 1 && this.original.getElementAtIndex(0).length === 0) { + if (this.original.lines.length === 1 && this.original.lines[0].length === 0) { // empty original => fast path - return [{ - originalStartLineNumber: 1, - originalEndLineNumber: 1, - modifiedStartLineNumber: 1, - modifiedEndLineNumber: this.modified.getLength(), - charChanges: [{ - modifiedEndColumn: 0, - modifiedEndLineNumber: 0, - modifiedStartColumn: 0, - modifiedStartLineNumber: 0, - originalEndColumn: 0, - originalEndLineNumber: 0, - originalStartColumn: 0, - originalStartLineNumber: 0 + return { + quitEarly: false, + changes: [{ + originalStartLineNumber: 1, + originalEndLineNumber: 1, + modifiedStartLineNumber: 1, + modifiedEndLineNumber: this.modified.lines.length, + charChanges: [{ + modifiedEndColumn: 0, + modifiedEndLineNumber: 0, + modifiedStartColumn: 0, + modifiedStartLineNumber: 0, + originalEndColumn: 0, + originalEndLineNumber: 0, + originalStartColumn: 0, + originalStartLineNumber: 0 + }] }] - }]; + }; } - if (this.modified.getLength() === 1 && this.modified.getElementAtIndex(0).length === 0) { + if (this.modified.lines.length === 1 && this.modified.lines[0].length === 0) { // empty modified => fast path - return [{ - originalStartLineNumber: 1, - originalEndLineNumber: this.original.getLength(), - modifiedStartLineNumber: 1, - modifiedEndLineNumber: 1, - charChanges: [{ - modifiedEndColumn: 0, - modifiedEndLineNumber: 0, - modifiedStartColumn: 0, - modifiedStartLineNumber: 0, - originalEndColumn: 0, - originalEndLineNumber: 0, - originalStartColumn: 0, - originalStartLineNumber: 0 + return { + quitEarly: false, + changes: [{ + originalStartLineNumber: 1, + originalEndLineNumber: this.original.lines.length, + modifiedStartLineNumber: 1, + modifiedEndLineNumber: 1, + charChanges: [{ + modifiedEndColumn: 0, + modifiedEndLineNumber: 0, + modifiedStartColumn: 0, + modifiedStartLineNumber: 0, + originalEndColumn: 0, + originalEndLineNumber: 0, + originalStartColumn: 0, + originalStartLineNumber: 0 + }] }] - }]; + }; } - this.computationStartTime = (new Date()).getTime(); - - let rawChanges = computeDiff(this.original, this.modified, this._continueProcessingPredicate.bind(this), this.shouldMakePrettyDiff); + const diffResult = computeDiff(this.original, this.modified, this.continueLineDiff, this.shouldMakePrettyDiff); + const rawChanges = diffResult.changes; + const quitEarly = diffResult.quitEarly; // The diff is always computed with ignoring trim whitespace // This ensures we get the prettiest diff if (this.shouldIgnoreTrimWhitespace) { - let lineChanges: LineChange[] = []; + const lineChanges: LineChange[] = []; for (let i = 0, length = rawChanges.length; i < length; i++) { - lineChanges.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, rawChanges[i], this.original, this.modified, this._continueProcessingPredicate.bind(this), this.shouldComputeCharChanges, this.shouldPostProcessCharChanges)); + lineChanges.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, rawChanges[i], this.original, this.modified, this.continueCharDiff, this.shouldComputeCharChanges, this.shouldPostProcessCharChanges)); } - return lineChanges; + return { + quitEarly: quitEarly, + changes: lineChanges + }; } // Need to post-process and introduce changes where the trim whitespace is different // Note that we are looping starting at -1 to also cover the lines before the first change - let result: LineChange[] = []; + const result: LineChange[] = []; let originalLineIndex = 0; let modifiedLineIndex = 0; @@ -409,8 +395,8 @@ export class DiffComputer { // Check the leading whitespace { - let originalStartColumn = LineMarkerSequence._getFirstNonBlankColumn(originalLine, 1); - let modifiedStartColumn = LineMarkerSequence._getFirstNonBlankColumn(modifiedLine, 1); + let originalStartColumn = getFirstNonBlankColumn(originalLine, 1); + let modifiedStartColumn = getFirstNonBlankColumn(modifiedLine, 1); while (originalStartColumn > 1 && modifiedStartColumn > 1) { const originalChar = originalLine.charCodeAt(originalStartColumn - 2); const modifiedChar = modifiedLine.charCodeAt(modifiedStartColumn - 2); @@ -431,8 +417,8 @@ export class DiffComputer { // Check the trailing whitespace { - let originalEndColumn = LineMarkerSequence._getLastNonBlankColumn(originalLine, 1); - let modifiedEndColumn = LineMarkerSequence._getLastNonBlankColumn(modifiedLine, 1); + let originalEndColumn = getLastNonBlankColumn(originalLine, 1); + let modifiedEndColumn = getLastNonBlankColumn(modifiedLine, 1); const originalMaxColumn = originalLine.length + 1; const modifiedMaxColumn = modifiedLine.length + 1; while (originalEndColumn < originalMaxColumn && modifiedEndColumn < modifiedMaxColumn) { @@ -459,14 +445,17 @@ export class DiffComputer { if (nextChange) { // Emit the actual change - result.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, nextChange, this.original, this.modified, this._continueProcessingPredicate.bind(this), this.shouldComputeCharChanges, this.shouldPostProcessCharChanges)); + result.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, nextChange, this.original, this.modified, this.continueCharDiff, this.shouldComputeCharChanges, this.shouldPostProcessCharChanges)); originalLineIndex += nextChange.originalLength; modifiedLineIndex += nextChange.modifiedLength; } } - return result; + return { + quitEarly: quitEarly, + changes: result + }; } private _pushTrimWhitespaceCharChange( @@ -513,8 +502,8 @@ export class DiffComputer { if (prevChange.originalEndLineNumber + 1 === originalLineNumber && prevChange.modifiedEndLineNumber + 1 === modifiedLineNumber) { prevChange.originalEndLineNumber = originalLineNumber; prevChange.modifiedEndLineNumber = modifiedLineNumber; - if (this.shouldComputeCharChanges) { - prevChange.charChanges!.push(new CharChange( + if (this.shouldComputeCharChanges && prevChange.charChanges) { + prevChange.charChanges.push(new CharChange( originalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn )); @@ -524,13 +513,31 @@ export class DiffComputer { return false; } +} - private _continueProcessingPredicate(): boolean { - if (this.maximumRunTimeMs === 0) { - return true; - } - const now = (new Date()).getTime(); - return now - this.computationStartTime < this.maximumRunTimeMs; +function getFirstNonBlankColumn(txt: string, defaultValue: number): number { + const r = strings.firstNonWhitespaceIndex(txt); + if (r === -1) { + return defaultValue; + } + return r + 1; +} + +function getLastNonBlankColumn(txt: string, defaultValue: number): number { + const r = strings.lastNonWhitespaceIndex(txt); + if (r === -1) { + return defaultValue; + } + return r + 2; +} + +function createContinueProcessingPredicate(maximumRuntime: number): () => boolean { + if (maximumRuntime === 0) { + return () => true; } + const startTime = Date.now(); + return () => { + return Date.now() - startTime < maximumRuntime; + }; } diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index bf44d118f85..679cb676023 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -280,6 +280,8 @@ export interface IEditor { /** * Instructs the editor to remeasure its container. This method should * be called when the container of the editor gets resized. + * + * If a dimension is passed in, the passed in value will be used. */ layout(dimension?: IDimension): void; @@ -313,6 +315,12 @@ export interface IEditor { */ getVisibleColumnFromPosition(position: IPosition): number; + /** + * Given a position, returns a column number that takes tab-widths into account. + * @internal + */ + getStatusbarColumn(position: IPosition): number; + /** * Returns the primary position of the cursor. */ @@ -486,10 +494,6 @@ export interface IDiffEditor extends IEditor { * An editor contribution that gets created every time a new editor gets created and gets disposed when the editor gets disposed. */ export interface IEditorContribution { - /** - * Get a unique identifier for this contribution. - */ - getId(): string; /** * Dispose this contribution. */ @@ -504,6 +508,17 @@ export interface IEditorContribution { restoreViewState?(state: any): void; } +/** + * A diff editor contribution that gets created every time a new diffeditor gets created and gets disposed when the diff editor gets disposed. + * @internal + */ +export interface IDiffEditorContribution { + /** + * Dispose this contribution. + */ + dispose(): void; +} + /** * @internal */ diff --git a/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts index 3037589c764..b73b57df96d 100644 --- a/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -459,8 +459,8 @@ export class FindMatch { */ export interface IFoundBracket { range: Range; - open: string; - close: string; + open: string[]; + close: string[]; isOpen: boolean; } @@ -608,6 +608,12 @@ export interface ITextModel { */ getValueLengthInRange(range: IRange): number; + /** + * Get the character count of text in a certain range. + * @param range The range describing what text length to get. + */ + getCharacterCountInRange(range: IRange): number; + /** * Splits characters in two buckets. First bucket (A) is of characters that * sit in lines with length < `LONG_LINE_BOUNDARY`. Second bucket (B) is of @@ -881,6 +887,13 @@ export interface ITextModel { */ findNextBracket(position: IPosition): IFoundBracket | null; + /** + * Find the enclosing brackets that contain `position`. + * @param position The position at which to start the search. + * @internal + */ + findEnclosingBrackets(position: IPosition): [Range, Range] | null; + /** * Given a `position`, if the position is on top or near a bracket, * find the matching bracket of that bracket and return the ranges of both brackets. @@ -1179,6 +1192,13 @@ export interface ITextBufferFactory { getFirstLineText(lengthLimit: number): string; } +/** + * @internal + */ +export const enum ModelConstants { + FIRST_LINE_DETECTION_LENGTH_LIMIT = 1000 +} + /** * @internal */ @@ -1196,6 +1216,7 @@ export interface ITextBuffer { getValueInRange(range: Range, eol: EndOfLinePreference): string; createSnapshot(preserveBOM: boolean): ITextSnapshot; getValueLengthInRange(range: Range, eol: EndOfLinePreference): number; + getCharacterCountInRange(range: Range, eol: EndOfLinePreference): number; getLength(): number; getLineCount(): number; getLinesContent(): string[]; diff --git a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts index 9e38117e9e7..1c844dd66c4 100644 --- a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts +++ b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts @@ -577,23 +577,34 @@ export class PieceTreeBase { let m: RegExpExecArray | null; // Reset regex to search from the beginning - searcher.reset(start); let ret: BufferCursor = { line: 0, column: 0 }; + let searchText: string; + let offsetInBuffer: (offset: number) => number; + + if (searcher._wordSeparators) { + searchText = buffer.buffer.substring(start, end); + offsetInBuffer = (offset: number) => offset + start; + searcher.reset(-1); + } else { + searchText = buffer.buffer; + offsetInBuffer = (offset: number) => offset; + searcher.reset(start); + } do { - m = searcher.next(buffer.buffer); + m = searcher.next(searchText); if (m) { - if (m.index >= end) { + if (offsetInBuffer(m.index) >= end) { return resultLen; } - this.positionInBuffer(node, m.index - startOffsetInBuffer, ret); + this.positionInBuffer(node, offsetInBuffer(m.index) - startOffsetInBuffer, ret); let lineFeedCnt = this.getLineFeedCnt(node.piece.bufferIndex, startCursor, ret); let retStartColumn = ret.line === startCursor.line ? ret.column - startCursor.column + startColumn : ret.column + 1; let retEndColumn = retStartColumn + m[0].length; result[resultLen++] = createFindMatch(new Range(startLineNumber + lineFeedCnt, retStartColumn, startLineNumber + lineFeedCnt, retEndColumn), m, captureMatches); - if (m.index + m[0].length >= end) { + if (offsetInBuffer(m.index) + m[0].length >= end) { return resultLen; } if (resultLen >= limitResultCount) { diff --git a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts index b6d05389439..a987231c3ab 100644 --- a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts +++ b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts @@ -106,6 +106,37 @@ export class PieceTreeTextBuffer implements ITextBuffer { return endOffset - startOffset; } + public getCharacterCountInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): number { + if (this._mightContainNonBasicASCII) { + // we must count by iterating + + let result = 0; + + const fromLineNumber = range.startLineNumber; + const toLineNumber = range.endLineNumber; + for (let lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) { + const lineContent = this.getLineContent(lineNumber); + const fromOffset = (lineNumber === fromLineNumber ? range.startColumn - 1 : 0); + const toOffset = (lineNumber === toLineNumber ? range.endColumn - 1 : lineContent.length); + + for (let offset = fromOffset; offset < toOffset; offset++) { + if (strings.isHighSurrogate(lineContent.charCodeAt(offset))) { + result = result + 1; + offset = offset + 1; + } else { + result = result + 1; + } + } + } + + result += this._getEndOfLine(eol).length * (toLineNumber - fromLineNumber); + + return result; + } + + return this.getValueLengthInRange(range, eol); + } + public getLength(): number { return this._pieceTree.getLength(); } diff --git a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts index 5b24e6f1c64..fa8d98e94e6 100644 --- a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts +++ b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts @@ -57,7 +57,7 @@ export class PieceTreeTextBufferFactory implements ITextBufferFactory { } public getFirstLineText(lengthLimit: number): string { - return this._chunks[0].buffer.substr(0, 100).split(/\r\n|\r|\n/)[0]; + return this._chunks[0].buffer.substr(0, lengthLimit).split(/\r\n|\r|\n/)[0]; } } diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index d0320749440..8545d94bd51 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -729,6 +729,11 @@ export class TextModel extends Disposable implements model.ITextModel { return this._buffer.getValueLengthInRange(this.validateRange(rawRange), eol); } + public getCharacterCountInRange(rawRange: IRange, eol: model.EndOfLinePreference = model.EndOfLinePreference.TextDefined): number { + this._assertNotDisposed(); + return this._buffer.getCharacterCountInRange(this.validateRange(rawRange), eol); + } + public getLineCount(): number { this._assertNotDisposed(); return this._buffer.getLineCount(); @@ -893,11 +898,9 @@ export class TextModel extends Disposable implements model.ITextModel { } if (strict) { - if (column > 1) { - const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2); - if (strings.isHighSurrogate(charCodeBefore)) { - return false; - } + const [charStartOffset,] = strings.getCharContainingOffset(this._buffer.getLineContent(lineNumber), column - 1); + if (column !== charStartOffset + 1) { + return false; } } @@ -930,12 +933,9 @@ export class TextModel extends Disposable implements model.ITextModel { } if (strict) { - // If the position would end up in the middle of a high-low surrogate pair, - // we move it to before the pair - // !!At this point, column > 1 - const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2); - if (strings.isHighSurrogate(charCodeBefore)) { - return new Position(lineNumber, column - 1); + const [charStartOffset,] = strings.getCharContainingOffset(this._buffer.getLineContent(lineNumber), column - 1); + if (column !== charStartOffset + 1) { + return new Position(lineNumber, charStartOffset + 1); } } @@ -972,17 +972,23 @@ export class TextModel extends Disposable implements model.ITextModel { } if (strict) { - const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0); - const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0); - - const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart); - const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd); - - if (!startInsideSurrogatePair && !endInsideSurrogatePair) { - return true; + const startLineContent = this._buffer.getLineContent(startLineNumber); + if (startColumn < startLineContent.length + 1) { + const [charStartOffset,] = strings.getCharContainingOffset(startLineContent, startColumn - 1); + if (startColumn !== charStartOffset + 1) { + return false; + } } - return false; + if (endColumn >= 2) { + const endLineContent = (endLineNumber === startLineNumber ? startLineContent : this._buffer.getLineContent(endLineNumber)); + const [, charEndOffset] = strings.getCharContainingOffset(endLineContent, endColumn - 2); + if (endColumn !== charEndOffset + 1) { + return false; + } + } + + return true; } return true; @@ -1002,37 +1008,32 @@ export class TextModel extends Disposable implements model.ITextModel { const end = this._validatePosition(_range.endLineNumber, _range.endColumn, false); const startLineNumber = start.lineNumber; - const startColumn = start.column; + let startColumn = start.column; const endLineNumber = end.lineNumber; - const endColumn = end.column; + let endColumn = end.column; + const isEmpty = (startLineNumber === endLineNumber && startColumn === endColumn); - const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0); - const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0); - - const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart); - const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd); - - if (!startInsideSurrogatePair && !endInsideSurrogatePair) { - return new Range(startLineNumber, startColumn, endLineNumber, endColumn); + const startLineContent = this._buffer.getLineContent(startLineNumber); + if (startColumn < startLineContent.length + 1) { + const [charStartOffset,] = strings.getCharContainingOffset(startLineContent, startColumn - 1); + if (startColumn !== charStartOffset + 1) { + if (isEmpty) { + // do not expand a collapsed range, simply move it to a valid location + return new Range(startLineNumber, charStartOffset + 1, startLineNumber, charStartOffset + 1); + } + startColumn = charStartOffset + 1; + } } - if (startLineNumber === endLineNumber && startColumn === endColumn) { - // do not expand a collapsed range, simply move it to a valid location - return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn - 1); + if (endColumn >= 2) { + const endLineContent = (endLineNumber === startLineNumber ? startLineContent : this._buffer.getLineContent(endLineNumber)); + const [, charEndOffset] = strings.getCharContainingOffset(endLineContent, endColumn - 2); + if (endColumn !== charEndOffset + 1) { + endColumn = charEndOffset + 1; + } } - if (startInsideSurrogatePair && endInsideSurrogatePair) { - // expand range at both ends - return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn + 1); - } - - if (startInsideSurrogatePair) { - // only expand range at the start - return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn); - } - - // only expand range at the end - return new Range(startLineNumber, startColumn, endLineNumber, endColumn + 1); + return new Range(startLineNumber, startColumn, endLineNumber, endColumn); } public modifyPosition(rawPosition: IPosition, offset: number): Position { @@ -1923,7 +1924,7 @@ export class TextModel extends Disposable implements model.ITextModel { const lineTokens = this._getLineTokens(lineNumber); const lineText = this._buffer.getLineContent(lineNumber); - let tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); + const tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); if (tokenIndex < 0) { return null; } @@ -1932,15 +1933,15 @@ export class TextModel extends Disposable implements model.ITextModel { // check that the token is not to be ignored if (currentModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))) { // limit search to not go before `maxBracketLength` - let searchStartOffset = Math.max(lineTokens.getStartOffset(tokenIndex), position.column - 1 - currentModeBrackets.maxBracketLength); + let searchStartOffset = Math.max(0, position.column - 1 - currentModeBrackets.maxBracketLength); // limit search to not go after `maxBracketLength` - const searchEndOffset = Math.min(lineTokens.getEndOffset(tokenIndex), position.column - 1 + currentModeBrackets.maxBracketLength); + const searchEndOffset = Math.min(lineText.length, position.column - 1 + currentModeBrackets.maxBracketLength); // it might be the case that [currentTokenStart -> currentTokenEnd] contains multiple brackets // `bestResult` will contain the most right-side result let bestResult: [Range, Range] | null = null; while (true) { - let foundBracket = BracketsUtils.findNextBracketInToken(currentModeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + const foundBracket = BracketsUtils.findNextBracketInRange(currentModeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); if (!foundBracket) { // there are no more brackets in this text break; @@ -1948,12 +1949,8 @@ export class TextModel extends Disposable implements model.ITextModel { // check that we didn't hit a bracket too far away from position if (foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) { - let foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1); - foundBracketText = foundBracketText.toLowerCase(); - - let r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText]); - - // check that we can actually match this bracket + const foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase(); + const r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText]); if (r) { bestResult = r; } @@ -1969,24 +1966,20 @@ export class TextModel extends Disposable implements model.ITextModel { // If position is in between two tokens, try also looking in the previous token if (tokenIndex > 0 && lineTokens.getStartOffset(tokenIndex) === position.column - 1) { - const searchEndOffset = lineTokens.getStartOffset(tokenIndex); - tokenIndex--; - const prevModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(lineTokens.getLanguageId(tokenIndex)); + const prevTokenIndex = tokenIndex - 1; + const prevModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(lineTokens.getLanguageId(prevTokenIndex)); // check that previous token is not to be ignored - if (prevModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))) { + if (prevModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(prevTokenIndex))) { // limit search in case previous token is very large, there's no need to go beyond `maxBracketLength` - const searchStartOffset = Math.max(lineTokens.getStartOffset(tokenIndex), position.column - 1 - prevModeBrackets.maxBracketLength); - const foundBracket = BracketsUtils.findPrevBracketInToken(prevModeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + const searchStartOffset = Math.max(0, position.column - 1 - prevModeBrackets.maxBracketLength); + const searchEndOffset = Math.min(lineText.length, position.column - 1 + prevModeBrackets.maxBracketLength); + const foundBracket = BracketsUtils.findPrevBracketInRange(prevModeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); // check that we didn't hit a bracket too far away from position if (foundBracket && foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) { - let foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1); - foundBracketText = foundBracketText.toLowerCase(); - - let r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText]); - - // check that we can actually match this bracket + const foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase(); + const r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText]); if (r) { return r; } @@ -2024,54 +2017,76 @@ export class TextModel extends Disposable implements model.ITextModel { const reversedBracketRegex = bracket.reversedRegex; let count = -1; + const searchPrevMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null => { + while (true) { + const r = BracketsUtils.findPrevBracketInRange(reversedBracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (!r) { + break; + } + + const hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase(); + if (bracket.isOpen(hitText)) { + count++; + } else if (bracket.isClose(hitText)) { + count--; + } + + if (count === 0) { + return r; + } + + searchEndOffset = r.startColumn - 1; + } + + return null; + }; + for (let lineNumber = position.lineNumber; lineNumber >= 1; lineNumber--) { const lineTokens = this._getLineTokens(lineNumber); const tokenCount = lineTokens.getCount(); const lineText = this._buffer.getLineContent(lineNumber); let tokenIndex = tokenCount - 1; - let searchStopOffset = -1; + let searchStartOffset = lineText.length; + let searchEndOffset = lineText.length; if (lineNumber === position.lineNumber) { tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); - searchStopOffset = position.column - 1; + searchStartOffset = position.column - 1; + searchEndOffset = position.column - 1; } + let prevSearchInToken = true; for (; tokenIndex >= 0; tokenIndex--) { - const tokenLanguageId = lineTokens.getLanguageId(tokenIndex); - const tokenType = lineTokens.getStandardTokenType(tokenIndex); - const tokenStartOffset = lineTokens.getStartOffset(tokenIndex); - const tokenEndOffset = lineTokens.getEndOffset(tokenIndex); + const searchInToken = (lineTokens.getLanguageId(tokenIndex) === languageId && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))); - if (searchStopOffset === -1) { - searchStopOffset = tokenEndOffset; - } - - if (tokenLanguageId === languageId && !ignoreBracketsInToken(tokenType)) { - - while (true) { - let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, lineNumber, lineText, tokenStartOffset, searchStopOffset); - if (!r) { - break; - } - - let hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1); - hitText = hitText.toLowerCase(); - - if (hitText === bracket.open) { - count++; - } else if (hitText === bracket.close) { - count--; - } - - if (count === 0) { + if (searchInToken) { + // this token should be searched + if (prevSearchInToken) { + // the previous token should be searched, simply extend searchStartOffset + searchStartOffset = lineTokens.getStartOffset(tokenIndex); + } else { + // the previous token should not be searched + searchStartOffset = lineTokens.getStartOffset(tokenIndex); + searchEndOffset = lineTokens.getEndOffset(tokenIndex); + } + } else { + // this token should not be searched + if (prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = searchPrevMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { return r; } - - searchStopOffset = r.startColumn - 1; } } - searchStopOffset = -1; + prevSearchInToken = searchInToken; + } + + if (prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = searchPrevMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return r; + } } } @@ -2085,53 +2100,77 @@ export class TextModel extends Disposable implements model.ITextModel { const bracketRegex = bracket.forwardRegex; let count = 1; - for (let lineNumber = position.lineNumber, lineCount = this.getLineCount(); lineNumber <= lineCount; lineNumber++) { + const searchNextMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null => { + while (true) { + const r = BracketsUtils.findNextBracketInRange(bracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (!r) { + break; + } + + const hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase(); + if (bracket.isOpen(hitText)) { + count++; + } else if (bracket.isClose(hitText)) { + count--; + } + + if (count === 0) { + return r; + } + + searchStartOffset = r.endColumn - 1; + } + + return null; + }; + + const lineCount = this.getLineCount(); + for (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) { const lineTokens = this._getLineTokens(lineNumber); const tokenCount = lineTokens.getCount(); const lineText = this._buffer.getLineContent(lineNumber); let tokenIndex = 0; let searchStartOffset = 0; + let searchEndOffset = 0; if (lineNumber === position.lineNumber) { tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); searchStartOffset = position.column - 1; + searchEndOffset = position.column - 1; } + let prevSearchInToken = true; for (; tokenIndex < tokenCount; tokenIndex++) { - const tokenLanguageId = lineTokens.getLanguageId(tokenIndex); - const tokenType = lineTokens.getStandardTokenType(tokenIndex); - const tokenStartOffset = lineTokens.getStartOffset(tokenIndex); - const tokenEndOffset = lineTokens.getEndOffset(tokenIndex); + const searchInToken = (lineTokens.getLanguageId(tokenIndex) === languageId && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))); - if (searchStartOffset === 0) { - searchStartOffset = tokenStartOffset; - } - - if (tokenLanguageId === languageId && !ignoreBracketsInToken(tokenType)) { - while (true) { - let r = BracketsUtils.findNextBracketInToken(bracketRegex, lineNumber, lineText, searchStartOffset, tokenEndOffset); - if (!r) { - break; - } - - let hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1); - hitText = hitText.toLowerCase(); - - if (hitText === bracket.open) { - count++; - } else if (hitText === bracket.close) { - count--; - } - - if (count === 0) { + if (searchInToken) { + // this token should be searched + if (prevSearchInToken) { + // the previous token should be searched, simply extend searchEndOffset + searchEndOffset = lineTokens.getEndOffset(tokenIndex); + } else { + // the previous token should not be searched + searchStartOffset = lineTokens.getStartOffset(tokenIndex); + searchEndOffset = lineTokens.getEndOffset(tokenIndex); + } + } else { + // this token should not be searched + if (prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = searchNextMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { return r; } - - searchStartOffset = r.endColumn - 1; } } - searchStartOffset = 0; + prevSearchInToken = searchInToken; + } + + if (prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = searchNextMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return r; + } } } @@ -2149,33 +2188,66 @@ export class TextModel extends Disposable implements model.ITextModel { const lineText = this._buffer.getLineContent(lineNumber); let tokenIndex = tokenCount - 1; - let searchStopOffset = -1; + let searchStartOffset = lineText.length; + let searchEndOffset = lineText.length; if (lineNumber === position.lineNumber) { tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); - searchStopOffset = position.column - 1; - } - - for (; tokenIndex >= 0; tokenIndex--) { + searchStartOffset = position.column - 1; + searchEndOffset = position.column - 1; const tokenLanguageId = lineTokens.getLanguageId(tokenIndex); - const tokenType = lineTokens.getStandardTokenType(tokenIndex); - const tokenStartOffset = lineTokens.getStartOffset(tokenIndex); - const tokenEndOffset = lineTokens.getEndOffset(tokenIndex); - - if (searchStopOffset === -1) { - searchStopOffset = tokenEndOffset; - } if (languageId !== tokenLanguageId) { languageId = tokenLanguageId; modeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId); } - if (modeBrackets && !ignoreBracketsInToken(tokenType)) { - let r = BracketsUtils.findPrevBracketInToken(modeBrackets.reversedRegex, lineNumber, lineText, tokenStartOffset, searchStopOffset); - if (r) { - return this._toFoundBracket(modeBrackets, r); + } + + let prevSearchInToken = true; + for (; tokenIndex >= 0; tokenIndex--) { + const tokenLanguageId = lineTokens.getLanguageId(tokenIndex); + + if (languageId !== tokenLanguageId) { + // language id change! + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return this._toFoundBracket(modeBrackets, r); + } + prevSearchInToken = false; + } + languageId = tokenLanguageId; + modeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId); + } + + const searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))); + + if (searchInToken) { + // this token should be searched + if (prevSearchInToken) { + // the previous token should be searched, simply extend searchStartOffset + searchStartOffset = lineTokens.getStartOffset(tokenIndex); + } else { + // the previous token should not be searched + searchStartOffset = lineTokens.getStartOffset(tokenIndex); + searchEndOffset = lineTokens.getEndOffset(tokenIndex); + } + } else { + // this token should not be searched + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return this._toFoundBracket(modeBrackets, r); + } } } - searchStopOffset = -1; + prevSearchInToken = searchInToken; + } + + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return this._toFoundBracket(modeBrackets, r); + } } } @@ -2184,43 +2256,187 @@ export class TextModel extends Disposable implements model.ITextModel { public findNextBracket(_position: IPosition): model.IFoundBracket | null { const position = this.validatePosition(_position); + const lineCount = this.getLineCount(); let languageId: LanguageId = -1; let modeBrackets: RichEditBrackets | null = null; - for (let lineNumber = position.lineNumber, lineCount = this.getLineCount(); lineNumber <= lineCount; lineNumber++) { + for (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) { const lineTokens = this._getLineTokens(lineNumber); const tokenCount = lineTokens.getCount(); const lineText = this._buffer.getLineContent(lineNumber); let tokenIndex = 0; let searchStartOffset = 0; + let searchEndOffset = 0; if (lineNumber === position.lineNumber) { tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); searchStartOffset = position.column - 1; - } - - for (; tokenIndex < tokenCount; tokenIndex++) { + searchEndOffset = position.column - 1; const tokenLanguageId = lineTokens.getLanguageId(tokenIndex); - const tokenType = lineTokens.getStandardTokenType(tokenIndex); - const tokenStartOffset = lineTokens.getStartOffset(tokenIndex); - const tokenEndOffset = lineTokens.getEndOffset(tokenIndex); - - if (searchStartOffset === 0) { - searchStartOffset = tokenStartOffset; - } - if (languageId !== tokenLanguageId) { languageId = tokenLanguageId; modeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId); } - if (modeBrackets && !ignoreBracketsInToken(tokenType)) { - let r = BracketsUtils.findNextBracketInToken(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, tokenEndOffset); - if (r) { - return this._toFoundBracket(modeBrackets, r); + } + + let prevSearchInToken = true; + for (; tokenIndex < tokenCount; tokenIndex++) { + const tokenLanguageId = lineTokens.getLanguageId(tokenIndex); + + if (languageId !== tokenLanguageId) { + // language id change! + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return this._toFoundBracket(modeBrackets, r); + } + prevSearchInToken = false; + } + languageId = tokenLanguageId; + modeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId); + } + + const searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))); + if (searchInToken) { + // this token should be searched + if (prevSearchInToken) { + // the previous token should be searched, simply extend searchEndOffset + searchEndOffset = lineTokens.getEndOffset(tokenIndex); + } else { + // the previous token should not be searched + searchStartOffset = lineTokens.getStartOffset(tokenIndex); + searchEndOffset = lineTokens.getEndOffset(tokenIndex); + } + } else { + // this token should not be searched + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return this._toFoundBracket(modeBrackets, r); + } } } - searchStartOffset = 0; + prevSearchInToken = searchInToken; + } + + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return this._toFoundBracket(modeBrackets, r); + } + } + } + + return null; + } + + public findEnclosingBrackets(_position: IPosition): [Range, Range] | null { + const position = this.validatePosition(_position); + const lineCount = this.getLineCount(); + + let counts: number[] = []; + const resetCounts = (modeBrackets: RichEditBrackets | null) => { + counts = []; + for (let i = 0, len = modeBrackets ? modeBrackets.brackets.length : 0; i < len; i++) { + counts[i] = 0; + } + }; + const searchInRange = (modeBrackets: RichEditBrackets, lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): [Range, Range] | null => { + while (true) { + const r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (!r) { + break; + } + + const hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase(); + const bracket = modeBrackets.textIsBracket[hitText]; + if (bracket) { + if (bracket.isOpen(hitText)) { + counts[bracket.index]++; + } else if (bracket.isClose(hitText)) { + counts[bracket.index]--; + } + + if (counts[bracket.index] === -1) { + return this._matchFoundBracket(r, bracket, false); + } + } + + searchStartOffset = r.endColumn - 1; + } + return null; + }; + + let languageId: LanguageId = -1; + let modeBrackets: RichEditBrackets | null = null; + for (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) { + const lineTokens = this._getLineTokens(lineNumber); + const tokenCount = lineTokens.getCount(); + const lineText = this._buffer.getLineContent(lineNumber); + + let tokenIndex = 0; + let searchStartOffset = 0; + let searchEndOffset = 0; + if (lineNumber === position.lineNumber) { + tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); + searchStartOffset = position.column - 1; + searchEndOffset = position.column - 1; + const tokenLanguageId = lineTokens.getLanguageId(tokenIndex); + if (languageId !== tokenLanguageId) { + languageId = tokenLanguageId; + modeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId); + resetCounts(modeBrackets); + } + } + + let prevSearchInToken = true; + for (; tokenIndex < tokenCount; tokenIndex++) { + const tokenLanguageId = lineTokens.getLanguageId(tokenIndex); + + if (languageId !== tokenLanguageId) { + // language id change! + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return r; + } + prevSearchInToken = false; + } + languageId = tokenLanguageId; + modeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId); + resetCounts(modeBrackets); + } + + const searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))); + if (searchInToken) { + // this token should be searched + if (prevSearchInToken) { + // the previous token should be searched, simply extend searchEndOffset + searchEndOffset = lineTokens.getEndOffset(tokenIndex); + } else { + // the previous token should not be searched + searchStartOffset = lineTokens.getStartOffset(tokenIndex); + searchEndOffset = lineTokens.getEndOffset(tokenIndex); + } + } else { + // this token should not be searched + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return r; + } + } + } + + prevSearchInToken = searchInToken; + } + + if (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) { + const r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset); + if (r) { + return r; + } } } diff --git a/src/vs/editor/common/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index f350079ee69..d41d1a2a1ba 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -85,7 +85,7 @@ export function isMultilineRegexSource(searchString: string): boolean { } const nextChCode = searchString.charCodeAt(i); - if (nextChCode === CharCode.n || nextChCode === CharCode.r || nextChCode === CharCode.W) { + if (nextChCode === CharCode.n || nextChCode === CharCode.r || nextChCode === CharCode.W || nextChCode === CharCode.w) { return true; } } @@ -510,7 +510,7 @@ export function isValidMatch(wordSeparators: WordCharacterClassifier, text: stri } export class Searcher { - private readonly _wordSeparators: WordCharacterClassifier | null; + public readonly _wordSeparators: WordCharacterClassifier | null; private readonly _searchRegex: RegExp; private _prevMatchStartIndex: number; private _prevMatchLength: number; diff --git a/src/vs/editor/common/model/textModelTokens.ts b/src/vs/editor/common/model/textModelTokens.ts index 03e1c4bd6b7..e127f50e38d 100644 --- a/src/vs/editor/common/model/textModelTokens.ts +++ b/src/vs/editor/common/model/textModelTokens.ts @@ -16,6 +16,7 @@ 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'; +import * as platform from 'vs/base/common/platform'; const enum Constants { CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048 @@ -196,14 +197,14 @@ export class TextModelTokenization extends Disposable { private readonly _textModel: TextModel; private readonly _tokenizationStateStore: TokenizationStateStore; - private _revalidateTokensTimeout: any; + private _isDisposed: boolean; private _tokenizationSupport: ITokenizationSupport | null; constructor(textModel: TextModel) { super(); + this._isDisposed = false; this._textModel = textModel; this._tokenizationStateStore = new TokenizationStateStore(); - this._revalidateTokensTimeout = -1; this._tokenizationSupport = null; this._register(TokenizationRegistry.onDidChange((e) => { @@ -246,19 +247,11 @@ export class TextModelTokenization extends Disposable { } public dispose(): void { - this._clearTimers(); + this._isDisposed = true; super.dispose(); } - private _clearTimers(): void { - if (this._revalidateTokensTimeout !== -1) { - clearTimeout(this._revalidateTokensTimeout); - this._revalidateTokensTimeout = -1; - } - } - private _resetTokenizationState(): void { - this._clearTimers(); const [tokenizationSupport, initialState] = initializeTokenization(this._textModel); this._tokenizationSupport = tokenizationSupport; this._tokenizationStateStore.flush(initialState); @@ -266,16 +259,19 @@ export class TextModelTokenization extends Disposable { } private _beginBackgroundTokenization(): void { - if (this._textModel.isAttachedToEditor() && this._hasLinesToTokenize() && this._revalidateTokensTimeout === -1) { - this._revalidateTokensTimeout = setTimeout(() => { - this._revalidateTokensTimeout = -1; + if (this._textModel.isAttachedToEditor() && this._hasLinesToTokenize()) { + platform.setImmediate(() => { + if (this._isDisposed) { + // disposed in the meantime + return; + } this._revalidateTokensNow(); - }, 0); + }); } } private _revalidateTokensNow(toLineNumber: number = this._textModel.getLineCount()): void { - const MAX_ALLOWED_TIME = 20; + const MAX_ALLOWED_TIME = 1; const builder = new MultilineTokensBuilder(); const sw = StopWatch.create(false); diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 6da2852d029..02efbb6a722 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -452,7 +452,7 @@ export interface CompletionItem { * *Note:* The range must be a [single line](#Range.isSingleLine) and it must * [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems). */ - range: IRange; + range: IRange | { insert: IRange, replace: IRange }; /** * An optional set of characters that when pressed while this completion is active will accept it first and * then type that character. *Note* that all commit characters should have `length=1` and that superfluous @@ -874,40 +874,82 @@ export const enum SymbolTag { /** * @internal */ -export const symbolKindToCssClass = (function () { +export namespace SymbolKinds { - const _fromMapping: { [n: number]: string } = Object.create(null); - _fromMapping[SymbolKind.File] = 'file'; - _fromMapping[SymbolKind.Module] = 'module'; - _fromMapping[SymbolKind.Namespace] = 'namespace'; - _fromMapping[SymbolKind.Package] = 'package'; - _fromMapping[SymbolKind.Class] = 'class'; - _fromMapping[SymbolKind.Method] = 'method'; - _fromMapping[SymbolKind.Property] = 'property'; - _fromMapping[SymbolKind.Field] = 'field'; - _fromMapping[SymbolKind.Constructor] = 'constructor'; - _fromMapping[SymbolKind.Enum] = 'enum'; - _fromMapping[SymbolKind.Interface] = 'interface'; - _fromMapping[SymbolKind.Function] = 'function'; - _fromMapping[SymbolKind.Variable] = 'variable'; - _fromMapping[SymbolKind.Constant] = 'constant'; - _fromMapping[SymbolKind.String] = 'string'; - _fromMapping[SymbolKind.Number] = 'number'; - _fromMapping[SymbolKind.Boolean] = 'boolean'; - _fromMapping[SymbolKind.Array] = 'array'; - _fromMapping[SymbolKind.Object] = 'object'; - _fromMapping[SymbolKind.Key] = 'key'; - _fromMapping[SymbolKind.Null] = 'null'; - _fromMapping[SymbolKind.EnumMember] = 'enum-member'; - _fromMapping[SymbolKind.Struct] = 'struct'; - _fromMapping[SymbolKind.Event] = 'event'; - _fromMapping[SymbolKind.Operator] = 'operator'; - _fromMapping[SymbolKind.TypeParameter] = 'type-parameter'; + const byName = new Map(); + byName.set('file', SymbolKind.File); + byName.set('module', SymbolKind.Module); + byName.set('namespace', SymbolKind.Namespace); + byName.set('package', SymbolKind.Package); + byName.set('class', SymbolKind.Class); + byName.set('method', SymbolKind.Method); + byName.set('property', SymbolKind.Property); + byName.set('field', SymbolKind.Field); + byName.set('constructor', SymbolKind.Constructor); + byName.set('enum', SymbolKind.Enum); + byName.set('interface', SymbolKind.Interface); + byName.set('function', SymbolKind.Function); + byName.set('variable', SymbolKind.Variable); + byName.set('constant', SymbolKind.Constant); + byName.set('string', SymbolKind.String); + byName.set('number', SymbolKind.Number); + byName.set('boolean', SymbolKind.Boolean); + byName.set('array', SymbolKind.Array); + byName.set('object', SymbolKind.Object); + byName.set('key', SymbolKind.Key); + byName.set('null', SymbolKind.Null); + byName.set('enum-member', SymbolKind.EnumMember); + byName.set('struct', SymbolKind.Struct); + byName.set('event', SymbolKind.Event); + byName.set('operator', SymbolKind.Operator); + byName.set('type-parameter', SymbolKind.TypeParameter); - return function toCssClassName(kind: SymbolKind, inline?: boolean): string { - return `symbol-icon ${inline ? 'inline' : 'block'} ${_fromMapping[kind] || 'property'}`; - }; -})(); + const byKind = new Map(); + byKind.set(SymbolKind.File, 'file'); + byKind.set(SymbolKind.Module, 'module'); + byKind.set(SymbolKind.Namespace, 'namespace'); + byKind.set(SymbolKind.Package, 'package'); + byKind.set(SymbolKind.Class, 'class'); + byKind.set(SymbolKind.Method, 'method'); + byKind.set(SymbolKind.Property, 'property'); + byKind.set(SymbolKind.Field, 'field'); + byKind.set(SymbolKind.Constructor, 'constructor'); + byKind.set(SymbolKind.Enum, 'enum'); + byKind.set(SymbolKind.Interface, 'interface'); + byKind.set(SymbolKind.Function, 'function'); + byKind.set(SymbolKind.Variable, 'variable'); + byKind.set(SymbolKind.Constant, 'constant'); + byKind.set(SymbolKind.String, 'string'); + byKind.set(SymbolKind.Number, 'number'); + byKind.set(SymbolKind.Boolean, 'boolean'); + byKind.set(SymbolKind.Array, 'array'); + byKind.set(SymbolKind.Object, 'object'); + byKind.set(SymbolKind.Key, 'key'); + byKind.set(SymbolKind.Null, 'null'); + byKind.set(SymbolKind.EnumMember, 'enum-member'); + byKind.set(SymbolKind.Struct, 'struct'); + byKind.set(SymbolKind.Event, 'event'); + byKind.set(SymbolKind.Operator, 'operator'); + byKind.set(SymbolKind.TypeParameter, 'type-parameter'); + /** + * @internal + */ + export function fromString(value: string): SymbolKind | undefined { + return byName.get(value); + } + /** + * @internal + */ + export function toString(kind: SymbolKind): string | undefined { + return byKind.get(kind); + } + /** + * @internal + */ + export function toCssClassName(kind: SymbolKind, inline?: boolean): string { + return `codicon ${inline ? 'inline' : 'block'} codicon-symbol-${byKind.get(kind) || 'property'}`; + } +} export interface DocumentSymbol { name: string; @@ -922,7 +964,7 @@ export interface DocumentSymbol { /** * The document symbol provider interface defines the contract between extensions and - * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_goto-symbol)-feature. + * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature. */ export interface DocumentSymbolProvider { @@ -1402,14 +1444,6 @@ export interface IWebviewPanelOptions { readonly retainContextWhenHidden?: boolean; } -/** - * @internal - */ -export const enum WebviewEditorState { - Readonly = 1, - Unchanged = 2, - Dirty = 3, -} export interface CodeLens { range: IRange; diff --git a/src/vs/editor/common/modes/languageConfiguration.ts b/src/vs/editor/common/modes/languageConfiguration.ts index ed8d2fdb4ae..686c7a0dab2 100644 --- a/src/vs/editor/common/modes/languageConfiguration.ts +++ b/src/vs/editor/common/modes/languageConfiguration.ts @@ -247,7 +247,7 @@ export class StandardAutoClosingPairConditional { if (Array.isArray(source.notIn)) { for (let i = 0, len = source.notIn.length; i < len; i++) { - let notIn = source.notIn[i]; + const notIn: string = source.notIn[i]; switch (notIn) { case 'string': this._standardTokenMask |= StandardTokenType.String; diff --git a/src/vs/editor/common/modes/linkComputer.ts b/src/vs/editor/common/modes/linkComputer.ts index 00bf7d01b36..9d381736536 100644 --- a/src/vs/editor/common/modes/linkComputer.ts +++ b/src/vs/editor/common/modes/linkComputer.ts @@ -5,7 +5,6 @@ import { CharCode } from 'vs/base/common/charCode'; import { CharacterClassifier } from 'vs/editor/common/core/characterClassifier'; -import { Uint8Matrix } from 'vs/editor/common/core/uint'; import { ILink } from 'vs/editor/common/modes'; export interface ILinkComputerTarget { @@ -33,6 +32,32 @@ export const enum State { export type Edge = [State, number, State]; +export class Uint8Matrix { + + private readonly _data: Uint8Array; + public readonly rows: number; + public readonly cols: number; + + constructor(rows: number, cols: number, defaultValue: number) { + const data = new Uint8Array(rows * cols); + for (let i = 0, len = rows * cols; i < len; i++) { + data[i] = defaultValue; + } + + this._data = data; + this.rows = rows; + this.cols = cols; + } + + public get(row: number, col: number): number { + return this._data[row * this.cols + col]; + } + + public set(row: number, col: number, value: number): void { + this._data[row * this.cols + col] = value; + } +} + export class StateMachine { private readonly _states: Uint8Matrix; @@ -239,6 +264,10 @@ export class LinkComputer { case CharCode.BackTick: chClass = (linkBeginChCode === CharCode.SingleQuote || linkBeginChCode === CharCode.DoubleQuote) ? CharacterClass.None : CharacterClass.ForceTermination; break; + case CharCode.Asterisk: + // `*` terminates a link if the link began with `*` + chClass = (linkBeginChCode === CharCode.Asterisk) ? CharacterClass.ForceTermination : CharacterClass.None; + break; default: chClass = classifier.get(chCode); } diff --git a/src/vs/editor/common/modes/modesRegistry.ts b/src/vs/editor/common/modes/modesRegistry.ts index fbdda5d65a4..f91dd75d17c 100644 --- a/src/vs/editor/common/modes/modesRegistry.ts +++ b/src/vs/editor/common/modes/modesRegistry.ts @@ -60,5 +60,17 @@ LanguageConfigurationRegistry.register(PLAINTEXT_LANGUAGE_IDENTIFIER, { ['(', ')'], ['[', ']'], ['{', '}'], - ] + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '<', close: '>' }, + { open: '\"', close: '\"' }, + { open: '\'', close: '\'' }, + { open: '`', close: '`' }, + ], + folding: { + offSide: true + } }); diff --git a/src/vs/editor/common/modes/supports/electricCharacter.ts b/src/vs/editor/common/modes/supports/electricCharacter.ts index 387994c28a4..9dee3d4ac88 100644 --- a/src/vs/editor/common/modes/supports/electricCharacter.ts +++ b/src/vs/editor/common/modes/supports/electricCharacter.ts @@ -28,10 +28,11 @@ export class BracketElectricCharacterSupport { let result: string[] = []; if (this._richEditBrackets) { - for (let i = 0, len = this._richEditBrackets.brackets.length; i < len; i++) { - let bracketPair = this._richEditBrackets.brackets[i]; - let lastChar = bracketPair.close.charAt(bracketPair.close.length - 1); - result.push(lastChar); + for (const bracket of this._richEditBrackets.brackets) { + for (const close of bracket.close) { + const lastChar = close.charAt(close.length - 1); + result.push(lastChar); + } } } @@ -56,7 +57,7 @@ export class BracketElectricCharacterSupport { let reversedBracketRegex = this._richEditBrackets.reversedRegex; let text = context.getLineContent().substring(0, column - 1) + character; - let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, 1, text, 0, text.length); + let r = BracketsUtils.findPrevBracketInRange(reversedBracketRegex, 1, text, 0, text.length); if (!r) { return null; } diff --git a/src/vs/editor/common/modes/supports/richEditBrackets.ts b/src/vs/editor/common/modes/supports/richEditBrackets.ts index 758ea39f1ff..ae10537c82e 100644 --- a/src/vs/editor/common/modes/supports/richEditBrackets.ts +++ b/src/vs/editor/common/modes/supports/richEditBrackets.ts @@ -8,27 +8,107 @@ import { Range } from 'vs/editor/common/core/range'; import { LanguageIdentifier } from 'vs/editor/common/modes'; import { CharacterPair } from 'vs/editor/common/modes/languageConfiguration'; -interface ISimpleInternalBracket { - open: string; - close: string; +interface InternalBracket { + open: string[]; + close: string[]; } export class RichEditBracket { _richEditBracketBrand: void; readonly languageIdentifier: LanguageIdentifier; - readonly open: string; - readonly close: string; + readonly index: number; + readonly open: string[]; + readonly close: string[]; readonly forwardRegex: RegExp; readonly reversedRegex: RegExp; + private readonly _openSet: Set; + private readonly _closeSet: Set; - constructor(languageIdentifier: LanguageIdentifier, open: string, close: string, forwardRegex: RegExp, reversedRegex: RegExp) { + constructor(languageIdentifier: LanguageIdentifier, index: number, open: string[], close: string[], forwardRegex: RegExp, reversedRegex: RegExp) { this.languageIdentifier = languageIdentifier; + this.index = index; this.open = open; this.close = close; this.forwardRegex = forwardRegex; this.reversedRegex = reversedRegex; + this._openSet = RichEditBracket._toSet(this.open); + this._closeSet = RichEditBracket._toSet(this.close); } + + public isOpen(text: string) { + return this._openSet.has(text); + } + + public isClose(text: string) { + return this._closeSet.has(text); + } + + private static _toSet(arr: string[]): Set { + const result = new Set(); + for (const element of arr) { + result.add(element); + } + return result; + } +} + +function groupFuzzyBrackets(brackets: CharacterPair[]): InternalBracket[] { + const N = brackets.length; + + brackets = brackets.map(b => [b[0].toLowerCase(), b[1].toLowerCase()]); + + const group: number[] = []; + for (let i = 0; i < N; i++) { + group[i] = i; + } + + const areOverlapping = (a: CharacterPair, b: CharacterPair) => { + const [aOpen, aClose] = a; + const [bOpen, bClose] = b; + return (aOpen === bOpen || aOpen === bClose || aClose === bOpen || aClose === bClose); + }; + + const mergeGroups = (g1: number, g2: number) => { + const newG = Math.min(g1, g2); + const oldG = Math.max(g1, g2); + for (let i = 0; i < N; i++) { + if (group[i] === oldG) { + group[i] = newG; + } + } + }; + + // group together brackets that have the same open or the same close sequence + for (let i = 0; i < N; i++) { + const a = brackets[i]; + for (let j = i + 1; j < N; j++) { + const b = brackets[j]; + if (areOverlapping(a, b)) { + mergeGroups(group[i], group[j]); + } + } + } + + const result: InternalBracket[] = []; + for (let g = 0; g < N; g++) { + let currentOpen: string[] = []; + let currentClose: string[] = []; + for (let i = 0; i < N; i++) { + if (group[i] === g) { + const [open, close] = brackets[i]; + currentOpen.push(open); + currentClose.push(close); + } + } + if (currentOpen.length > 0) { + result.push({ + open: currentOpen, + close: currentClose + }); + } + } + return result; } export class RichEditBrackets { @@ -41,87 +121,140 @@ export class RichEditBrackets { public readonly textIsBracket: { [text: string]: RichEditBracket; }; public readonly textIsOpenBracket: { [text: string]: boolean; }; - constructor(languageIdentifier: LanguageIdentifier, brackets: CharacterPair[]) { - this.brackets = brackets.map((b) => { + constructor(languageIdentifier: LanguageIdentifier, _brackets: CharacterPair[]) { + const brackets = groupFuzzyBrackets(_brackets); + + this.brackets = brackets.map((b, index) => { return new RichEditBracket( languageIdentifier, - b[0], - b[1], - getRegexForBracketPair({ open: b[0], close: b[1] }), - getReversedRegexForBracketPair({ open: b[0], close: b[1] }) + index, + b.open, + b.close, + getRegexForBracketPair(b.open, b.close, brackets, index), + getReversedRegexForBracketPair(b.open, b.close, brackets, index) ); }); + this.forwardRegex = getRegexForBrackets(this.brackets); this.reversedRegex = getReversedRegexForBrackets(this.brackets); this.textIsBracket = {}; this.textIsOpenBracket = {}; - let maxBracketLength = 0; - this.brackets.forEach((b) => { - this.textIsBracket[b.open.toLowerCase()] = b; - this.textIsBracket[b.close.toLowerCase()] = b; - this.textIsOpenBracket[b.open.toLowerCase()] = true; - this.textIsOpenBracket[b.close.toLowerCase()] = false; - maxBracketLength = Math.max(maxBracketLength, b.open.length); - maxBracketLength = Math.max(maxBracketLength, b.close.length); - }); - this.maxBracketLength = maxBracketLength; - } -} - -function once(keyFn: (input: T) => string, computeFn: (input: T) => R): (input: T) => R { - let cache: { [key: string]: R; } = {}; - return (input: T): R => { - let key = keyFn(input); - if (!cache.hasOwnProperty(key)) { - cache[key] = computeFn(input); + this.maxBracketLength = 0; + for (const bracket of this.brackets) { + for (const open of bracket.open) { + this.textIsBracket[open] = bracket; + this.textIsOpenBracket[open] = true; + this.maxBracketLength = Math.max(this.maxBracketLength, open.length); + } + for (const close of bracket.close) { + this.textIsBracket[close] = bracket; + this.textIsOpenBracket[close] = false; + this.maxBracketLength = Math.max(this.maxBracketLength, close.length); + } } - return cache[key]; - }; + } } -const getRegexForBracketPair = once( - (input) => `${input.open};${input.close}`, - (input) => { - return createBracketOrRegExp([input.open, input.close]); +function collectSuperstrings(str: string, brackets: InternalBracket[], currentIndex: number, dest: string[]): void { + for (let i = 0, len = brackets.length; i < len; i++) { + if (i === currentIndex) { + continue; + } + const bracket = brackets[i]; + for (const open of bracket.open) { + if (open.indexOf(str) >= 0) { + dest.push(open); + } + } + for (const close of bracket.close) { + if (close.indexOf(str) >= 0) { + dest.push(close); + } + } } -); +} -const getReversedRegexForBracketPair = once( - (input) => `${input.open};${input.close}`, - (input) => { - return createBracketOrRegExp([toReversedString(input.open), toReversedString(input.close)]); - } -); +function lengthcmp(a: string, b: string) { + return a.length - b.length; +} -const getRegexForBrackets = once( - (input) => input.map(b => `${b.open};${b.close}`).join(';'), - (input) => { - let pieces: string[] = []; - input.forEach((b) => { - pieces.push(b.open); - pieces.push(b.close); - }); - return createBracketOrRegExp(pieces); +function unique(arr: string[]): string[] { + if (arr.length <= 1) { + return arr; } -); + const result: string[] = []; + const seen = new Set(); + for (const element of arr) { + if (seen.has(element)) { + continue; + } + result.push(element); + seen.add(element); + } + return result; +} -const getReversedRegexForBrackets = once( - (input) => input.map(b => `${b.open};${b.close}`).join(';'), - (input) => { - let pieces: string[] = []; - input.forEach((b) => { - pieces.push(toReversedString(b.open)); - pieces.push(toReversedString(b.close)); - }); - return createBracketOrRegExp(pieces); +function getRegexForBracketPair(open: string[], close: string[], brackets: InternalBracket[], currentIndex: number): RegExp { + // search in all brackets for other brackets that are a superstring of these brackets + let pieces: string[] = []; + pieces = pieces.concat(open); + pieces = pieces.concat(close); + for (let i = 0, len = pieces.length; i < len; i++) { + collectSuperstrings(pieces[i], brackets, currentIndex, pieces); } -); + pieces = unique(pieces); + pieces.sort(lengthcmp); + pieces.reverse(); + return createBracketOrRegExp(pieces); +} + +function getReversedRegexForBracketPair(open: string[], close: string[], brackets: InternalBracket[], currentIndex: number): RegExp { + // search in all brackets for other brackets that are a superstring of these brackets + let pieces: string[] = []; + pieces = pieces.concat(open); + pieces = pieces.concat(close); + for (let i = 0, len = pieces.length; i < len; i++) { + collectSuperstrings(pieces[i], brackets, currentIndex, pieces); + } + pieces = unique(pieces); + pieces.sort(lengthcmp); + pieces.reverse(); + return createBracketOrRegExp(pieces.map(toReversedString)); +} + +function getRegexForBrackets(brackets: RichEditBracket[]): RegExp { + let pieces: string[] = []; + for (const bracket of brackets) { + for (const open of bracket.open) { + pieces.push(open); + } + for (const close of bracket.close) { + pieces.push(close); + } + } + pieces = unique(pieces); + return createBracketOrRegExp(pieces); +} + +function getReversedRegexForBrackets(brackets: RichEditBracket[]): RegExp { + let pieces: string[] = []; + for (const bracket of brackets) { + for (const open of bracket.open) { + pieces.push(open); + } + for (const close of bracket.close) { + pieces.push(close); + } + } + pieces = unique(pieces); + return createBracketOrRegExp(pieces.map(toReversedString)); +} function prepareBracketForRegExp(str: string): string { // This bracket pair uses letters like e.g. "begin" - "end" - const insertWordBoundaries = (/^[\w]+$/.test(str)); + const insertWordBoundaries = (/^[\w ]+$/.test(str)); str = strings.escapeRegExpCharacters(str); return (insertWordBoundaries ? `\\b${str}\\b` : str); } @@ -168,12 +301,11 @@ export class BracketsUtils { return new Range(lineNumber, absoluteMatchOffset - matchLength + 1, lineNumber, absoluteMatchOffset + 1); } - public static findPrevBracketInToken(reversedBracketRegex: RegExp, lineNumber: number, lineText: string, currentTokenStart: number, currentTokenEnd: number): Range | null { + public static findPrevBracketInRange(reversedBracketRegex: RegExp, lineNumber: number, lineText: string, startOffset: number, endOffset: number): Range | null { // Because JS does not support backwards regex search, we search forwards in a reversed string with a reversed regex ;) - let reversedLineText = toReversedString(lineText); - let reversedTokenText = reversedLineText.substring(lineText.length - currentTokenEnd, lineText.length - currentTokenStart); - - return this._findPrevBracketInText(reversedBracketRegex, lineNumber, reversedTokenText, currentTokenStart); + const reversedLineText = toReversedString(lineText); + const reversedSubstr = reversedLineText.substring(lineText.length - endOffset, lineText.length - startOffset); + return this._findPrevBracketInText(reversedBracketRegex, lineNumber, reversedSubstr, startOffset); } public static findNextBracketInText(bracketRegex: RegExp, lineNumber: number, text: string, offset: number): Range | null { @@ -193,10 +325,8 @@ export class BracketsUtils { return new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength); } - public static findNextBracketInToken(bracketRegex: RegExp, lineNumber: number, lineText: string, currentTokenStart: number, currentTokenEnd: number): Range | null { - let currentTokenText = lineText.substring(currentTokenStart, currentTokenEnd); - - return this.findNextBracketInText(bracketRegex, lineNumber, currentTokenText, currentTokenStart); + public static findNextBracketInRange(bracketRegex: RegExp, lineNumber: number, lineText: string, startOffset: number, endOffset: number): Range | null { + const substr = lineText.substring(startOffset, endOffset); + return this.findNextBracketInText(bracketRegex, lineNumber, substr, startOffset); } - } diff --git a/src/vs/editor/common/modes/textToHtmlTokenizer.ts b/src/vs/editor/common/modes/textToHtmlTokenizer.ts index af5a682bc37..e98f2b37f19 100644 --- a/src/vs/editor/common/modes/textToHtmlTokenizer.ts +++ b/src/vs/editor/common/modes/textToHtmlTokenizer.ts @@ -24,7 +24,7 @@ export function tokenizeToString(text: string, tokenizationSupport: IReducedToke return _tokenizeToString(text, tokenizationSupport || fallback); } -export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens, colorMap: string[], startOffset: number, endOffset: number, tabSize: number): string { +export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens, colorMap: string[], startOffset: number, endOffset: number, tabSize: number, useNbsp: boolean): string { let result = `
`; let charIndex = startOffset; let tabsCharDelta = 0; @@ -46,7 +46,7 @@ export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens let insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize; tabsCharDelta += insertSpacesCount - 1; while (insertSpacesCount > 0) { - partContent += ' '; + partContent += useNbsp ? ' ' : ' '; insertSpacesCount--; } break; @@ -78,7 +78,7 @@ export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens break; case CharCode.Space: - partContent += ' '; + partContent += useNbsp ? ' ' : ' '; break; default: diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index 06c11b3303e..01ca792e497 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -17,7 +17,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { EndOfLineSequence, IWordAtPosition } from 'vs/editor/common/model'; import { IModelChangedEvent, MirrorTextModel as BaseMirrorModel } from 'vs/editor/common/model/mirrorTextModel'; import { ensureValidWordDefinition, getWordAtText } from 'vs/editor/common/model/wordHelper'; -import { CompletionItem, CompletionItemKind, CompletionList, IInplaceReplaceSupportResult, ILink, TextEdit } from 'vs/editor/common/modes'; +import { IInplaceReplaceSupportResult, ILink, TextEdit } from 'vs/editor/common/modes'; import { ILinkComputerTarget, computeLinks } from 'vs/editor/common/modes/linkComputer'; import { BasicInplaceReplace } from 'vs/editor/common/modes/supports/inplaceReplaceSupport'; import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService'; @@ -377,11 +377,11 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { // ---- BEGIN diff -------------------------------------------------------------------------- - public computeDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): Promise { + public async computeDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise { const original = this._getModel(originalUrl); const modified = this._getModel(modifiedUrl); if (!original || !modified) { - return Promise.resolve(null); + return null; } const originalLines = original.getLinesContent(); @@ -390,15 +390,17 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { shouldComputeCharChanges: true, shouldPostProcessCharChanges: true, shouldIgnoreTrimWhitespace: ignoreTrimWhitespace, - shouldMakePrettyDiff: true + shouldMakePrettyDiff: true, + maxComputationTime: maxComputationTime }); - const changes = diffComputer.computeDiff(); - let identical = (changes.length > 0 ? false : this._modelsAreIdentical(original, modified)); - return Promise.resolve({ + const diffResult = diffComputer.computeDiff(); + const identical = (diffResult.changes.length > 0 ? false : this._modelsAreIdentical(original, modified)); + return { + quitEarly: diffResult.quitEarly, identical: identical, - changes: changes - }); + changes: diffResult.changes + }; } private _modelsAreIdentical(original: ICommonModel, modified: ICommonModel): boolean { @@ -417,11 +419,11 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { return true; } - public computeDirtyDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): Promise { + public async computeDirtyDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean): Promise { let original = this._getModel(originalUrl); let modified = this._getModel(modifiedUrl); if (!original || !modified) { - return Promise.resolve(null); + return null; } let originalLines = original.getLinesContent(); @@ -430,9 +432,10 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { shouldComputeCharChanges: false, shouldPostProcessCharChanges: false, shouldIgnoreTrimWhitespace: ignoreTrimWhitespace, - shouldMakePrettyDiff: true + shouldMakePrettyDiff: true, + maxComputationTime: 1000 }); - return Promise.resolve(diffComputer.computeDiff()); + return diffComputer.computeDiff().changes; } // ---- END diff -------------------------------------------------------------------------- @@ -442,10 +445,10 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { private static readonly _diffLimit = 100000; - public computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): Promise { + public async computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): Promise { const model = this._getModel(modelUrl); if (!model) { - return Promise.resolve(edits); + return edits; } const result: TextEdit[] = []; @@ -508,62 +511,56 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { result.push({ eol: lastEol, text: '', range: { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 } }); } - return Promise.resolve(result); + return result; } // ---- END minimal edits --------------------------------------------------------------- - public computeLinks(modelUrl: string): Promise { + public async computeLinks(modelUrl: string): Promise { let model = this._getModel(modelUrl); if (!model) { - return Promise.resolve(null); + return null; } - return Promise.resolve(computeLinks(model)); + return computeLinks(model); } // ---- BEGIN suggest -------------------------------------------------------------------------- private static readonly _suggestionsLimit = 10000; - public textualSuggest(modelUrl: string, position: IPosition, wordDef: string, wordDefFlags: string): Promise { + public async textualSuggest(modelUrl: string, position: IPosition, wordDef: string, wordDefFlags: string): Promise { const model = this._getModel(modelUrl); if (!model) { - return Promise.resolve(null); + return null; } - const seen: Record = Object.create(null); - const suggestions: CompletionItem[] = []; + + const words: string[] = []; + const seen = new Set(); const wordDefRegExp = new RegExp(wordDef, wordDefFlags); - const wordUntil = model.getWordUntilPosition(position, wordDefRegExp); const wordAt = model.getWordAtPosition(position, wordDefRegExp); if (wordAt) { - seen[model.getValueInRange(wordAt)] = true; + seen.add(model.getValueInRange(wordAt)); } for ( let iter = model.createWordIterator(wordDefRegExp), e = iter.next(); - !e.done && suggestions.length <= EditorSimpleWorker._suggestionsLimit; + !e.done && seen.size <= EditorSimpleWorker._suggestionsLimit; e = iter.next() ) { const word = e.value; - if (seen[word]) { + if (seen.has(word)) { continue; } - seen[word] = true; + seen.add(word); if (!isNaN(Number(word))) { continue; } - - suggestions.push({ - kind: CompletionItemKind.Text, - label: word, - insertText: word, - range: { startLineNumber: position.lineNumber, startColumn: wordUntil.startColumn, endLineNumber: position.lineNumber, endColumn: wordUntil.endColumn } - }); + words.push(word); } - return Promise.resolve({ suggestions }); + return words; } @@ -571,10 +568,10 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { //#region -- word ranges -- - computeWordRanges(modelUrl: string, range: IRange, wordDef: string, wordDefFlags: string): Promise<{ [word: string]: IRange[] }> { + public async computeWordRanges(modelUrl: string, range: IRange, wordDef: string, wordDefFlags: string): Promise<{ [word: string]: IRange[] }> { let model = this._getModel(modelUrl); if (!model) { - return Promise.resolve(Object.create(null)); + return Object.create(null); } const wordDefRegExp = new RegExp(wordDef, wordDefFlags); const result: { [word: string]: IRange[] } = Object.create(null); @@ -597,15 +594,15 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { }); } } - return Promise.resolve(result); + return result; } //#endregion - public navigateValueSet(modelUrl: string, range: IRange, up: boolean, wordDef: string, wordDefFlags: string): Promise { + public async navigateValueSet(modelUrl: string, range: IRange, up: boolean, wordDef: string, wordDefFlags: string): Promise { let model = this._getModel(modelUrl); if (!model) { - return Promise.resolve(null); + return null; } let wordDefRegExp = new RegExp(wordDef, wordDefFlags); @@ -623,11 +620,11 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable { let wordRange = model.getWordAtPosition({ lineNumber: range.startLineNumber, column: range.startColumn }, wordDefRegExp); if (!wordRange) { - return Promise.resolve(null); + return null; } let word = model.getValueInRange(wordRange); let result = BasicInplaceReplace.INSTANCE.navigateValueSet(range, selectionText, wordRange, word, up); - return Promise.resolve(result); + return result; } // ---- BEGIN foreign module support -------------------------------------------------------------------------- diff --git a/src/vs/editor/common/services/editorWorkerService.ts b/src/vs/editor/common/services/editorWorkerService.ts index bd217b1944d..ab850e96a2c 100644 --- a/src/vs/editor/common/services/editorWorkerService.ts +++ b/src/vs/editor/common/services/editorWorkerService.ts @@ -13,6 +13,7 @@ export const ID_EDITOR_WORKER_SERVICE = 'editorWorkerService'; export const IEditorWorkerService = createDecorator(ID_EDITOR_WORKER_SERVICE); export interface IDiffComputationResult { + quitEarly: boolean; identical: boolean; changes: ILineChange[]; } @@ -21,7 +22,7 @@ export interface IEditorWorkerService { _serviceBrand: undefined; canComputeDiff(original: URI, modified: URI): boolean; - computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise; + computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise; canComputeDirtyDiff(original: URI, modified: URI): boolean; computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise; diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index 9267a035826..f2061ba0b4c 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { SimpleWorkerClient, logOnceWebWorkerWarning, IWorkerClient } from 'vs/base/common/worker/simpleWorker'; import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory'; import { IPosition, Position } from 'vs/editor/common/core/position'; -import { IRange } from 'vs/editor/common/core/range'; +import { IRange, Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import * as modes from 'vs/editor/common/modes'; @@ -82,8 +82,8 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker return (canSyncModel(this._modelService, original) && canSyncModel(this._modelService, modified)); } - public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise { - return this._workerManager.withWorker().then(client => client.computeDiff(original, modified, ignoreTrimWhitespace)); + public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise { + return this._workerManager.withWorker().then(client => client.computeDiff(original, modified, ignoreTrimWhitespace, maxComputationTime)); } public canComputeDirtyDiff(original: URI, modified: URI): boolean { @@ -144,7 +144,7 @@ class WordBasedCompletionItemProvider implements modes.CompletionItemProvider { this._modelService = modelService; } - provideCompletionItems(model: ITextModel, position: Position): Promise | undefined { + async provideCompletionItems(model: ITextModel, position: Position): Promise { const { wordBasedSuggestions } = this._configurationService.getValue<{ wordBasedSuggestions?: boolean }>(model.uri, position, 'editor'); if (!wordBasedSuggestions) { return undefined; @@ -152,7 +152,27 @@ class WordBasedCompletionItemProvider implements modes.CompletionItemProvider { if (!canSyncModel(this._modelService, model.uri)) { return undefined; // File too large } - return this._workerManager.withWorker().then(client => client.textualSuggest(model.uri, position)); + + const word = model.getWordAtPosition(position); + const replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn); + const insert = replace.setEndPosition(position.lineNumber, position.column); + + const client = await this._workerManager.withWorker(); + const words = await client.textualSuggest(model.uri, position); + if (!words) { + return undefined; + } + + return { + suggestions: words.map((word): modes.CompletionItem => { + return { + kind: modes.CompletionItemKind.Text, + label: word, + insertText: word, + range: { insert, replace } + }; + }) + }; } } @@ -409,9 +429,9 @@ export class EditorWorkerClient extends Disposable { }); } - public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise { + public computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise { return this._withSyncedResources([original, modified]).then(proxy => { - return proxy.computeDiff(original.toString(), modified.toString(), ignoreTrimWhitespace); + return proxy.computeDiff(original.toString(), modified.toString(), ignoreTrimWhitespace, maxComputationTime); }); } @@ -433,7 +453,7 @@ export class EditorWorkerClient extends Disposable { }); } - public textualSuggest(resource: URI, position: IPosition): Promise { + public textualSuggest(resource: URI, position: IPosition): Promise { return this._withSyncedResources([resource]).then(proxy => { let model = this._modelService.getModel(resource); if (!model) { diff --git a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts index c2140eff46d..dff0d9924aa 100644 --- a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts +++ b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts @@ -95,7 +95,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor return markerDecorations ? markerDecorations.getMarkers() : []; } - private _handleMarkerChange(changedResources: URI[]): void { + private _handleMarkerChange(changedResources: readonly URI[]): void { changedResources.forEach((resource) => { const markerDecorations = this._markerDecorations.get(MODEL_ID(resource)); if (markerDecorations) { diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 01d2d990579..f7788996ded 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -223,6 +223,10 @@ export class ModelServiceImpl extends Disposable implements IModelService { } private static _setModelOptionsForModel(model: ITextModel, newOptions: ITextModelCreationOptions, currentOptions: ITextModelCreationOptions): void { + if (currentOptions && currentOptions.defaultEOL !== newOptions.defaultEOL && model.getLineCount() === 1) { + model.setEOL(newOptions.defaultEOL === DefaultEndOfLine.LF ? EndOfLineSequence.LF : EndOfLineSequence.CRLF); + } + if (currentOptions && (currentOptions.detectIndentation === newOptions.detectIndentation) && (currentOptions.insertSpaces === newOptions.insertSpaces) diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 8ef13878743..9d227632149 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -403,10 +403,8 @@ export enum TextEditorCursorStyle { export enum RenderMinimap { None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4 + Text = 1, + Blocks = 2 } export enum RenderLineNumbersType { diff --git a/src/vs/editor/common/view/minimapCharRenderer.ts b/src/vs/editor/common/view/minimapCharRenderer.ts deleted file mode 100644 index f47962e4c0f..00000000000 --- a/src/vs/editor/common/view/minimapCharRenderer.ts +++ /dev/null @@ -1,349 +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 { Emitter, Event } from 'vs/base/common/event'; -import { RGBA8 } from 'vs/editor/common/core/rgba'; -import { ColorId, TokenizationRegistry } from 'vs/editor/common/modes'; - -export class MinimapTokensColorTracker { - private static _INSTANCE: MinimapTokensColorTracker | null = null; - public static getInstance(): MinimapTokensColorTracker { - if (!this._INSTANCE) { - this._INSTANCE = new MinimapTokensColorTracker(); - } - return this._INSTANCE; - } - - private _colors!: RGBA8[]; - private _backgroundIsLight!: boolean; - - private readonly _onDidChange = new Emitter(); - public readonly onDidChange: Event = this._onDidChange.event; - - private constructor() { - this._updateColorMap(); - TokenizationRegistry.onDidChange((e) => { - if (e.changedColorMap) { - this._updateColorMap(); - } - }); - } - - private _updateColorMap(): void { - const colorMap = TokenizationRegistry.getColorMap(); - if (!colorMap) { - this._colors = [RGBA8.Empty]; - this._backgroundIsLight = true; - return; - } - this._colors = [RGBA8.Empty]; - for (let colorId = 1; colorId < colorMap.length; colorId++) { - const source = colorMap[colorId].rgba; - // Use a VM friendly data-type - this._colors[colorId] = new RGBA8(source.r, source.g, source.b, Math.round(source.a * 255)); - } - let backgroundLuminosity = colorMap[ColorId.DefaultBackground].getRelativeLuminance(); - this._backgroundIsLight = (backgroundLuminosity >= 0.5); - this._onDidChange.fire(undefined); - } - - public getColor(colorId: ColorId): RGBA8 { - if (colorId < 1 || colorId >= this._colors.length) { - // background color (basically invisible) - colorId = ColorId.DefaultBackground; - } - return this._colors[colorId]; - } - - public backgroundIsLight(): boolean { - return this._backgroundIsLight; - } -} - -export const enum Constants { - START_CH_CODE = 32, // Space - END_CH_CODE = 126, // Tilde (~) - CHAR_COUNT = END_CH_CODE - START_CH_CODE + 1, - - SAMPLED_CHAR_HEIGHT = 16, - SAMPLED_CHAR_WIDTH = 10, - SAMPLED_HALF_CHAR_WIDTH = SAMPLED_CHAR_WIDTH / 2, - - x2_CHAR_HEIGHT = 4, - x2_CHAR_WIDTH = 2, - - x1_CHAR_HEIGHT = 2, - x1_CHAR_WIDTH = 1, - - RGBA_CHANNELS_CNT = 4, -} - -export class MinimapCharRenderer { - - _minimapCharRendererBrand: void; - - public readonly x2charData: Uint8ClampedArray; - public readonly x1charData: Uint8ClampedArray; - - public readonly x2charDataLight: Uint8ClampedArray; - public readonly x1charDataLight: Uint8ClampedArray; - - constructor(x2CharData: Uint8ClampedArray, x1CharData: Uint8ClampedArray) { - const x2ExpectedLen = Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * Constants.CHAR_COUNT; - if (x2CharData.length !== x2ExpectedLen) { - throw new Error('Invalid x2CharData'); - } - const x1ExpectedLen = Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * Constants.CHAR_COUNT; - if (x1CharData.length !== x1ExpectedLen) { - throw new Error('Invalid x1CharData'); - } - this.x2charData = x2CharData; - this.x1charData = x1CharData; - - this.x2charDataLight = MinimapCharRenderer.soften(x2CharData, 12 / 15); - this.x1charDataLight = MinimapCharRenderer.soften(x1CharData, 50 / 60); - } - - private static soften(input: Uint8ClampedArray, ratio: number): Uint8ClampedArray { - let result = new Uint8ClampedArray(input.length); - for (let i = 0, len = input.length; i < len; i++) { - result[i] = input[i] * ratio; - } - return result; - } - - private static _getChIndex(chCode: number): number { - chCode -= Constants.START_CH_CODE; - if (chCode < 0) { - chCode += Constants.CHAR_COUNT; - } - return (chCode % Constants.CHAR_COUNT); - } - - public x2RenderChar(target: ImageData, dx: number, dy: number, chCode: number, color: RGBA8, backgroundColor: RGBA8, useLighterFont: boolean): void { - if (dx + Constants.x2_CHAR_WIDTH > target.width || dy + Constants.x2_CHAR_HEIGHT > target.height) { - console.warn('bad render request outside image data'); - return; - } - const x2CharData = useLighterFont ? this.x2charDataLight : this.x2charData; - const chIndex = MinimapCharRenderer._getChIndex(chCode); - - const outWidth = target.width * Constants.RGBA_CHANNELS_CNT; - - const backgroundR = backgroundColor.r; - const backgroundG = backgroundColor.g; - const backgroundB = backgroundColor.b; - - const deltaR = color.r - backgroundR; - const deltaG = color.g - backgroundG; - const deltaB = color.b - backgroundB; - - const dest = target.data; - const sourceOffset = chIndex * Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH; - let destOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT; - { - const c = x2CharData[sourceOffset] / 255; - dest[destOffset + 0] = backgroundR + deltaR * c; - dest[destOffset + 1] = backgroundG + deltaG * c; - dest[destOffset + 2] = backgroundB + deltaB * c; - } - { - const c = x2CharData[sourceOffset + 1] / 255; - dest[destOffset + 4] = backgroundR + deltaR * c; - dest[destOffset + 5] = backgroundG + deltaG * c; - dest[destOffset + 6] = backgroundB + deltaB * c; - } - - destOffset += outWidth; - { - const c = x2CharData[sourceOffset + 2] / 255; - dest[destOffset + 0] = backgroundR + deltaR * c; - dest[destOffset + 1] = backgroundG + deltaG * c; - dest[destOffset + 2] = backgroundB + deltaB * c; - } - { - const c = x2CharData[sourceOffset + 3] / 255; - dest[destOffset + 4] = backgroundR + deltaR * c; - dest[destOffset + 5] = backgroundG + deltaG * c; - dest[destOffset + 6] = backgroundB + deltaB * c; - } - - destOffset += outWidth; - { - const c = x2CharData[sourceOffset + 4] / 255; - dest[destOffset + 0] = backgroundR + deltaR * c; - dest[destOffset + 1] = backgroundG + deltaG * c; - dest[destOffset + 2] = backgroundB + deltaB * c; - } - { - const c = x2CharData[sourceOffset + 5] / 255; - dest[destOffset + 4] = backgroundR + deltaR * c; - dest[destOffset + 5] = backgroundG + deltaG * c; - dest[destOffset + 6] = backgroundB + deltaB * c; - } - - destOffset += outWidth; - { - const c = x2CharData[sourceOffset + 6] / 255; - dest[destOffset + 0] = backgroundR + deltaR * c; - dest[destOffset + 1] = backgroundG + deltaG * c; - dest[destOffset + 2] = backgroundB + deltaB * c; - } - { - const c = x2CharData[sourceOffset + 7] / 255; - dest[destOffset + 4] = backgroundR + deltaR * c; - dest[destOffset + 5] = backgroundG + deltaG * c; - dest[destOffset + 6] = backgroundB + deltaB * c; - } - } - - public x1RenderChar(target: ImageData, dx: number, dy: number, chCode: number, color: RGBA8, backgroundColor: RGBA8, useLighterFont: boolean): void { - if (dx + Constants.x1_CHAR_WIDTH > target.width || dy + Constants.x1_CHAR_HEIGHT > target.height) { - console.warn('bad render request outside image data'); - return; - } - const x1CharData = useLighterFont ? this.x1charDataLight : this.x1charData; - const chIndex = MinimapCharRenderer._getChIndex(chCode); - - const outWidth = target.width * Constants.RGBA_CHANNELS_CNT; - - const backgroundR = backgroundColor.r; - const backgroundG = backgroundColor.g; - const backgroundB = backgroundColor.b; - - const deltaR = color.r - backgroundR; - const deltaG = color.g - backgroundG; - const deltaB = color.b - backgroundB; - - const dest = target.data; - const sourceOffset = chIndex * Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH; - let destOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT; - { - const c = x1CharData[sourceOffset] / 255; - dest[destOffset + 0] = backgroundR + deltaR * c; - dest[destOffset + 1] = backgroundG + deltaG * c; - dest[destOffset + 2] = backgroundB + deltaB * c; - } - - destOffset += outWidth; - { - const c = x1CharData[sourceOffset + 1] / 255; - dest[destOffset + 0] = backgroundR + deltaR * c; - dest[destOffset + 1] = backgroundG + deltaG * c; - dest[destOffset + 2] = backgroundB + deltaB * c; - } - } - - public x2BlockRenderChar(target: ImageData, dx: number, dy: number, color: RGBA8, backgroundColor: RGBA8, useLighterFont: boolean): void { - if (dx + Constants.x2_CHAR_WIDTH > target.width || dy + Constants.x2_CHAR_HEIGHT > target.height) { - console.warn('bad render request outside image data'); - return; - } - - const outWidth = target.width * Constants.RGBA_CHANNELS_CNT; - - const c = 0.5; - - const backgroundR = backgroundColor.r; - const backgroundG = backgroundColor.g; - const backgroundB = backgroundColor.b; - - const deltaR = color.r - backgroundR; - const deltaG = color.g - backgroundG; - const deltaB = color.b - backgroundB; - - const colorR = backgroundR + deltaR * c; - const colorG = backgroundG + deltaG * c; - const colorB = backgroundB + deltaB * c; - - const dest = target.data; - let destOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT; - { - dest[destOffset + 0] = colorR; - dest[destOffset + 1] = colorG; - dest[destOffset + 2] = colorB; - } - { - dest[destOffset + 4] = colorR; - dest[destOffset + 5] = colorG; - dest[destOffset + 6] = colorB; - } - - destOffset += outWidth; - { - dest[destOffset + 0] = colorR; - dest[destOffset + 1] = colorG; - dest[destOffset + 2] = colorB; - } - { - dest[destOffset + 4] = colorR; - dest[destOffset + 5] = colorG; - dest[destOffset + 6] = colorB; - } - - destOffset += outWidth; - { - dest[destOffset + 0] = colorR; - dest[destOffset + 1] = colorG; - dest[destOffset + 2] = colorB; - } - { - dest[destOffset + 4] = colorR; - dest[destOffset + 5] = colorG; - dest[destOffset + 6] = colorB; - } - - destOffset += outWidth; - { - dest[destOffset + 0] = colorR; - dest[destOffset + 1] = colorG; - dest[destOffset + 2] = colorB; - } - { - dest[destOffset + 4] = colorR; - dest[destOffset + 5] = colorG; - dest[destOffset + 6] = colorB; - } - } - - public x1BlockRenderChar(target: ImageData, dx: number, dy: number, color: RGBA8, backgroundColor: RGBA8, useLighterFont: boolean): void { - if (dx + Constants.x1_CHAR_WIDTH > target.width || dy + Constants.x1_CHAR_HEIGHT > target.height) { - console.warn('bad render request outside image data'); - return; - } - - const outWidth = target.width * Constants.RGBA_CHANNELS_CNT; - - const c = 0.5; - - const backgroundR = backgroundColor.r; - const backgroundG = backgroundColor.g; - const backgroundB = backgroundColor.b; - - const deltaR = color.r - backgroundR; - const deltaG = color.g - backgroundG; - const deltaB = color.b - backgroundB; - - const colorR = backgroundR + deltaR * c; - const colorG = backgroundG + deltaG * c; - const colorB = backgroundB + deltaB * c; - - const dest = target.data; - - let destOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT; - { - dest[destOffset + 0] = colorR; - dest[destOffset + 1] = colorG; - dest[destOffset + 2] = colorB; - } - - destOffset += outWidth; - { - dest[destOffset + 0] = colorR; - dest[destOffset + 1] = colorG; - dest[destOffset + 2] = colorB; - } - } -} diff --git a/src/vs/editor/common/view/renderingContext.ts b/src/vs/editor/common/view/renderingContext.ts index 6a3e7beba91..c7b9665b7a4 100644 --- a/src/vs/editor/common/view/renderingContext.ts +++ b/src/vs/editor/common/view/renderingContext.ts @@ -10,7 +10,7 @@ import { IViewLayout, ViewModelDecoration } from 'vs/editor/common/viewModel/vie export interface IViewLines { linesVisibleRangesForRange(range: Range, includeNewLines: boolean): LineVisibleRanges[] | null; - visibleRangeForPosition(position: Position): HorizontalRange | null; + visibleRangeForPosition(position: Position): HorizontalPosition | null; } export abstract class RestrictedRenderingContext { @@ -77,26 +77,20 @@ export class RenderingContext extends RestrictedRenderingContext { return this._viewLines.linesVisibleRangesForRange(range, includeNewLines); } - public visibleRangeForPosition(position: Position): HorizontalRange | null { + public visibleRangeForPosition(position: Position): HorizontalPosition | null { return this._viewLines.visibleRangeForPosition(position); } } export class LineVisibleRanges { - _lineVisibleRangesBrand: void; - - public lineNumber: number; - public ranges: HorizontalRange[]; - - constructor(lineNumber: number, ranges: HorizontalRange[]) { - this.lineNumber = lineNumber; - this.ranges = ranges; - } + constructor( + public readonly outsideRenderedLine: boolean, + public readonly lineNumber: number, + public readonly ranges: HorizontalRange[] + ) { } } export class HorizontalRange { - _horizontalRangeBrand: void; - public left: number; public width: number; @@ -109,3 +103,21 @@ export class HorizontalRange { return `[${this.left},${this.width}]`; } } + +export class HorizontalPosition { + public outsideRenderedLine: boolean; + public left: number; + + constructor(outsideRenderedLine: boolean, left: number) { + this.outsideRenderedLine = outsideRenderedLine; + this.left = Math.round(left); + } +} + +export class VisibleRanges { + constructor( + public readonly outsideRenderedLine: boolean, + public readonly ranges: HorizontalRange[] + ) { + } +} diff --git a/src/vs/editor/common/view/runtimeMinimapCharRenderer.ts b/src/vs/editor/common/view/runtimeMinimapCharRenderer.ts deleted file mode 100644 index 21f84e3fe98..00000000000 --- a/src/vs/editor/common/view/runtimeMinimapCharRenderer.ts +++ /dev/null @@ -1,985 +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 { MinimapCharRenderer } from 'vs/editor/common/view/minimapCharRenderer'; - -function toUint8ClampedArrat(arr: number[]): Uint8ClampedArray { - let r = new Uint8ClampedArray(arr.length); - for (let i = 0, len = arr.length; i < len; i++) { - r[i] = arr[i]; - } - return r; -} - -let minimapCharRenderer: MinimapCharRenderer | null = null; -export function getOrCreateMinimapCharRenderer(): MinimapCharRenderer { - if (!minimapCharRenderer) { - let _x1Data = toUint8ClampedArrat(x1Data!); - x1Data = null; - - let _x2Data = toUint8ClampedArrat(x2Data!); - x2Data = null; - minimapCharRenderer = new MinimapCharRenderer(_x2Data, _x1Data); - } - return minimapCharRenderer; -} - -let x2Data: number[] | null = [ - - // - 0, 0, - 0, 0, - 0, 0, - 0, 0, - - // ! - 39, 14, - 39, 14, - 14, 5, - 29, 10, - - // " - 96, 96, - 29, 29, - 0, 0, - 0, 0, - - // # - 49, 113, - 195, 214, - 227, 166, - 135, 42, - - // $ - 40, 29, - 194, 38, - 75, 148, - 197, 187, - - // % - 145, 0, - 160, 61, - 75, 143, - 2, 183, - - // & - 138, 58, - 163, 6, - 177, 223, - 197, 227, - - // ' - 38, 13, - 11, 4, - 0, 0, - 0, 0, - - // ( - 10, 54, - 52, 8, - 62, 4, - 71, 122, - - // ) - 73, 2, - 19, 40, - 10, 50, - 155, 36, - - // * - 79, 70, - 145, 121, - 7, 5, - 0, 0, - - // + - 2, 1, - 36, 12, - 204, 166, - 16, 5, - - // , - 0, 0, - 0, 0, - 1, 0, - 154, 34, - - // - - 0, 0, - 0, 0, - 96, 83, - 0, 0, - - // . - 0, 0, - 0, 0, - 0, 0, - 46, 34, - - // / - 0, 82, - 2, 56, - 53, 3, - 146, 0, - - // 0 - 146, 119, - 152, 132, - 152, 131, - 145, 119, - - // 1 - 170, 42, - 15, 42, - 15, 42, - 172, 194, - - // 2 - 131, 132, - 0, 139, - 80, 28, - 227, 143, - - // 3 - 159, 135, - 15, 118, - 11, 126, - 171, 144, - - // 4 - 20, 124, - 88, 106, - 217, 196, - 0, 106, - - // 5 - 189, 92, - 168, 43, - 5, 130, - 164, 133, - - // 6 - 130, 115, - 183, 65, - 134, 120, - 141, 141, - - // 7 - 170, 196, - 2, 106, - 31, 32, - 105, 2, - - // 8 - 145, 130, - 116, 114, - 132, 135, - 138, 140, - - // 9 - 138, 113, - 147, 137, - 81, 183, - 129, 94, - - // : - 0, 0, - 21, 16, - 4, 3, - 46, 34, - - // ; - 0, 0, - 45, 34, - 1, 0, - 160, 49, - - // < - 0, 0, - 43, 143, - 203, 23, - 1, 76, - - // = - 0, 0, - 38, 28, - 131, 96, - 38, 28, - - // > - 0, 0, - 168, 31, - 29, 191, - 98, 0, - - // ? - 118, 139, - 5, 113, - 45, 13, - 37, 6, - - // @ - 97, 115, - 161, 179, - 204, 105, - 223, 224, - - // A - 83, 52, - 111, 100, - 184, 186, - 120, 132, - - // B - 212, 145, - 180, 139, - 174, 161, - 212, 182, - - // C - 104, 162, - 131, 0, - 131, 0, - 104, 161, - - // D - 219, 120, - 110, 116, - 110, 116, - 219, 120, - - // E - 207, 154, - 163, 40, - 147, 22, - 207, 154, - - // F - 202, 159, - 161, 47, - 145, 23, - 111, 0, - - // G - 139, 154, - 144, 30, - 144, 135, - 139, 187, - - // H - 110, 110, - 168, 161, - 150, 145, - 110, 110, - - // I - 185, 162, - 43, 16, - 43, 16, - 185, 162, - - // J - 73, 129, - 0, 110, - 0, 110, - 191, 87, - - // K - 149, 149, - 236, 48, - 195, 91, - 146, 149, - - // L - 146, 0, - 146, 0, - 146, 0, - 187, 173, - - // M - 200, 201, - 222, 215, - 172, 147, - 95, 95, - - // N - 193, 97, - 224, 129, - 159, 206, - 97, 192, - - // O - 155, 139, - 153, 115, - 153, 115, - 156, 140, - - // P - 189, 158, - 123, 136, - 190, 64, - 111, 0, - - // Q - 155, 139, - 153, 115, - 153, 114, - 156, 241, - - // R - 197, 148, - 150, 152, - 170, 116, - 110, 157, - - // S - 156, 128, - 169, 14, - 13, 159, - 158, 149, - - // T - 212, 189, - 43, 16, - 43, 16, - 43, 16, - - // U - 148, 110, - 148, 110, - 147, 109, - 182, 151, - - // V - 133, 121, - 106, 118, - 114, 103, - 89, 66, - - // W - 94, 94, - 211, 188, - 205, 207, - 139, 168, - - // X - 151, 152, - 87, 76, - 101, 79, - 151, 152, - - // Y - 130, 156, - 125, 116, - 47, 29, - 43, 16, - - // Z - 169, 228, - 11, 103, - 120, 6, - 230, 176, - - // [ - 55, 49, - 55, 6, - 55, 6, - 193, 102, - - // \ - 92, 0, - 71, 0, - 13, 30, - 0, 147, - - // ] - 63, 43, - 12, 43, - 12, 43, - 142, 152, - - // ^ - 71, 53, - 61, 61, - 0, 0, - 0, 0, - - // _ - 0, 0, - 0, 0, - 0, 0, - 158, 146, - - // ` - 25, 2, - 0, 0, - 0, 0, - 0, 0, - - // a - 0, 0, - 107, 130, - 170, 194, - 176, 188, - - // b - 109, 0, - 203, 159, - 113, 111, - 202, 158, - - // c - 0, 0, - 135, 135, - 114, 0, - 136, 135, - - // d - 0, 109, - 187, 190, - 148, 126, - 177, 187, - - // e - 0, 0, - 149, 130, - 218, 105, - 169, 135, - - // f - 37, 113, - 146, 113, - 49, 13, - 49, 13, - - // g - 0, 0, - 178, 195, - 147, 114, - 255, 255, - - // h - 109, 0, - 193, 149, - 110, 109, - 109, 109, - - // i - 12, 15, - 125, 41, - 33, 41, - 144, 188, - - // j - 1, 6, - 75, 53, - 10, 53, - 210, 161, - - // k - 110, 0, - 152, 148, - 210, 60, - 110, 156, - - // l - 213, 5, - 63, 5, - 63, 5, - 45, 111, - - // m - 0, 0, - 232, 172, - 190, 168, - 190, 169, - - // n - 0, 0, - 190, 144, - 109, 109, - 109, 109, - - // o - 0, 0, - 168, 140, - 148, 111, - 168, 140, - - // p - 0, 0, - 200, 151, - 113, 110, - 255, 158, - - // q - 0, 0, - 184, 188, - 147, 139, - 186, 255, - - // r - 0, 0, - 122, 130, - 111, 0, - 109, 0, - - // s - 0, 0, - 132, 69, - 109, 93, - 110, 136, - - // t - 51, 5, - 205, 103, - 61, 6, - 47, 106, - - // u - 0, 0, - 110, 109, - 110, 122, - 155, 179, - - // v - 0, 0, - 132, 120, - 113, 114, - 84, 63, - - // w - 0, 0, - 124, 108, - 202, 189, - 160, 174, - - // x - 0, 0, - 144, 142, - 79, 57, - 159, 146, - - // y - 0, 0, - 138, 138, - 119, 117, - 255, 69, - - // z - 0, 0, - 97, 198, - 47, 38, - 208, 84, - - // { - 23, 112, - 41, 14, - 157, 7, - 121, 192, - - // | - 35, 11, - 35, 11, - 35, 11, - 160, 61, - - // } - 129, 9, - 40, 19, - 20, 139, - 236, 44, - - // ~ - 0, 0, - 15, 3, - 97, 93, - 0, 0, - -]; - -let x1Data: number[] | null = [ - - // - 0, - 0, - - // ! - 23, - 12, - - // " - 53, - 0, - - // # - 130, - 127, - - // $ - 58, - 149, - - // % - 67, - 77, - - // & - 72, - 198, - - // ' - 13, - 0, - - // ( - 25, - 51, - - // ) - 25, - 49, - - // * - 94, - 2, - - // + - 8, - 64, - - // , - 0, - 24, - - // - - 0, - 21, - - // . - 0, - 9, - - // / - 19, - 27, - - // 0 - 126, - 126, - - // 1 - 51, - 80, - - // 2 - 72, - 105, - - // 3 - 87, - 98, - - // 4 - 73, - 93, - - // 5 - 106, - 85, - - // 6 - 111, - 123, - - // 7 - 87, - 30, - - // 8 - 116, - 126, - - // 9 - 123, - 110, - - // : - 4, - 16, - - // ; - 9, - 28, - - // < - 21, - 53, - - // = - 8, - 62, - - // > - 23, - 52, - - // ? - 73, - 21, - - // @ - 132, - 183, - - // A - 78, - 142, - - // B - 168, - 175, - - // C - 70, - 70, - - // D - 128, - 128, - - // E - 123, - 110, - - // F - 125, - 43, - - // G - 100, - 139, - - // H - 125, - 119, - - // I - 78, - 78, - - // J - 54, - 77, - - // K - 139, - 139, - - // L - 33, - 87, - - // M - 201, - 117, - - // N - 162, - 149, - - // O - 130, - 130, - - // P - 138, - 60, - - // Q - 130, - 172, - - // R - 149, - 127, - - // S - 95, - 98, - - // T - 95, - 25, - - // U - 118, - 135, - - // V - 110, - 85, - - // W - 147, - 175, - - // X - 105, - 110, - - // Y - 121, - 30, - - // Z - 101, - 113, - - // [ - 34, - 68, - - // \ - 20, - 26, - - // ] - 34, - 68, - - // ^ - 56, - 0, - - // _ - 0, - 44, - - // ` - 3, - 0, - - // a - 27, - 175, - - // b - 80, - 133, - - // c - 31, - 66, - - // d - 85, - 147, - - // e - 32, - 150, - - // f - 90, - 25, - - // g - 45, - 230, - - // h - 77, - 101, - - // i - 36, - 83, - - // j - 22, - 84, - - // k - 71, - 118, - - // l - 44, - 44, - - // m - 52, - 172, - - // n - 38, - 101, - - // o - 35, - 130, - - // p - 40, - 197, - - // q - 43, - 197, - - // r - 29, - 26, - - // s - 23, - 103, - - // t - 67, - 44, - - // u - 25, - 129, - - // v - 29, - 85, - - // w - 27, - 177, - - // x - 33, - 97, - - // y - 32, - 145, - - // z - 33, - 77, - - // { - 38, - 96, - - // | - 20, - 55, - - // } - 36, - 95, - - // ~ - 2, - 22, - -]; diff --git a/src/vs/editor/common/viewLayout/lineDecorations.ts b/src/vs/editor/common/viewLayout/lineDecorations.ts index 5e79341a942..367abd68f82 100644 --- a/src/vs/editor/common/viewLayout/lineDecorations.ts +++ b/src/vs/editor/common/viewLayout/lineDecorations.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as strings from 'vs/base/common/strings'; -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; export class LineDecoration { diff --git a/src/vs/editor/common/viewLayout/viewLayout.ts b/src/vs/editor/common/viewLayout/viewLayout.ts index c06d7220a42..74fca28d029 100644 --- a/src/vs/editor/common/viewLayout/viewLayout.ts +++ b/src/vs/editor/common/viewLayout/viewLayout.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; -import { IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; +import { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; @@ -65,15 +65,23 @@ export class ViewLayout extends Disposable implements IViewLayout { } if (e.hasChanged(EditorOption.layoutInfo)) { const layoutInfo = options.get(EditorOption.layoutInfo); + const width = layoutInfo.contentWidth; + const height = layoutInfo.contentHeight; + const scrollDimensions = this.scrollable.getScrollDimensions(); + const scrollWidth = scrollDimensions.scrollWidth; + const scrollHeight = this._getTotalHeight(width, height, scrollWidth); + this.scrollable.setScrollDimensions({ - width: layoutInfo.contentWidth, - height: layoutInfo.contentHeight + width: width, + height: height, + scrollHeight: scrollHeight }); + } else { + this._updateHeight(); } if (e.hasChanged(EditorOption.smoothScrolling)) { this._configureSmoothScrollDuration(); } - this._updateHeight(); } public onFlushed(lineCount: number): void { this._linesLayout.onFlushed(lineCount); @@ -87,37 +95,41 @@ export class ViewLayout extends Disposable implements IViewLayout { // ---- end view event handlers - private _getHorizontalScrollbarHeight(scrollDimensions: IScrollDimensions): number { + private _getHorizontalScrollbarHeight(width: number, scrollWidth: number): number { const options = this._configuration.options; const scrollbar = options.get(EditorOption.scrollbar); if (scrollbar.horizontal === ScrollbarVisibility.Hidden) { // horizontal scrollbar not visible return 0; } - if (scrollDimensions.width >= scrollDimensions.scrollWidth) { + if (width >= scrollWidth) { // horizontal scrollbar not visible return 0; } return scrollbar.horizontalScrollbarSize; } - private _getTotalHeight(): number { + private _getTotalHeight(width: number, height: number, scrollWidth: number): number { const options = this._configuration.options; - const scrollDimensions = this.scrollable.getScrollDimensions(); let result = this._linesLayout.getLinesTotalHeight(); if (options.get(EditorOption.scrollBeyondLastLine)) { - result += scrollDimensions.height - options.get(EditorOption.lineHeight); + result += height - options.get(EditorOption.lineHeight); } else { - result += this._getHorizontalScrollbarHeight(scrollDimensions); + result += this._getHorizontalScrollbarHeight(width, scrollWidth); } - return Math.max(scrollDimensions.height, result); + return Math.max(height, result); } private _updateHeight(): void { + const scrollDimensions = this.scrollable.getScrollDimensions(); + const width = scrollDimensions.width; + const height = scrollDimensions.height; + const scrollWidth = scrollDimensions.scrollWidth; + const scrollHeight = this._getTotalHeight(width, height, scrollWidth); this.scrollable.setScrollDimensions({ - scrollHeight: this._getTotalHeight() + scrollHeight: scrollHeight }); } diff --git a/src/vs/editor/common/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts index bbb9b39cb8c..5298d234529 100644 --- a/src/vs/editor/common/viewLayout/viewLineRenderer.ts +++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts @@ -783,7 +783,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render if (!fontIsMonospace) { const partIsOnlyWhitespace = (partType === 'vs-whitespace'); if (partIsOnlyWhitespace || !containsForeignElements) { - sb.appendASCIIString(' style="width:'); + sb.appendASCIIString(' style="display:inline-block;width:'); sb.appendASCIIString(String(spaceWidth * partContentCnt)); sb.appendASCIIString('px"'); } diff --git a/src/vs/editor/common/viewModel/characterHardWrappingLineMapper.ts b/src/vs/editor/common/viewModel/characterHardWrappingLineMapper.ts index 74b236d4b78..bbf71e817b9 100644 --- a/src/vs/editor/common/viewModel/characterHardWrappingLineMapper.ts +++ b/src/vs/editor/common/viewModel/characterHardWrappingLineMapper.ts @@ -7,7 +7,7 @@ import { CharCode } from 'vs/base/common/charCode'; import * as strings from 'vs/base/common/strings'; import { WrappingIndent } from 'vs/editor/common/config/editorOptions'; import { CharacterClassifier } from 'vs/editor/common/core/characterClassifier'; -import { toUint32Array } from 'vs/editor/common/core/uint'; +import { toUint32Array } from 'vs/base/common/uint'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { ILineMapperFactory, ILineMapping, OutputPosition } from 'vs/editor/common/viewModel/splitLinesCollection'; diff --git a/src/vs/editor/common/viewModel/minimapTokensColorTracker.ts b/src/vs/editor/common/viewModel/minimapTokensColorTracker.ts new file mode 100644 index 00000000000..39eb06d774c --- /dev/null +++ b/src/vs/editor/common/viewModel/minimapTokensColorTracker.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 { Emitter, Event } from 'vs/base/common/event'; +import { RGBA8 } from 'vs/editor/common/core/rgba'; +import { ColorId, TokenizationRegistry } from 'vs/editor/common/modes'; + +export class MinimapTokensColorTracker { + private static _INSTANCE: MinimapTokensColorTracker | null = null; + public static getInstance(): MinimapTokensColorTracker { + if (!this._INSTANCE) { + this._INSTANCE = new MinimapTokensColorTracker(); + } + return this._INSTANCE; + } + + private _colors!: RGBA8[]; + private _backgroundIsLight!: boolean; + + private readonly _onDidChange = new Emitter(); + public readonly onDidChange: Event = this._onDidChange.event; + + private constructor() { + this._updateColorMap(); + TokenizationRegistry.onDidChange(e => { + if (e.changedColorMap) { + this._updateColorMap(); + } + }); + } + + private _updateColorMap(): void { + const colorMap = TokenizationRegistry.getColorMap(); + if (!colorMap) { + this._colors = [RGBA8.Empty]; + this._backgroundIsLight = true; + return; + } + this._colors = [RGBA8.Empty]; + for (let colorId = 1; colorId < colorMap.length; colorId++) { + const source = colorMap[colorId].rgba; + // Use a VM friendly data-type + this._colors[colorId] = new RGBA8(source.r, source.g, source.b, Math.round(source.a * 255)); + } + let backgroundLuminosity = colorMap[ColorId.DefaultBackground].getRelativeLuminance(); + this._backgroundIsLight = backgroundLuminosity >= 0.5; + this._onDidChange.fire(undefined); + } + + public getColor(colorId: ColorId): RGBA8 { + if (colorId < 1 || colorId >= this._colors.length) { + // background color (basically invisible) + colorId = ColorId.DefaultBackground; + } + return this._colors[colorId]; + } + + public backgroundIsLight(): boolean { + return this._backgroundIsLight; + } +} diff --git a/src/vs/editor/common/viewModel/prefixSumComputer.ts b/src/vs/editor/common/viewModel/prefixSumComputer.ts index 81e66ac5059..d4e8c1f0df2 100644 --- a/src/vs/editor/common/viewModel/prefixSumComputer.ts +++ b/src/vs/editor/common/viewModel/prefixSumComputer.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { toUint32 } from 'vs/editor/common/core/uint'; +import { toUint32 } from 'vs/base/common/uint'; export class PrefixSumIndexOfResult { _prefixSumIndexOfResultBrand: void; diff --git a/src/vs/editor/common/viewModel/splitLinesCollection.ts b/src/vs/editor/common/viewModel/splitLinesCollection.ts index 0704e236922..3cd2afbafaf 100644 --- a/src/vs/editor/common/viewModel/splitLinesCollection.ts +++ b/src/vs/editor/common/viewModel/splitLinesCollection.ts @@ -129,9 +129,7 @@ export class CoordinatesConverter implements ICoordinatesConverter { } public convertModelRangeToViewRange(modelRange: Range): Range { - let start = this._lines.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn); - let end = this._lines.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn); - return new Range(start.lineNumber, start.column, end.lineNumber, end.column); + return this._lines.convertModelRangeToViewRange(modelRange); } public modelPositionIsVisible(modelPosition: Position): boolean { @@ -737,9 +735,9 @@ export class SplitLinesCollection implements IViewModelLinesCollection { public convertModelPositionToViewPosition(_modelLineNumber: number, _modelColumn: number): Position { this._ensureValidState(); - let validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn)); - let inputLineNumber = validPosition.lineNumber; - let inputColumn = validPosition.column; + const validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn)); + const inputLineNumber = validPosition.lineNumber; + const inputColumn = validPosition.column; let lineIndex = inputLineNumber - 1, lineIndexChanged = false; while (lineIndex > 0 && !this.lines[lineIndex].isVisible()) { @@ -751,7 +749,7 @@ export class SplitLinesCollection implements IViewModelLinesCollection { // console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + 1 + ',' + 1); return new Position(1, 1); } - let deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1)); + const deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1)); let r: Position; if (lineIndexChanged) { @@ -764,6 +762,19 @@ export class SplitLinesCollection implements IViewModelLinesCollection { return r; } + public convertModelRangeToViewRange(modelRange: Range): Range { + let start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn); + let end = this.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn); + if (modelRange.startLineNumber === modelRange.endLineNumber && start.lineNumber !== end.lineNumber) { + // This is a single line range that ends up taking more lines due to wrapping + if (end.column === this.getViewLineMinColumn(end.lineNumber)) { + // the end column lands on the first column of the next line + return new Range(start.lineNumber, start.column, end.lineNumber - 1, this.getViewLineMaxColumn(end.lineNumber - 1)); + } + } + return new Range(start.lineNumber, start.column, end.lineNumber, end.column); + } + private _getViewLineNumberForModelPosition(inputLineNumber: number, inputColumn: number): number { let lineIndex = inputLineNumber - 1; if (this.lines[lineIndex].isVisible()) { diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 01e9f36723c..e08af64ebf9 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -15,7 +15,7 @@ import { ModelDecorationOverviewRulerOptions, ModelDecorationMinimapOptions } fr 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'; -import { MinimapTokensColorTracker } from 'vs/editor/common/view/minimapCharRenderer'; +import { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { ViewLayout } from 'vs/editor/common/viewLayout/viewLayout'; import { CharacterHardWrappingLineMapperFactory } from 'vs/editor/common/viewModel/characterHardWrappingLineMapper'; @@ -24,6 +24,7 @@ import { ICoordinatesConverter, IOverviewRulerDecorations, IViewModel, MinimapLi import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations'; import { ITheme } from 'vs/platform/theme/common/themeService'; import { RunOnceScheduler } from 'vs/base/common/async'; +import * as platform from 'vs/base/common/platform'; const USE_IDENTITY_LINES_COLLECTION = true; @@ -128,6 +129,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel super.dispose(); this.decorations.dispose(); this.lines.dispose(); + this.invalidateMinimapColorCache(); this.viewportStartLineTrackedRange = this.model._setTrackedRange(this.viewportStartLineTrackedRange, null, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges); } @@ -626,9 +628,19 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel ranges = ranges.slice(0); ranges.sort(Range.compareRangesUsingStarts); - const nonEmptyRanges = ranges.filter((r) => !r.isEmpty()); - if (nonEmptyRanges.length === 0) { + let hasEmptyRange = false; + let hasNonEmptyRange = false; + for (const range of ranges) { + if (range.isEmpty()) { + hasEmptyRange = true; + } else { + hasNonEmptyRange = true; + } + } + + if (!hasNonEmptyRange) { + // all ranges are empty if (!emptySelectionClipboard) { return ''; } @@ -648,9 +660,29 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel return result; } + if (hasEmptyRange && emptySelectionClipboard) { + // mixed empty selections and non-empty selections + let result: string[] = []; + let prevModelLineNumber = 0; + for (const range of ranges) { + const modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber; + if (range.isEmpty()) { + if (modelLineNumber !== prevModelLineNumber) { + result.push(this.model.getLineContent(modelLineNumber)); + } + } else { + result.push(this.getValueInRange(range, forceCRLF ? EndOfLinePreference.CRLF : EndOfLinePreference.TextDefined)); + } + prevModelLineNumber = modelLineNumber; + } + return result.length === 1 ? result[0] : result; + } + let result: string[] = []; - for (const nonEmptyRange of nonEmptyRanges) { - result.push(this.getValueInRange(nonEmptyRange, forceCRLF ? EndOfLinePreference.CRLF : EndOfLinePreference.TextDefined)); + for (const range of ranges) { + if (!range.isEmpty()) { + result.push(this.getValueInRange(range, forceCRLF ? EndOfLinePreference.CRLF : EndOfLinePreference.TextDefined)); + } } return result.length === 1 ? result[0] : result; } @@ -713,7 +745,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel if (lineContent === '') { result += '
'; } else { - result += tokenizeLineToHTML(lineContent, lineTokens.inflate(), colorMap, startOffset, endOffset, tabSize); + result += tokenizeLineToHTML(lineContent, lineTokens.inflate(), colorMap, startOffset, endOffset, tabSize, platform.isWindows); } } diff --git a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts index 44d7bb7613a..ac8db2f7325 100644 --- a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts @@ -56,16 +56,36 @@ class SelectToBracketAction extends EditorAction { id: 'editor.action.selectToBracket', label: nls.localize('smartSelect.selectToBracket', "Select to Bracket"), alias: 'Select to Bracket', - precondition: undefined + precondition: undefined, + description: { + description: `Select to Bracket`, + args: [{ + name: 'args', + schema: { + type: 'object', + properties: { + 'selectBrackets': { + type: 'boolean', + default: true + } + }, + } + }] + } }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - let controller = BracketMatchingController.get(editor); + public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { + const controller = BracketMatchingController.get(editor); if (!controller) { return; } - controller.selectToBracket(); + + let selectBrackets = true; + if (args && args.selectBrackets === false) { + selectBrackets = false; + } + controller.selectToBracket(selectBrackets); } } @@ -74,15 +94,17 @@ type Brackets = [Range, Range]; class BracketsData { public readonly position: Position; public readonly brackets: Brackets | null; + public readonly options: ModelDecorationOptions; - constructor(position: Position, brackets: Brackets | null) { + constructor(position: Position, brackets: Brackets | null, options: ModelDecorationOptions) { this.position = position; this.brackets = brackets; + this.options = options; } } export class BracketMatchingController extends Disposable implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.bracketMatchingController'; + public static readonly ID = 'editor.contrib.bracketMatchingController'; public static get(editor: ICodeEditor): BracketMatchingController { return editor.getContribution(BracketMatchingController.ID); @@ -140,10 +162,6 @@ export class BracketMatchingController extends Disposable implements editorCommo })); } - public getId(): string { - return BracketMatchingController.ID; - } - public jumpToBracket(): void { if (!this._editor.hasModel()) { return; @@ -163,10 +181,16 @@ export class BracketMatchingController extends Disposable implements editorCommo newCursorPosition = brackets[0].getStartPosition(); } } else { - // find the next bracket if the position isn't on a matching bracket - const nextBracket = model.findNextBracket(position); - if (nextBracket && nextBracket.range) { - newCursorPosition = nextBracket.range.getStartPosition(); + // find the enclosing brackets if the position isn't on a matching bracket + const enclosingBrackets = model.findEnclosingBrackets(position); + if (enclosingBrackets) { + newCursorPosition = enclosingBrackets[0].getStartPosition(); + } else { + // no enclosing brackets, try the very first next bracket + const nextBracket = model.findNextBracket(position); + if (nextBracket && nextBracket.range) { + newCursorPosition = nextBracket.range.getStartPosition(); + } } } @@ -180,7 +204,7 @@ export class BracketMatchingController extends Disposable implements editorCommo this._editor.revealRange(newSelections[0]); } - public selectToBracket(): void { + public selectToBracket(selectBrackets: boolean): void { if (!this._editor.hasModel()) { return; } @@ -192,44 +216,38 @@ export class BracketMatchingController extends Disposable implements editorCommo const position = selection.getStartPosition(); let brackets = model.matchBracket(position); - let openBracket: Position | null = null; - let closeBracket: Position | null = null; - if (!brackets) { - const nextBracket = model.findNextBracket(position); - if (nextBracket && nextBracket.range) { - brackets = model.matchBracket(nextBracket.range.getStartPosition()); + brackets = model.findEnclosingBrackets(position); + if (!brackets) { + const nextBracket = model.findNextBracket(position); + if (nextBracket && nextBracket.range) { + brackets = model.matchBracket(nextBracket.range.getStartPosition()); + } } } + let selectFrom: Position | null = null; + let selectTo: Position | null = null; + if (brackets) { - if (brackets[0].startLineNumber === brackets[1].startLineNumber) { - openBracket = brackets[1].startColumn < brackets[0].startColumn ? - brackets[1].getStartPosition() : brackets[0].getStartPosition(); - closeBracket = brackets[1].startColumn < brackets[0].startColumn ? - brackets[0].getEndPosition() : brackets[1].getEndPosition(); - } else { - openBracket = brackets[1].startLineNumber < brackets[0].startLineNumber ? - brackets[1].getStartPosition() : brackets[0].getStartPosition(); - closeBracket = brackets[1].startLineNumber < brackets[0].startLineNumber ? - brackets[0].getEndPosition() : brackets[1].getEndPosition(); - } + brackets.sort(Range.compareRangesUsingStarts); + const [open, close] = brackets; + selectFrom = selectBrackets ? open.getStartPosition() : open.getEndPosition(); + selectTo = selectBrackets ? close.getEndPosition() : close.getStartPosition(); } - if (openBracket && closeBracket) { - newSelections.push(new Selection(openBracket.lineNumber, openBracket.column, closeBracket.lineNumber, closeBracket.column)); + if (selectFrom && selectTo) { + newSelections.push(new Selection(selectFrom.lineNumber, selectFrom.column, selectTo.lineNumber, selectTo.column)); } }); - if (newSelections.length > 0) { this._editor.setSelections(newSelections); this._editor.revealRange(newSelections[0]); } } - - private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({ + private static readonly _DECORATION_OPTIONS_WITH_OVERVIEW_RULER = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'bracket-match', overviewRuler: { @@ -238,6 +256,11 @@ export class BracketMatchingController extends Disposable implements editorCommo } }); + private static readonly _DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'bracket-match' + }); + private _updateBrackets(): void { if (!this._matchBrackets) { return; @@ -245,11 +268,11 @@ export class BracketMatchingController extends Disposable implements editorCommo this._recomputeBrackets(); let newDecorations: IModelDeltaDecoration[] = [], newDecorationsLen = 0; - for (let i = 0, len = this._lastBracketsData.length; i < len; i++) { - let brackets = this._lastBracketsData[i].brackets; + for (const bracketData of this._lastBracketsData) { + let brackets = bracketData.brackets; if (brackets) { - newDecorations[newDecorationsLen++] = { range: brackets[0], options: BracketMatchingController._DECORATION_OPTIONS }; - newDecorations[newDecorationsLen++] = { range: brackets[1], options: BracketMatchingController._DECORATION_OPTIONS }; + newDecorations[newDecorationsLen++] = { range: brackets[0], options: bracketData.options }; + newDecorations[newDecorationsLen++] = { range: brackets[1], options: bracketData.options }; } } @@ -264,6 +287,14 @@ export class BracketMatchingController extends Disposable implements editorCommo return; } + const selections = this._editor.getSelections(); + if (selections.length > 100) { + // no bracket matching for high numbers of selections + this._lastBracketsData = []; + this._lastVersionId = 0; + return; + } + const model = this._editor.getModel(); const versionId = model.getVersionId(); let previousData: BracketsData[] = []; @@ -272,8 +303,6 @@ export class BracketMatchingController extends Disposable implements editorCommo previousData = this._lastBracketsData; } - const selections = this._editor.getSelections(); - let positions: Position[] = [], positionsLen = 0; for (let i = 0, len = selections.length; i < len; i++) { let selection = selections[i]; @@ -302,7 +331,12 @@ export class BracketMatchingController extends Disposable implements editorCommo newData[newDataLen++] = previousData[previousIndex]; } else { let brackets = model.matchBracket(position); - newData[newDataLen++] = new BracketsData(position, brackets); + let options = BracketMatchingController._DECORATION_OPTIONS_WITH_OVERVIEW_RULER; + if (!brackets) { + brackets = model.findEnclosingBrackets(position); + options = BracketMatchingController._DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER; + } + newData[newDataLen++] = new BracketsData(position, brackets, options); } } @@ -311,7 +345,7 @@ export class BracketMatchingController extends Disposable implements editorCommo } } -registerEditorContribution(BracketMatchingController); +registerEditorContribution(BracketMatchingController.ID, BracketMatchingController); registerEditorAction(SelectToBracketAction); registerEditorAction(JumpToBracketAction); registerThemingParticipant((theme, collector) => { diff --git a/src/vs/editor/contrib/bracketMatching/test/bracketMatching.test.ts b/src/vs/editor/contrib/bracketMatching/test/bracketMatching.test.ts index f9deb3ce478..87886115932 100644 --- a/src/vs/editor/contrib/bracketMatching/test/bracketMatching.test.ts +++ b/src/vs/editor/contrib/bracketMatching/test/bracketMatching.test.ts @@ -34,7 +34,7 @@ suite('bracket matching', () => { let model = TextModel.createFromString('var x = (3 + (5-7)) + ((5+3)+5);', undefined, mode.getLanguageIdentifier()); withTestCodeEditor(null, { model: model }, (editor, cursor) => { - let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController); + let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController); // start on closing bracket editor.setPosition(new Position(1, 20)); @@ -66,7 +66,7 @@ suite('bracket matching', () => { let model = TextModel.createFromString('var x = (3 + (5-7)); y();', undefined, mode.getLanguageIdentifier()); withTestCodeEditor(null, { model: model }, (editor, cursor) => { - let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController); + let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController); // start position between brackets editor.setPosition(new Position(1, 16)); @@ -103,36 +103,36 @@ suite('bracket matching', () => { let model = TextModel.createFromString('var x = (3 + (5-7)); y();', undefined, mode.getLanguageIdentifier()); withTestCodeEditor(null, { model: model }, (editor, cursor) => { - let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController); + let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController); // start position in open brackets editor.setPosition(new Position(1, 9)); - bracketMatchingController.selectToBracket(); + bracketMatchingController.selectToBracket(true); assert.deepEqual(editor.getPosition(), new Position(1, 20)); assert.deepEqual(editor.getSelection(), new Selection(1, 9, 1, 20)); // start position in close brackets editor.setPosition(new Position(1, 20)); - bracketMatchingController.selectToBracket(); + bracketMatchingController.selectToBracket(true); assert.deepEqual(editor.getPosition(), new Position(1, 20)); assert.deepEqual(editor.getSelection(), new Selection(1, 9, 1, 20)); // start position between brackets editor.setPosition(new Position(1, 16)); - bracketMatchingController.selectToBracket(); + bracketMatchingController.selectToBracket(true); assert.deepEqual(editor.getPosition(), new Position(1, 19)); assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 19)); // start position outside brackets editor.setPosition(new Position(1, 21)); - bracketMatchingController.selectToBracket(); + bracketMatchingController.selectToBracket(true); assert.deepEqual(editor.getPosition(), new Position(1, 25)); assert.deepEqual(editor.getSelection(), new Selection(1, 23, 1, 25)); // do not break if no brackets are available editor.setPosition(new Position(1, 26)); - bracketMatchingController.selectToBracket(); + bracketMatchingController.selectToBracket(true); assert.deepEqual(editor.getPosition(), new Position(1, 26)); assert.deepEqual(editor.getSelection(), new Selection(1, 26, 1, 26)); @@ -143,12 +143,62 @@ suite('bracket matching', () => { mode.dispose(); }); + test('issue #1772: jump to enclosing brackets', () => { + const text = [ + 'const x = {', + ' something: [0, 1, 2],', + ' another: true,', + ' somethingmore: [0, 2, 4]', + '};', + ].join('\n'); + const mode = new BracketMode(); + const model = TextModel.createFromString(text, undefined, mode.getLanguageIdentifier()); + + withTestCodeEditor(null, { model: model }, (editor, cursor) => { + const bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController); + + editor.setPosition(new Position(3, 5)); + bracketMatchingController.jumpToBracket(); + assert.deepEqual(editor.getSelection(), new Selection(5, 1, 5, 1)); + + bracketMatchingController.dispose(); + }); + + model.dispose(); + mode.dispose(); + }); + + test('issue #43371: argument to not select brackets', () => { + const text = [ + 'const x = {', + ' something: [0, 1, 2],', + ' another: true,', + ' somethingmore: [0, 2, 4]', + '};', + ].join('\n'); + const mode = new BracketMode(); + const model = TextModel.createFromString(text, undefined, mode.getLanguageIdentifier()); + + withTestCodeEditor(null, { model: model }, (editor, cursor) => { + const bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController); + + editor.setPosition(new Position(3, 5)); + bracketMatchingController.selectToBracket(false); + assert.deepEqual(editor.getSelection(), new Selection(1, 12, 5, 1)); + + bracketMatchingController.dispose(); + }); + + model.dispose(); + mode.dispose(); + }); + test('issue #45369: Select to Bracket with multicursor', () => { let mode = new BracketMode(); let model = TextModel.createFromString('{ } { } { }', undefined, mode.getLanguageIdentifier()); withTestCodeEditor(null, { model: model }, (editor, cursor) => { - let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController); + let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController); // cursors inside brackets become selections of the entire bracket contents editor.setSelections([ @@ -156,7 +206,7 @@ suite('bracket matching', () => { new Selection(1, 10, 1, 10), new Selection(1, 17, 1, 17) ]); - bracketMatchingController.selectToBracket(); + bracketMatchingController.selectToBracket(true); assert.deepEqual(editor.getSelections(), [ new Selection(1, 1, 1, 5), new Selection(1, 8, 1, 13), @@ -169,7 +219,7 @@ suite('bracket matching', () => { new Selection(1, 6, 1, 6), new Selection(1, 14, 1, 14) ]); - bracketMatchingController.selectToBracket(); + bracketMatchingController.selectToBracket(true); assert.deepEqual(editor.getSelections(), [ new Selection(1, 1, 1, 5), new Selection(1, 8, 1, 13), @@ -182,7 +232,7 @@ suite('bracket matching', () => { new Selection(1, 13, 1, 13), new Selection(1, 19, 1, 19) ]); - bracketMatchingController.selectToBracket(); + bracketMatchingController.selectToBracket(true); assert.deepEqual(editor.getSelections(), [ new Selection(1, 1, 1, 5), new Selection(1, 8, 1, 13), diff --git a/src/vs/editor/contrib/caretOperations/transpose.ts b/src/vs/editor/contrib/caretOperations/transpose.ts index 719d4fa186b..121f05bd113 100644 --- a/src/vs/editor/contrib/caretOperations/transpose.ts +++ b/src/vs/editor/contrib/caretOperations/transpose.ts @@ -5,57 +5,17 @@ import * as nls from 'vs/nls'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { isHighSurrogate, isLowSurrogate } from 'vs/base/common/strings'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; -import { IPosition, Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ICommand } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { ITextModel } from 'vs/editor/common/model'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations'; class TransposeLettersAction extends EditorAction { - private positionLeftOf(start: IPosition, model: ITextModel): Position { - let column = start.column; - let lineNumber = start.lineNumber; - - if (column > model.getLineMinColumn(lineNumber)) { - if (isLowSurrogate(model.getLineContent(lineNumber).charCodeAt(column - 2))) { - // character before column is a low surrogate - column = column - 2; - } else { - column = column - 1; - } - } else if (lineNumber > 1) { - lineNumber = lineNumber - 1; - column = model.getLineMaxColumn(lineNumber); - } - - return new Position(lineNumber, column); - } - - private positionRightOf(start: IPosition, model: ITextModel): Position { - let column = start.column; - let lineNumber = start.lineNumber; - - if (column < model.getLineMaxColumn(lineNumber)) { - if (isHighSurrogate(model.getLineContent(lineNumber).charCodeAt(column - 1))) { - // character after column is a high surrogate - column = column + 2; - } else { - column = column + 1; - } - } else if (lineNumber < model.getLineCount()) { - lineNumber = lineNumber + 1; - column = 0; - } - - return new Position(lineNumber, column); - } - constructor() { super({ id: 'editor.action.transposeLetters', @@ -101,10 +61,10 @@ class TransposeLettersAction extends EditorAction { // otherwise, transpose left and right chars let endPosition = (column === lastColumn) ? selection.getPosition() : - this.positionRightOf(selection.getPosition(), model); + MoveOperations.rightPosition(model, selection.getPosition().lineNumber, selection.getPosition().column); - let middlePosition = this.positionLeftOf(endPosition, model); - let beginPosition = this.positionLeftOf(middlePosition, model); + let middlePosition = MoveOperations.leftPosition(model, endPosition.lineNumber, endPosition.column); + let beginPosition = MoveOperations.leftPosition(model, middlePosition.lineNumber, middlePosition.column); let leftChar = model.getValueInRange(Range.fromPositions(beginPosition, middlePosition)); let rightChar = model.getValueInRange(Range.fromPositions(middlePosition, endPosition)); diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index 72af0135934..54c773a6c4b 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -5,6 +5,7 @@ import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { Lazy } from 'vs/base/common/lazy'; import { Disposable } from 'vs/base/common/lifecycle'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -39,7 +40,7 @@ function contextKeyForSupportedActions(kind: CodeActionKind) { export class QuickFixController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.quickFixController'; + public static readonly ID = 'editor.contrib.quickFixController'; public static get(editor: ICodeEditor): QuickFixController { return editor.getContribution(QuickFixController.ID); @@ -47,7 +48,7 @@ export class QuickFixController extends Disposable implements IEditorContributio private readonly _editor: ICodeEditor; private readonly _model: CodeActionModel; - private readonly _ui: CodeActionUi; + private readonly _ui: Lazy; constructor( editor: ICodeEditor, @@ -64,31 +65,29 @@ export class QuickFixController extends Disposable implements IEditorContributio this._editor = editor; this._model = this._register(new CodeActionModel(this._editor, markerService, contextKeyService, progressService)); - this._register(this._model.onDidChangeState((newState) => this.update(newState))); + 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: {} }); + this._ui = new Lazy(() => + this._register(new CodeActionUi(editor, QuickFixAction.Id, AutoFixAction.Id, { + applyCodeAction: async (action, retrigger) => { + try { + await this._applyCodeAction(action); + } finally { + if (retrigger) { + this._trigger({ type: 'auto', filter: {} }); + } } } - } - }, contextMenuService, keybindingService)); + }, contextMenuService, keybindingService)) + ); } private update(newState: CodeActionsState.State): void { - this._ui.update(newState); + this._ui.getValue().update(newState); } public showCodeActions(actions: CodeActionSet, at: IAnchor | IPosition) { - return this._ui.showCodeActionList(actions, at); - } - - public getId(): string { - return QuickFixController.ID; + return this._ui.getValue().showCodeActionList(actions, at); } public manualTriggerAtCurrentPosition( diff --git a/src/vs/editor/contrib/codeAction/codeActionContributions.ts b/src/vs/editor/contrib/codeAction/codeActionContributions.ts index 2b9ed4cea8c..bc25e46078d 100644 --- a/src/vs/editor/contrib/codeAction/codeActionContributions.ts +++ b/src/vs/editor/contrib/codeAction/codeActionContributions.ts @@ -7,7 +7,7 @@ import { registerEditorAction, registerEditorCommand, registerEditorContribution import { CodeActionCommand, OrganizeImportsAction, QuickFixAction, QuickFixController, RefactorAction, SourceAction, AutoFixAction, FixAllAction } from 'vs/editor/contrib/codeAction/codeActionCommands'; -registerEditorContribution(QuickFixController); +registerEditorContribution(QuickFixController.ID, QuickFixController); registerEditorAction(QuickFixAction); registerEditorAction(RefactorAction); registerEditorAction(SourceAction); diff --git a/src/vs/editor/contrib/codeAction/codeActionModel.ts b/src/vs/editor/contrib/codeAction/codeActionModel.ts index 2af98e865aa..91bd478b18f 100644 --- a/src/vs/editor/contrib/codeAction/codeActionModel.ts +++ b/src/vs/editor/contrib/codeAction/codeActionModel.ts @@ -18,6 +18,7 @@ import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { getCodeActions, CodeActionSet } from './codeAction'; import { CodeActionTrigger } from './codeActionTrigger'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { isEqual } from 'vs/base/common/resources'; export const SUPPORTED_CODE_ACTIONS = new RawContextKey('supportedCodeAction', ''); @@ -47,13 +48,13 @@ class CodeActionOracle extends Disposable { return this._createEventAndSignalChange(trigger, selection); } - private _onMarkerChanges(resources: URI[]): void { + private _onMarkerChanges(resources: readonly URI[]): void { const model = this._editor.getModel(); if (!model) { return; } - if (resources.some(resource => resource.toString() === model.uri.toString())) { + if (resources.some(resource => isEqual(resource, model.uri))) { this._autoTriggerTimer.cancelAndSet(() => { this.trigger({ type: 'auto' }); }, this._delay); diff --git a/src/vs/editor/contrib/codeAction/codeActionUi.ts b/src/vs/editor/contrib/codeAction/codeActionUi.ts index a496f3e708f..67edd66106c 100644 --- a/src/vs/editor/contrib/codeAction/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/codeActionUi.ts @@ -17,16 +17,18 @@ 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'; +import { Lazy } from 'vs/base/common/lazy'; export class CodeActionUi extends Disposable { - private readonly _codeActionWidget: CodeActionWidget; - private readonly _lightBulbWidget: LightBulbWidget; + private readonly _codeActionWidget: Lazy; + private readonly _lightBulbWidget: Lazy; private readonly _activeCodeActions = this._register(new MutableDisposable()); constructor( private readonly _editor: ICodeEditor, quickFixActionId: string, + preferredFixActionId: string, private readonly delegate: { applyCodeAction: (action: CodeAction, regtriggerAfterApply: boolean) => void }, @@ -35,19 +37,26 @@ export class CodeActionUi extends Disposable { ) { 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._codeActionWidget = new Lazy(() => { + return this._register(new CodeActionWidget(this._editor, contextMenuService, { + onSelectCodeAction: async (action) => { + this.delegate.applyCodeAction(action, /* retrigger */ true); + } + })); + }); - this._register(this._lightBulbWidget.onClick(this._handleLightBulbSelect, this)); + this._lightBulbWidget = new Lazy(() => { + const widget = this._register(new LightBulbWidget(this._editor, quickFixActionId, preferredFixActionId, keybindingService)); + this._register(widget.onClick(this._handleLightBulbSelect, this)); + return widget; + }); } public async update(newState: CodeActionsState.State): Promise { if (newState.type !== CodeActionsState.Type.Triggered) { - this._lightBulbWidget.hide(); + if (this._lightBulbWidget.hasValue()) { + this._lightBulbWidget.getValue().hide(); + } return; } @@ -59,7 +68,7 @@ export class CodeActionUi extends Disposable { return; } - this._lightBulbWidget.update(actions, newState.position); + this._lightBulbWidget.getValue().update(actions, newState.position); if (!actions.actions.length && newState.trigger.context) { MessageController.get(this._editor).showMessage(newState.trigger.context.notAvailableMessage, newState.trigger.context.position); @@ -83,10 +92,10 @@ export class CodeActionUi extends Disposable { } } this._activeCodeActions.value = actions; - this._codeActionWidget.show(actions, newState.position); + this._codeActionWidget.getValue().show(actions, newState.position); } else { // auto magically triggered - if (this._codeActionWidget.isVisible) { + if (this._codeActionWidget.getValue().isVisible) { // TODO: Figure out if we should update the showing menu? actions.dispose(); } else { @@ -96,10 +105,10 @@ export class CodeActionUi extends Disposable { } public async showCodeActionList(actions: CodeActionSet, at?: IAnchor | IPosition): Promise { - this._codeActionWidget.show(actions, at); + this._codeActionWidget.getValue().show(actions, at); } private _handleLightBulbSelect(e: { x: number, y: number, actions: CodeActionSet }): void { - this._codeActionWidget.show(e.actions, e); + this._codeActionWidget.getValue().show(e.actions, e); } } diff --git a/src/vs/editor/contrib/codeAction/codeActionWidget.ts b/src/vs/editor/contrib/codeAction/codeActionWidget.ts index 4f31015c81c..cb5b1eb4b2b 100644 --- a/src/vs/editor/contrib/codeAction/codeActionWidget.ts +++ b/src/vs/editor/contrib/codeAction/codeActionWidget.ts @@ -21,7 +21,7 @@ interface CodeActionWidgetDelegate { export class CodeActionWidget extends Disposable { - private _visible: boolean; + private _visible: boolean = false; private readonly _showingActions = this._register(new MutableDisposable()); constructor( @@ -30,7 +30,6 @@ export class CodeActionWidget extends Disposable { private readonly _delegate: CodeActionWidgetDelegate, ) { super(); - this._visible = false; } public async show(codeActions: CodeActionSet, at?: IAnchor | IPosition): Promise { diff --git a/src/vs/editor/contrib/codeAction/lightBulbWidget.css b/src/vs/editor/contrib/codeAction/lightBulbWidget.css index afacdc3d2ec..aadcb4fd6e6 100644 --- a/src/vs/editor/contrib/codeAction/lightBulbWidget.css +++ b/src/vs/editor/contrib/codeAction/lightBulbWidget.css @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +.monaco-editor .lightbulb-glyph, .monaco-editor .codicon-lightbulb { display: flex; align-items: center; @@ -12,6 +13,7 @@ padding-left: 2px; } +.monaco-editor .lightbulb-glyph:hover, .monaco-editor .codicon-lightbulb:hover { cursor: pointer; /* transform: scale(1.3, 1.3); */ diff --git a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts index 8c5f26d3668..505f13244f9 100644 --- a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts +++ b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts @@ -47,7 +47,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { private readonly _domNode: HTMLDivElement; - private readonly _onClick = this._register(new Emitter<{ x: number; y: number; actions: CodeActionSet }>()); + private readonly _onClick = this._register(new Emitter<{ x: number; y: number; actions: CodeActionSet; }>()); public readonly onClick = this._onClick.event; private _state: LightBulbState.State = LightBulbState.Hidden; @@ -55,6 +55,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { constructor( private readonly _editor: ICodeEditor, private readonly _quickFixActionId: string, + private readonly _preferredFixActionId: string, @IKeybindingService private readonly _keybindingService: IKeybindingService ) { super(); @@ -66,12 +67,12 @@ export class LightBulbWidget extends Disposable implements IContentWidget { this._register(this._editor.onDidChangeModelContent(_ => { // cancel when the line in question has been removed const editorModel = this._editor.getModel(); - if (this._state.type !== LightBulbState.Type.Showing || !editorModel || this._state.editorPosition.lineNumber >= editorModel.getLineCount()) { + if (this.state.type !== LightBulbState.Type.Showing || !editorModel || this.state.editorPosition.lineNumber >= editorModel.getLineCount()) { this.hide(); } })); this._register(dom.addStandardDisposableListener(this._domNode, 'mousedown', e => { - if (this._state.type !== LightBulbState.Type.Showing) { + if (this.state.type !== LightBulbState.Type.Showing) { return; } @@ -84,14 +85,14 @@ export class LightBulbWidget extends Disposable implements IContentWidget { const lineHeight = this._editor.getOption(EditorOption.lineHeight); let pad = Math.floor(lineHeight / 3); - if (this._state.widgetPosition.position !== null && this._state.widgetPosition.position.lineNumber < this._state.editorPosition.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, - actions: this._state.actions + actions: this.state.actions }); })); this._register(dom.addDisposableListener(this._domNode, 'mouseenter', (e: MouseEvent) => { @@ -173,7 +174,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget { } } - this._state = new LightBulbState.Showing(actions, atPosition, { + this.state = new LightBulbState.Showing(actions, atPosition, { position: { lineNumber: effectiveLineNumber, column: 1 }, preference: LightBulbWidget._posPref }); @@ -181,24 +182,37 @@ export class LightBulbWidget extends Disposable implements IContentWidget { this._editor.layoutContentWidget(this); } - private set title(value: string) { - this._domNode.title = value; - } - public hide(): void { - this._state = LightBulbState.Hidden; + this.state = LightBulbState.Hidden; this._editor.layoutContentWidget(this); } + private get state(): LightBulbState.State { return this._state; } + + private set state(value) { + this._state = value; + this._updateLightBulbTitle(); + } + 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"); + if (this.state.type === LightBulbState.Type.Showing && this.state.actions.hasAutoFix) { + const preferredKb = this._keybindingService.lookupKeybinding(this._preferredFixActionId); + if (preferredKb) { + this.title = nls.localize('prefferedQuickFixWithKb', "Show Fixes. Preferred Fix Available ({0})", preferredKb.getLabel()); + return; + } } - this.title = title; + + const kb = this._keybindingService.lookupKeybinding(this._quickFixActionId); + if (kb) { + this.title = nls.localize('quickFixWithKb', "Show Fixes ({0})", kb.getLabel()); + } else { + this.title = nls.localize('quickFix', "Show Fixes"); + } + } + + private set title(value: string) { + this._domNode.title = value; } } diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index 6e89d47039c..a4acfe1ed17 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -21,7 +21,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class CodeLensContribution implements editorCommon.IEditorContribution { - private static readonly ID: string = 'css.editor.codeLens'; + public static readonly ID: string = 'css.editor.codeLens'; private _isEnabled: boolean; @@ -78,10 +78,6 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { dispose(this._currentCodeLensModel); } - getId(): string { - return CodeLensContribution.ID; - } - private _onModelChange(): void { this._localDispose(); @@ -366,4 +362,4 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { } } -registerEditorContribution(CodeLensContribution); +registerEditorContribution(CodeLensContribution.ID, CodeLensContribution); diff --git a/src/vs/editor/contrib/codelens/codelensWidget.css b/src/vs/editor/contrib/codelens/codelensWidget.css index 90319b63c7a..e266cf8b6a8 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.css +++ b/src/vs/editor/contrib/codelens/codelensWidget.css @@ -11,10 +11,9 @@ .monaco-editor .codelens-decoration > span, .monaco-editor .codelens-decoration > a { - -moz-user-select: none; + user-select: none; -webkit-user-select: none; -ms-user-select: none; - user-select: none; white-space: nowrap; vertical-align: sub; } diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index 42cf0deb06e..c048a6f1541 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -6,7 +6,7 @@ import 'vs/css!./codelensWidget'; import * as dom from 'vs/base/browser/dom'; import { coalesce, isFalsyOrEmpty } from 'vs/base/common/arrays'; -import { escape } from 'vs/base/common/strings'; +import { renderCodicons } from 'vs/base/browser/ui/codiconLabel/codiconLabel'; 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'; @@ -104,7 +104,7 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { for (let i = 0; i < symbols.length; i++) { const command = symbols[i].command; if (command) { - const title = escape(command.title); + const title = renderCodicons(command.title); let part: string; if (command.id) { part = `${title}`; diff --git a/src/vs/editor/contrib/colorPicker/colorDetector.ts b/src/vs/editor/contrib/colorPicker/colorDetector.ts index c1460b7650d..9e2113c38d9 100644 --- a/src/vs/editor/contrib/colorPicker/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/colorDetector.ts @@ -25,9 +25,9 @@ const MAX_DECORATORS = 500; export class ColorDetector extends Disposable implements IEditorContribution { - private static readonly ID: string = 'editor.contrib.colorDetector'; + public static readonly ID: string = 'editor.contrib.colorDetector'; - static RECOMPUTE_TIME = 1000; // ms + static readonly RECOMPUTE_TIME = 1000; // ms private readonly _localToDispose = this._register(new DisposableStore()); private _computePromise: CancelablePromise | null; @@ -88,10 +88,6 @@ export class ColorDetector extends Disposable implements IEditorContribution { return this._editor.getOption(EditorOption.colorDecorators); } - getId(): string { - return ColorDetector.ID; - } - static get(editor: ICodeEditor): ColorDetector { return editor.getContribution(this.ID); } @@ -247,4 +243,4 @@ export class ColorDetector extends Disposable implements IEditorContribution { } } -registerEditorContribution(ColorDetector); +registerEditorContribution(ColorDetector.ID, ColorDetector); diff --git a/src/vs/editor/contrib/colorPicker/colorPicker.css b/src/vs/editor/contrib/colorPicker/colorPicker.css index d1d83d46b2b..123ada78476 100644 --- a/src/vs/editor/contrib/colorPicker/colorPicker.css +++ b/src/vs/editor/contrib/colorPicker/colorPicker.css @@ -6,6 +6,8 @@ .colorpicker-widget { height: 190px; user-select: none; + -webkit-user-select: none; + -ms-user-select: none; } .monaco-editor .colorpicker-hover:focus { @@ -115,4 +117,4 @@ .colorpicker-body .strip .overlay { height: 150px; pointer-events: none; -} \ No newline at end of file +} diff --git a/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts b/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts index 64329a79ba9..4a74a4a5e0d 100644 --- a/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts +++ b/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts @@ -32,7 +32,7 @@ export class ColorPickerHeader extends Disposable { this.pickedColorNode = dom.append(this.domNode, $('.picked-color')); const colorBox = dom.append(this.domNode, $('.original-color')); - colorBox.style.backgroundColor = Color.Format.CSS.format(this.model.originalColor); + colorBox.style.backgroundColor = Color.Format.CSS.format(this.model.originalColor) || ''; this.backgroundColor = themeService.getTheme().getColor(editorHoverBackground) || Color.white; this._register(registerThemingParticipant((theme, collector) => { @@ -46,12 +46,12 @@ export class ColorPickerHeader extends Disposable { })); this._register(model.onDidChangeColor(this.onDidChangeColor, this)); this._register(model.onDidChangePresentation(this.onDidChangePresentation, this)); - this.pickedColorNode.style.backgroundColor = Color.Format.CSS.format(model.color); + this.pickedColorNode.style.backgroundColor = Color.Format.CSS.format(model.color) || ''; dom.toggleClass(this.pickedColorNode, 'light', model.color.rgba.a < 0.5 ? this.backgroundColor.isLighter() : model.color.isLighter()); } private onDidChangeColor(color: Color): void { - this.pickedColorNode.style.backgroundColor = Color.Format.CSS.format(color); + this.pickedColorNode.style.backgroundColor = Color.Format.CSS.format(color) || ''; dom.toggleClass(this.pickedColorNode, 'light', color.rgba.a < 0.5 ? this.backgroundColor.isLighter() : color.isLighter()); this.onDidChangePresentation(); } diff --git a/src/vs/editor/contrib/comment/lineCommentCommand.ts b/src/vs/editor/contrib/comment/lineCommentCommand.ts index a097d994648..5c3716ed79c 100644 --- a/src/vs/editor/contrib/comment/lineCommentCommand.ts +++ b/src/vs/editor/contrib/comment/lineCommentCommand.ts @@ -13,6 +13,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { BlockCommentCommand } from 'vs/editor/contrib/comment/blockCommentCommand'; +import { Constants } from 'vs/base/common/uint'; export interface IInsertionPoint { ignore: boolean; @@ -392,7 +393,7 @@ export class LineCommentCommand implements editorCommon.ICommand { * Adjust insertion points to have them vertically aligned in the add line comment case */ public static _normalizeInsertionPoint(model: ISimpleModel, lines: IInsertionPoint[], startLineNumber: number, tabSize: number): void { - let minVisibleColumn = Number.MAX_VALUE; + let minVisibleColumn = Constants.MAX_SAFE_SMALL_INTEGER; let j: number; let lenJ: number; diff --git a/src/vs/editor/contrib/contextmenu/contextmenu.ts b/src/vs/editor/contrib/contextmenu/contextmenu.ts index e88f633d4ca..ea1d5f26b17 100644 --- a/src/vs/editor/contrib/contextmenu/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/contextmenu.ts @@ -26,7 +26,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class ContextMenuController implements IEditorContribution { - private static readonly ID = 'editor.contrib.contextmenu'; + public static readonly ID = 'editor.contrib.contextmenu'; public static get(editor: ICodeEditor): ContextMenuController { return editor.getContribution(ContextMenuController.ID); @@ -90,8 +90,18 @@ export class ContextMenuController implements IEditorContribution { this._editor.focus(); // Ensure the cursor is at the position of the mouse click - if (e.target.position && !this._editor.getSelection().containsPosition(e.target.position)) { - this._editor.setPosition(e.target.position); + if (e.target.position) { + let hasSelectionAtPosition = false; + for (const selection of this._editor.getSelections()) { + if (selection.containsPosition(e.target.position)) { + hasSelectionAtPosition = true; + break; + } + } + + if (!hasSelectionAtPosition) { + this._editor.setPosition(e.target.position); + } } // Unless the user triggerd the context menu through Shift+F10, use the mouse position as menu position @@ -209,10 +219,6 @@ export class ContextMenuController implements IEditorContribution { return this._keybindingService.lookupKeybinding(action.id); } - public getId(): string { - return ContextMenuController.ID; - } - public dispose(): void { if (this._contextMenuIsBeingShownCount > 0) { this._contextViewService.hideContextView(); @@ -244,5 +250,5 @@ class ShowContextMenu extends EditorAction { } } -registerEditorContribution(ContextMenuController); +registerEditorContribution(ContextMenuController.ID, ContextMenuController); registerEditorAction(ShowContextMenu); diff --git a/src/vs/editor/contrib/cursorUndo/cursorUndo.ts b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts index 0d9ea4ea21e..aecd7026498 100644 --- a/src/vs/editor/contrib/cursorUndo/cursorUndo.ts +++ b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts @@ -35,81 +35,82 @@ class CursorState { } } -export class CursorUndoController extends Disposable implements IEditorContribution { +export class CursorUndoRedoController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.cursorUndoController'; + public static readonly ID = 'editor.contrib.cursorUndoRedoController'; - public static get(editor: ICodeEditor): CursorUndoController { - return editor.getContribution(CursorUndoController.ID); + public static get(editor: ICodeEditor): CursorUndoRedoController { + return editor.getContribution(CursorUndoRedoController.ID); } private readonly _editor: ICodeEditor; - private _isCursorUndo: boolean; + private _isCursorUndoRedo: boolean; private _undoStack: CursorState[]; - private _prevState: CursorState | null; + private _redoStack: CursorState[]; constructor(editor: ICodeEditor) { super(); this._editor = editor; - this._isCursorUndo = false; + this._isCursorUndoRedo = false; this._undoStack = []; - this._prevState = this._readState(); + this._redoStack = []; this._register(editor.onDidChangeModel((e) => { this._undoStack = []; - this._prevState = null; + this._redoStack = []; })); this._register(editor.onDidChangeModelContent((e) => { this._undoStack = []; - this._prevState = null; + this._redoStack = []; })); this._register(editor.onDidChangeCursorSelection((e) => { - - if (!this._isCursorUndo && this._prevState) { - this._undoStack.push(this._prevState); + if (this._isCursorUndoRedo) { + return; + } + if (!e.oldSelections) { + return; + } + if (e.oldModelVersionId !== e.modelVersionId) { + return; + } + const prevState = new CursorState(e.oldSelections); + const isEqualToLastUndoStack = (this._undoStack.length > 0 && this._undoStack[this._undoStack.length - 1].equals(prevState)); + if (!isEqualToLastUndoStack) { + this._undoStack.push(prevState); + this._redoStack = []; if (this._undoStack.length > 50) { // keep the cursor undo stack bounded this._undoStack.shift(); } } - - this._prevState = this._readState(); })); } - private _readState(): CursorState | null { - if (!this._editor.hasModel()) { - // no model => no state - return null; - } - - return new CursorState(this._editor.getSelections()); - } - - public getId(): string { - return CursorUndoController.ID; - } - public cursorUndo(): void { - if (!this._editor.hasModel()) { + if (!this._editor.hasModel() || this._undoStack.length === 0) { return; } - const currState = new CursorState(this._editor.getSelections()); + this._redoStack.push(new CursorState(this._editor.getSelections())); + this._applyState(this._undoStack.pop()!); + } - while (this._undoStack.length > 0) { - const prevState = this._undoStack.pop()!; - - if (!prevState.equals(currState)) { - this._isCursorUndo = true; - this._editor.setSelections(prevState.selections); - this._editor.revealRangeInCenterIfOutsideViewport(prevState.selections[0], ScrollType.Smooth); - this._isCursorUndo = false; - return; - } + public cursorRedo(): void { + if (!this._editor.hasModel() || this._redoStack.length === 0) { + return; } + + this._undoStack.push(new CursorState(this._editor.getSelections())); + this._applyState(this._redoStack.pop()!); + } + + private _applyState(state: CursorState): void { + this._isCursorUndoRedo = true; + this._editor.setSelections(state.selections); + this._editor.revealRangeInCenterIfOutsideViewport(state.selections[0], ScrollType.Smooth); + this._isCursorUndoRedo = false; } } @@ -117,8 +118,8 @@ export class CursorUndo extends EditorAction { constructor() { super({ id: 'cursorUndo', - label: nls.localize('cursor.undo', "Soft Undo"), - alias: 'Soft Undo', + label: nls.localize('cursor.undo', "Cursor Undo"), + alias: 'Cursor Undo', precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, @@ -129,9 +130,25 @@ export class CursorUndo extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { - CursorUndoController.get(editor).cursorUndo(); + CursorUndoRedoController.get(editor).cursorUndo(); } } -registerEditorContribution(CursorUndoController); +export class CursorRedo extends EditorAction { + constructor() { + super({ + id: 'cursorRedo', + label: nls.localize('cursor.redo', "Cursor Redo"), + alias: 'Cursor Redo', + precondition: undefined + }); + } + + public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { + CursorUndoRedoController.get(editor).cursorRedo(); + } +} + +registerEditorContribution(CursorUndoRedoController.ID, CursorUndoRedoController); registerEditorAction(CursorUndo); +registerEditorAction(CursorRedo); diff --git a/src/vs/editor/contrib/cursorUndo/test/cursorUndo.test.ts b/src/vs/editor/contrib/cursorUndo/test/cursorUndo.test.ts new file mode 100644 index 00000000000..308484142e9 --- /dev/null +++ b/src/vs/editor/contrib/cursorUndo/test/cursorUndo.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 { Selection } from 'vs/editor/common/core/selection'; +import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; +import { CursorUndo, CursorUndoRedoController } from 'vs/editor/contrib/cursorUndo/cursorUndo'; +import { Handler } from 'vs/editor/common/editorCommon'; +import { CoreNavigationCommands, CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands'; + +suite('FindController', () => { + + const cursorUndoAction = new CursorUndo(); + + test('issue #82535: Edge case with cursorUndo', () => { + withTestCodeEditor([ + '' + ], {}, (editor) => { + + editor.registerAndInstantiateContribution(CursorUndoRedoController.ID, CursorUndoRedoController); + + // type hello + editor.trigger('test', Handler.Type, { text: 'hello' }); + + // press left + CoreNavigationCommands.CursorLeft.runEditorCommand(null, editor, {}); + + // press Delete + CoreEditingCommands.DeleteRight.runEditorCommand(null, editor, {}); + assert.deepEqual(editor.getValue(), 'hell'); + assert.deepEqual(editor.getSelections(), [new Selection(1, 5, 1, 5)]); + + // press left + CoreNavigationCommands.CursorLeft.runEditorCommand(null, editor, {}); + assert.deepEqual(editor.getSelections(), [new Selection(1, 4, 1, 4)]); + + // press Ctrl+U + cursorUndoAction.run(null!, editor, {}); + assert.deepEqual(editor.getSelections(), [new Selection(1, 5, 1, 5)]); + }); + }); + + test('issue #82535: Edge case with cursorUndo (reverse)', () => { + withTestCodeEditor([ + '' + ], {}, (editor) => { + + editor.registerAndInstantiateContribution(CursorUndoRedoController.ID, CursorUndoRedoController); + + // type hello + editor.trigger('test', Handler.Type, { text: 'hell' }); + editor.trigger('test', Handler.Type, { text: 'o' }); + assert.deepEqual(editor.getValue(), 'hello'); + assert.deepEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]); + + // press Ctrl+U + cursorUndoAction.run(null!, editor, {}); + assert.deepEqual(editor.getSelections(), [new Selection(1, 6, 1, 6)]); + }); + }); +}); diff --git a/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts index bbf3df37d01..f9c0cd00902 100644 --- a/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -31,14 +31,14 @@ function hasTriggerModifier(e: IKeyboardEvent | IMouseEvent): boolean { export class DragAndDropController extends Disposable implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.dragAndDrop'; + public static readonly ID = 'editor.contrib.dragAndDrop'; private readonly _editor: ICodeEditor; private _dragSelection: Selection | null; private _dndDecorationIds: string[]; private _mouseDown: boolean; private _modifierPressed: boolean; - static TRIGGER_KEY_VALUE = isMacintosh ? KeyCode.Alt : KeyCode.Ctrl; + static readonly TRIGGER_KEY_VALUE = isMacintosh ? KeyCode.Alt : KeyCode.Ctrl; static get(editor: ICodeEditor): DragAndDropController { return editor.getContribution(DragAndDropController.ID); @@ -219,10 +219,6 @@ export class DragAndDropController extends Disposable implements editorCommon.IE target.type === MouseTargetType.GUTTER_LINE_DECORATIONS; } - public getId(): string { - return DragAndDropController.ID; - } - public dispose(): void { this._removeDecoration(); this._dragSelection = null; @@ -232,4 +228,4 @@ export class DragAndDropController extends Disposable implements editorCommon.IE } } -registerEditorContribution(DragAndDropController); +registerEditorContribution(DragAndDropController.ID, DragAndDropController); diff --git a/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg b/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg deleted file mode 100644 index e009568b131..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg b/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg deleted file mode 100644 index 06613f8bedd..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/class-dark.svg b/src/vs/editor/contrib/documentSymbols/media/class-dark.svg deleted file mode 100644 index a71e221f6bd..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/class-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/class-light.svg b/src/vs/editor/contrib/documentSymbols/media/class-light.svg deleted file mode 100644 index aa106f18f87..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/class-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg b/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg deleted file mode 100644 index 0e90ecafcd8..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/constant-light.svg b/src/vs/editor/contrib/documentSymbols/media/constant-light.svg deleted file mode 100644 index 1a369c1d8aa..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/constant-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg deleted file mode 100644 index 82d4ff29c44..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg deleted file mode 100644 index 23c697fdf17..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg deleted file mode 100644 index a99045d3352..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg deleted file mode 100644 index e2441a0dc16..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/event-dark.svg b/src/vs/editor/contrib/documentSymbols/media/event-dark.svg deleted file mode 100644 index 051bef316e9..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/event-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/event-light.svg b/src/vs/editor/contrib/documentSymbols/media/event-light.svg deleted file mode 100644 index 712344d1f92..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/event-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/field-dark.svg b/src/vs/editor/contrib/documentSymbols/media/field-dark.svg deleted file mode 100644 index 15623061c5d..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/field-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/field-light.svg b/src/vs/editor/contrib/documentSymbols/media/field-light.svg deleted file mode 100644 index 72dd79504f6..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/field-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/file-dark.svg b/src/vs/editor/contrib/documentSymbols/media/file-dark.svg deleted file mode 100644 index 5ed5762a1f0..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/file-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/file-light.svg b/src/vs/editor/contrib/documentSymbols/media/file-light.svg deleted file mode 100644 index ad54e13b1b1..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/file-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg b/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg deleted file mode 100644 index e92131d3d02..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg b/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg deleted file mode 100644 index 207899642c8..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg b/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg deleted file mode 100644 index 6d482b2abde..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/interface-light.svg b/src/vs/editor/contrib/documentSymbols/media/interface-light.svg deleted file mode 100644 index a397dd00b00..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/interface-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg b/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg deleted file mode 100644 index 70ba6ea9331..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg b/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg deleted file mode 100644 index fc57528a3ef..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/method-dark.svg b/src/vs/editor/contrib/documentSymbols/media/method-dark.svg deleted file mode 100644 index 970d7b61480..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/method-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/method-light.svg b/src/vs/editor/contrib/documentSymbols/media/method-light.svg deleted file mode 100644 index 403a9b90dd9..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/method-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg b/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg deleted file mode 100644 index 9a725bb41fd..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg b/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg deleted file mode 100644 index 1339da7ce21..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg b/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg deleted file mode 100644 index a1573df0107..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg b/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg deleted file mode 100644 index ea0e56e0225..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg b/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg deleted file mode 100644 index 957f5f44f17..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/operator-light.svg b/src/vs/editor/contrib/documentSymbols/media/operator-light.svg deleted file mode 100644 index bf6ed57996a..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/operator-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/outlineTree.css b/src/vs/editor/contrib/documentSymbols/media/outlineTree.css index ebc2389a0e2..e7953bf8ec6 100644 --- a/src/vs/editor/contrib/documentSymbols/media/outlineTree.css +++ b/src/vs/editor/contrib/documentSymbols/media/outlineTree.css @@ -35,7 +35,11 @@ } .monaco-list .outline-element .outline-element-decoration.bubble { - font-family: octicons; + font-family: codicon; font-size: 14px; opacity: 0.4; } + +.monaco-list .outline-element .outline-element-icon { + margin-right: 4px; +} diff --git a/src/vs/editor/contrib/documentSymbols/media/property-dark.svg b/src/vs/editor/contrib/documentSymbols/media/property-dark.svg deleted file mode 100644 index 23e07ffa19b..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/property-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/property-light.svg b/src/vs/editor/contrib/documentSymbols/media/property-light.svg deleted file mode 100644 index be642dd152d..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/property-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg b/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg deleted file mode 100644 index 79799f98c26..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg b/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg deleted file mode 100644 index 45fa3a001e8..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/string-dark.svg b/src/vs/editor/contrib/documentSymbols/media/string-dark.svg deleted file mode 100644 index 80fb9d6567d..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/string-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/string-light.svg b/src/vs/editor/contrib/documentSymbols/media/string-light.svg deleted file mode 100644 index 02a0282e906..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/string-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg b/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg deleted file mode 100644 index 13766a5dcea..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/structure-light.svg b/src/vs/editor/contrib/documentSymbols/media/structure-light.svg deleted file mode 100644 index c96bcfa61b0..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/structure-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css b/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css index 0504a233a63..0885772974f 100644 --- a/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css +++ b/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css @@ -9,9 +9,9 @@ } .monaco-workbench .symbol-icon.inline { - background-position: left center; - padding-left: 20px; - background-size: 16px 16px; + display: flex; + align-items: center; + padding-left: 0; } .monaco-workbench .symbol-icon.block { @@ -22,267 +22,3 @@ min-width: 16px; background-position: center; } - -/* default icons */ -.monaco-workbench .symbol-icon { - 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-dark.svg'); -} - -/* constant */ -.monaco-workbench .symbol-icon.constant { - background-image: url('constant-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.constant, -.hc-black .monaco-workbench .symbol-icon.constant { - background-image: url('constant-dark.svg'); -} - -/* enum */ -.monaco-workbench .symbol-icon.enum { - background-image: url('enumerator-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.enum, -.hc-black .monaco-workbench .symbol-icon.enum { - background-image: url('enumerator-dark.svg'); -} - -/* enum-member */ -.monaco-workbench .symbol-icon.enum-member { - 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('enumerator-item-dark.svg'); -} - -/* struct */ -.monaco-workbench .symbol-icon.struct { - background-image: url('structure-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.struct, -.hc-black .monaco-workbench .symbol-icon.struct { - background-image: url('structure-dark.svg'); -} - -/* event */ -.monaco-workbench .symbol-icon.event { - background-image: url('event-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.event, -.hc-black .monaco-workbench .symbol-icon.event { - background-image: url('event-dark.svg'); -} - -/* operator */ -.monaco-workbench .symbol-icon.operator { - background-image: url('operator-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.operator, -.hc-black .monaco-workbench .symbol-icon.operator { - background-image: url('operator-dark.svg'); -} - -/* type paramter */ -.monaco-workbench .symbol-icon.type-parameter { - 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-dark.svg'); -} - -/* boolean, null */ -.monaco-workbench .symbol-icon.boolean { - background-image: url('boolean-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.boolean, -.hc-black .monaco-workbench .symbol-icon.boolean { - background-image: url('boolean-dark.svg'); -} - -/* null */ -.monaco-workbench .symbol-icon.null { - background-image: url('boolean-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.null, -.hc-black .monaco-workbench .symbol-icon.null { - background-image: url('boolean-dark.svg'); -} - -/* class */ -.monaco-workbench .symbol-icon.class { - background-image: url('class-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.class, -.hc-black .monaco-workbench .symbol-icon.class { - background-image: url('class-dark.svg'); -} - -/* constructor */ -.monaco-workbench .symbol-icon.constructor { - background-image: url('method-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.constructor, -.hc-black .monaco-workbench .symbol-icon.constructor { - background-image: url('method-dark.svg'); -} - -/* file */ -.monaco-workbench .symbol-icon.file { - background-image: url('file-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.file, -.hc-black .monaco-workbench .symbol-icon.file { - background-image: url('file-dark.svg'); -} - -/* field */ -.monaco-workbench .symbol-icon.field { - background-image: url('field-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.field, -.hc-black .monaco-workbench .symbol-icon.field { - background-image: url('field-dark.svg'); -} - -/* variable */ -.monaco-workbench .symbol-icon.variable { - background-image: url('variable-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.variable, -.hc-black .monaco-workbench .symbol-icon.variable { - background-image: url('variable-dark.svg'); -} - -/* array */ -.monaco-workbench .symbol-icon.array { - background-image: url('indexer-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.array, -.hc-black .monaco-workbench .symbol-icon.array { - background-image: url('indexer-dark.svg'); -} - -/* keyword */ -/* todo@joh not used? */ -.monaco-workbench .symbol-icon.keyword { - background-image: url('keyword-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.keyword, -.hc-black .monaco-workbench .symbol-icon.keyword { - background-image: url('keyword-dark.svg'); -} - -/* interface */ -.monaco-workbench .symbol-icon.interface { - background-image: url('interface-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.interface, -.hc-black .monaco-workbench .symbol-icon.interface { - background-image: url('interface-dark.svg'); -} - -/* method */ -.monaco-workbench .symbol-icon.method { - background-image: url('method-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.method, -.hc-black .monaco-workbench .symbol-icon.method { - background-image: url('method-dark.svg'); -} - -/* function */ -.monaco-workbench .symbol-icon.function { - background-image: url('method-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.function, -.hc-black .monaco-workbench .symbol-icon.function { - background-image: url('method-dark.svg'); -} - -/* object */ -.monaco-workbench .symbol-icon.object { - background-image: url('namespace-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.object, -.hc-black .monaco-workbench .symbol-icon.object { - background-image: url('namespace-dark.svg'); -} - -/* namespace */ -.monaco-workbench .symbol-icon.namespace { - background-image: url('namespace-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.namespace, -.hc-black .monaco-workbench .symbol-icon.namespace { - background-image: url('namespace-dark.svg'); -} - -/* package */ -.monaco-workbench .symbol-icon.package { - background-image: url('namespace-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.package, -.hc-black .monaco-workbench .symbol-icon.package { - background-image: url('namespace-dark.svg'); -} - -/* module */ -.monaco-workbench .symbol-icon.module { - background-image: url('namespace-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.module, -.hc-black .monaco-workbench .symbol-icon.module { - background-image: url('namespace-dark.svg'); -} - -/* number */ -.monaco-workbench .symbol-icon.number { - background-image: url('numeric-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.number, -.hc-black .monaco-workbench .symbol-icon.number { - background-image: url('numeric-dark.svg'); -} - -/* property */ -.monaco-workbench .symbol-icon.property { - background-image: url('property-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.property, -.hc-black .monaco-workbench .symbol-icon.property { - background-image: url('property-dark.svg'); -} - -/* snippet */ -/* todo@joh unused? */ -.monaco-workbench .symbol-icon.snippet { - background-image: url('snippet-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.snippet, -.hc-black .monaco-workbench .symbol-icon.snippet { - background-image: url('snippet-dark.svg'); -} - -/* string */ -.monaco-workbench .symbol-icon.string { - background-image: url('string-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.string, -.hc-black .monaco-workbench .symbol-icon.string { - background-image: url('string-dark.svg'); -} - -/* key */ -.monaco-workbench .symbol-icon.key { - background-image: url('string-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.key, -.hc-black .monaco-workbench .symbol-icon.key { - 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 deleted file mode 100644 index 425ced36f0e..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/template-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/template-light.svg b/src/vs/editor/contrib/documentSymbols/media/template-light.svg deleted file mode 100644 index 496d8f7c85c..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/template-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg b/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg deleted file mode 100644 index 687fcabfff5..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/variable-light.svg b/src/vs/editor/contrib/documentSymbols/media/variable-light.svg deleted file mode 100644 index ede7e9434dd..00000000000 --- a/src/vs/editor/contrib/documentSymbols/media/variable-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/outlineTree.ts b/src/vs/editor/contrib/documentSymbols/outlineTree.ts index 84ac8bb704c..970453bc12b 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineTree.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineTree.ts @@ -6,21 +6,21 @@ import * as dom from 'vs/base/browser/dom'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { IIdentityProvider, IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; -import { IDataSource, ITreeNode, ITreeRenderer, ITreeSorter } from 'vs/base/browser/ui/tree/tree'; -import { values } from 'vs/base/common/collections'; +import { IDataSource, ITreeNode, ITreeRenderer, ITreeSorter, ITreeFilter } from 'vs/base/browser/ui/tree/tree'; +import { values, forEach } from 'vs/base/common/collections'; import { createMatches, FuzzyScore } from 'vs/base/common/filters'; import 'vs/css!./media/outlineTree'; import 'vs/css!./media/symbol-icons'; import { Range } from 'vs/editor/common/core/range'; -import { SymbolKind, symbolKindToCssClass, SymbolTag } from 'vs/editor/common/modes'; +import { SymbolKind, SymbolKinds, SymbolTag } from 'vs/editor/common/modes'; import { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; 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 { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; +import { registerColor, listErrorForeground, listWarningForeground, foreground } from 'vs/platform/theme/common/colorRegistry'; import { IdleValue } from 'vs/base/common/async'; export type OutlineItem = OutlineGroup | OutlineElement; @@ -44,7 +44,7 @@ export class OutlineIdentityProvider implements IIdentityProvider { } export class OutlineGroupTemplate { - static id = 'OutlineGroupTemplate'; + static readonly id = 'OutlineGroupTemplate'; constructor( readonly labelContainer: HTMLElement, readonly label: HighlightedLabel, @@ -52,10 +52,11 @@ export class OutlineGroupTemplate { } export class OutlineElementTemplate { - static id = 'OutlineElementTemplate'; + static readonly id = 'OutlineElementTemplate'; constructor( readonly container: HTMLElement, readonly iconLabel: IconLabel, + readonly iconClass: HTMLElement, readonly decoration: HTMLElement, ) { } } @@ -110,9 +111,11 @@ export class OutlineElementRenderer implements ITreeRenderer, index: number, template: OutlineElementTemplate): void { @@ -125,7 +128,8 @@ export class OutlineElementRenderer implements ITreeRenderer= 0) { options.extraClasses.push(`deprecated`); @@ -168,7 +172,7 @@ export class OutlineElementRenderer implements ITreeRenderer { + + static readonly configNameToKind = Object.freeze({ + ['showFiles']: SymbolKind.File, + ['showModules']: SymbolKind.Module, + ['showNamespaces']: SymbolKind.Namespace, + ['showPackages']: SymbolKind.Package, + ['showClasses']: SymbolKind.Class, + ['showMethods']: SymbolKind.Method, + ['showProperties']: SymbolKind.Property, + ['showFields']: SymbolKind.Field, + ['showConstructors']: SymbolKind.Constructor, + ['showEnums']: SymbolKind.Enum, + ['showInterfaces']: SymbolKind.Interface, + ['showFunctions']: SymbolKind.Function, + ['showVariables']: SymbolKind.Variable, + ['showConstants']: SymbolKind.Constant, + ['showStrings']: SymbolKind.String, + ['showNumbers']: SymbolKind.Number, + ['showBooleans']: SymbolKind.Boolean, + ['showArrays']: SymbolKind.Array, + ['showObjects']: SymbolKind.Object, + ['showKeys']: SymbolKind.Key, + ['showNull']: SymbolKind.Null, + ['showEnumMembers']: SymbolKind.EnumMember, + ['showStructs']: SymbolKind.Struct, + ['showEvents']: SymbolKind.Event, + ['showOperators']: SymbolKind.Operator, + ['showTypeParameters']: SymbolKind.TypeParameter, + }); + + static readonly kindToConfigName = Object.freeze({ + [SymbolKind.File]: 'showFiles', + [SymbolKind.Module]: 'showModules', + [SymbolKind.Namespace]: 'showNamespaces', + [SymbolKind.Package]: 'showPackages', + [SymbolKind.Class]: 'showClasses', + [SymbolKind.Method]: 'showMethods', + [SymbolKind.Property]: 'showProperties', + [SymbolKind.Field]: 'showFields', + [SymbolKind.Constructor]: 'showConstructors', + [SymbolKind.Enum]: 'showEnums', + [SymbolKind.Interface]: 'showInterfaces', + [SymbolKind.Function]: 'showFunctions', + [SymbolKind.Variable]: 'showVariables', + [SymbolKind.Constant]: 'showConstants', + [SymbolKind.String]: 'showStrings', + [SymbolKind.Number]: 'showNumbers', + [SymbolKind.Boolean]: 'showBooleans', + [SymbolKind.Array]: 'showArrays', + [SymbolKind.Object]: 'showObjects', + [SymbolKind.Key]: 'showKeys', + [SymbolKind.Null]: 'showNull', + [SymbolKind.EnumMember]: 'showEnumMembers', + [SymbolKind.Struct]: 'showStructs', + [SymbolKind.Event]: 'showEvents', + [SymbolKind.Operator]: 'showOperators', + [SymbolKind.TypeParameter]: 'showTypeParameters', + }); + + private readonly _filteredTypes = new Set(); + + constructor( + private readonly _prefix: string, + @IConfigurationService private readonly _configService: IConfigurationService, + ) { + this.update(); + } + + update() { + this._filteredTypes.clear(); + forEach(OutlineFilter.configNameToKind, entry => { + const key = `${this._prefix}.${entry.key}`; + if (this._configService.getValue(key) === false) { + this._filteredTypes.add(entry.value); + } + }); + } + + filter(element: OutlineItem): boolean { + return !(element instanceof OutlineElement) || !this._filteredTypes.has(element.symbol.kind); + } +} + export class OutlineItemComparator implements ITreeSorter { private readonly _collator = new IdleValue(() => new Intl.Collator(undefined, { numeric: true })); @@ -248,3 +336,503 @@ export class OutlineDataSource implements IDataSource return values(element.children); } } + +export const SYMBOL_ICON_ARRAY_FOREGROUND = registerColor('symbolIcon.arrayForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.arrayForeground', 'The foreground color for array symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_BOOLEAN_FOREGROUND = registerColor('symbolIcon.booleanForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.booleanForeground', 'The foreground color for boolean symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_CLASS_FOREGROUND = registerColor('symbolIcon.classForeground', { + dark: '#EE9D28', + light: '#D67E00', + hc: '#EE9D28' +}, localize('symbolIcon.classForeground', 'The foreground color for class symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_COLOR_FOREGROUND = registerColor('symbolIcon.colorForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.colorForeground', 'The foreground color for color symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_CONSTANT_FOREGROUND = registerColor('symbolIcon.constantForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.constantForeground', 'The foreground color for constant symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_CONSTRUCTOR_FOREGROUND = registerColor('symbolIcon.constructorForeground', { + dark: '#B180D7', + light: '#652D90', + hc: '#B180D7' +}, localize('symbolIcon.constructorForeground', 'The foreground color for constructor symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_ENUMERATOR_FOREGROUND = registerColor('symbolIcon.enumeratorForeground', { + dark: '#EE9D28', + light: '#D67E00', + hc: '#EE9D28' +}, localize('symbolIcon.enumeratorForeground', 'The foreground color for enumerator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND = registerColor('symbolIcon.enumeratorMemberForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('symbolIcon.enumeratorMemberForeground', 'The foreground color for enumerator member symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_EVENT_FOREGROUND = registerColor('symbolIcon.eventForeground', { + dark: '#EE9D28', + light: '#D67E00', + hc: '#EE9D28' +}, localize('symbolIcon.eventForeground', 'The foreground color for event symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_FIELD_FOREGROUND = registerColor('symbolIcon.fieldForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('symbolIcon.fieldForeground', 'The foreground color for field symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_FILE_FOREGROUND = registerColor('symbolIcon.fileForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.fileForeground', 'The foreground color for file symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_FOLDER_FOREGROUND = registerColor('symbolIcon.folderForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.folderForeground', 'The foreground color for folder symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_FUNCTION_FOREGROUND = registerColor('symbolIcon.functionForeground', { + dark: '#B180D7', + light: '#652D90', + hc: '#B180D7' +}, localize('symbolIcon.functionForeground', 'The foreground color for function symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_INTERFACE_FOREGROUND = registerColor('symbolIcon.interfaceForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('symbolIcon.interfaceForeground', 'The foreground color for interface symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_KEY_FOREGROUND = registerColor('symbolIcon.keyForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.keyForeground', 'The foreground color for key symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_KEYWORD_FOREGROUND = registerColor('symbolIcon.keywordForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.keywordForeground', 'The foreground color for keyword symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_METHOD_FOREGROUND = registerColor('symbolIcon.methodForeground', { + dark: '#B180D7', + light: '#652D90', + hc: '#B180D7' +}, localize('symbolIcon.methodForeground', 'The foreground color for method symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_MODULE_FOREGROUND = registerColor('symbolIcon.moduleForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.moduleForeground', 'The foreground color for module symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_NAMESPACE_FOREGROUND = registerColor('symbolIcon.namespaceForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.namespaceForeground', 'The foreground color for namespace symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_NULL_FOREGROUND = registerColor('symbolIcon.nullForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.nullForeground', 'The foreground color for null symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_NUMBER_FOREGROUND = registerColor('symbolIcon.numberForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.numberForeground', 'The foreground color for number symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_OBJECT_FOREGROUND = registerColor('symbolIcon.objectForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.objectForeground', 'The foreground color for object symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_OPERATOR_FOREGROUND = registerColor('symbolIcon.operatorForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.operatorForeground', 'The foreground color for operator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_PACKAGE_FOREGROUND = registerColor('symbolIcon.packageForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.packageForeground', 'The foreground color for package symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_PROPERTY_FOREGROUND = registerColor('symbolIcon.propertyForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.propertyForeground', 'The foreground color for property symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_REFERENCE_FOREGROUND = registerColor('symbolIcon.referenceForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.referenceForeground', 'The foreground color for reference symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_SNIPPET_FOREGROUND = registerColor('symbolIcon.snippetForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.snippetForeground', 'The foreground color for snippet symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_STRING_FOREGROUND = registerColor('symbolIcon.stringForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.stringForeground', 'The foreground color for string symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_STRUCT_FOREGROUND = registerColor('symbolIcon.structForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.structForeground', 'The foreground color for struct symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_TEXT_FOREGROUND = registerColor('symbolIcon.textForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.textForeground', 'The foreground color for text symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_TYPEPARAMETER_FOREGROUND = registerColor('symbolIcon.typeParameterForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.typeParameterForeground', 'The foreground color for type parameter symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_UNIT_FOREGROUND = registerColor('symbolIcon.unitForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.unitForeground', 'The foreground color for unit symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_VARIABLE_FOREGROUND = registerColor('symbolIcon.variableForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('symbolIcon.variableForeground', 'The foreground color for variable symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + + const symbolIconArrayColor = theme.getColor(SYMBOL_ICON_ARRAY_FOREGROUND); + if (symbolIconArrayColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-array { + color: ${symbolIconArrayColor} !important; + } + `); + } + + const symbolIconBooleanColor = theme.getColor(SYMBOL_ICON_BOOLEAN_FOREGROUND); + if (symbolIconBooleanColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-boolean { + color: ${symbolIconBooleanColor} !important; + } + `); + } + + const symbolIconClassColor = theme.getColor(SYMBOL_ICON_CLASS_FOREGROUND); + if (symbolIconClassColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-class { + color: ${symbolIconClassColor} !important; + } + `); + } + + const symbolIconMethodColor = theme.getColor(SYMBOL_ICON_METHOD_FOREGROUND); + if (symbolIconMethodColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-method { + color: ${symbolIconMethodColor} !important; + } + `); + } + + const symbolIconColorColor = theme.getColor(SYMBOL_ICON_COLOR_FOREGROUND); + if (symbolIconColorColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-color { + color: ${symbolIconColorColor} !important; + } + `); + } + + const symbolIconConstantColor = theme.getColor(SYMBOL_ICON_CONSTANT_FOREGROUND); + if (symbolIconConstantColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-constant { + color: ${symbolIconConstantColor} !important; + } + `); + } + + const symbolIconConstructorColor = theme.getColor(SYMBOL_ICON_CONSTRUCTOR_FOREGROUND); + if (symbolIconConstructorColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-constructor { + color: ${symbolIconConstructorColor} !important; + } + `); + } + + const symbolIconEnumeratorColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_FOREGROUND); + if (symbolIconEnumeratorColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-value, + .monaco-workbench .codicon-symbol-enum { + color: ${symbolIconEnumeratorColor} !important; + } + `); + } + + const symbolIconEnumeratorMemberColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND); + if (symbolIconEnumeratorMemberColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-enum-member { + color: ${symbolIconEnumeratorMemberColor} !important; + } + `); + } + + const symbolIconEventColor = theme.getColor(SYMBOL_ICON_EVENT_FOREGROUND); + if (symbolIconEventColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-event { + color: ${symbolIconEventColor} !important; + } + `); + } + + const symbolIconFieldColor = theme.getColor(SYMBOL_ICON_FIELD_FOREGROUND); + if (symbolIconFieldColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-field { + color: ${symbolIconFieldColor} !important; + } + `); + } + + const symbolIconFileColor = theme.getColor(SYMBOL_ICON_FILE_FOREGROUND); + if (symbolIconFileColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-file { + color: ${symbolIconFileColor} !important; + } + `); + } + + const symbolIconFolderColor = theme.getColor(SYMBOL_ICON_FOLDER_FOREGROUND); + if (symbolIconFolderColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-folder { + color: ${symbolIconFolderColor} !important; + } + `); + } + + const symbolIconFunctionColor = theme.getColor(SYMBOL_ICON_FUNCTION_FOREGROUND); + if (symbolIconFunctionColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-function { + color: ${symbolIconFunctionColor} !important; + } + `); + } + + const symbolIconInterfaceColor = theme.getColor(SYMBOL_ICON_INTERFACE_FOREGROUND); + if (symbolIconInterfaceColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-interface { + color: ${symbolIconInterfaceColor} !important; + } + `); + } + + const symbolIconKeyColor = theme.getColor(SYMBOL_ICON_KEY_FOREGROUND); + if (symbolIconKeyColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-key { + color: ${symbolIconKeyColor} !important; + } + `); + } + + const symbolIconKeywordColor = theme.getColor(SYMBOL_ICON_KEYWORD_FOREGROUND); + if (symbolIconKeywordColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-keyword { + color: ${symbolIconKeywordColor} !important; + } + `); + } + + const symbolIconModuleColor = theme.getColor(SYMBOL_ICON_MODULE_FOREGROUND); + if (symbolIconModuleColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-module { + color: ${symbolIconModuleColor} !important; + } + `); + } + + const outlineNamespaceColor = theme.getColor(SYMBOL_ICON_NAMESPACE_FOREGROUND); + if (outlineNamespaceColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-namespace { + color: ${outlineNamespaceColor} !important; + } + `); + } + + const symbolIconNullColor = theme.getColor(SYMBOL_ICON_NULL_FOREGROUND); + if (symbolIconNullColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-null { + color: ${symbolIconNullColor} !important; + } + `); + } + + const symbolIconNumberColor = theme.getColor(SYMBOL_ICON_NUMBER_FOREGROUND); + if (symbolIconNumberColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-number { + color: ${symbolIconNumberColor} !important; + } + `); + } + + const symbolIconObjectColor = theme.getColor(SYMBOL_ICON_OBJECT_FOREGROUND); + if (symbolIconObjectColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-object { + color: ${symbolIconObjectColor} !important; + } + `); + } + + const symbolIconOperatorColor = theme.getColor(SYMBOL_ICON_OPERATOR_FOREGROUND); + if (symbolIconOperatorColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-operator { + color: ${symbolIconOperatorColor} !important; + } + `); + } + + const symbolIconPackageColor = theme.getColor(SYMBOL_ICON_PACKAGE_FOREGROUND); + if (symbolIconPackageColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-package { + color: ${symbolIconPackageColor} !important; + } + `); + } + + const symbolIconPropertyColor = theme.getColor(SYMBOL_ICON_PROPERTY_FOREGROUND); + if (symbolIconPropertyColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-property { + color: ${symbolIconPropertyColor} !important; + } + `); + } + + const symbolIconReferenceColor = theme.getColor(SYMBOL_ICON_REFERENCE_FOREGROUND); + if (symbolIconReferenceColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-reference { + color: ${symbolIconReferenceColor} !important; + } + `); + } + + const symbolIconSnippetColor = theme.getColor(SYMBOL_ICON_SNIPPET_FOREGROUND); + if (symbolIconSnippetColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-snippet { + color: ${symbolIconSnippetColor} !important; + } + `); + } + + const symbolIconStringColor = theme.getColor(SYMBOL_ICON_STRING_FOREGROUND); + if (symbolIconStringColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-string { + color: ${symbolIconStringColor} !important; + } + `); + } + + const symbolIconStructColor = theme.getColor(SYMBOL_ICON_STRUCT_FOREGROUND); + if (symbolIconStructColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-struct { + color: ${symbolIconStructColor} !important; + } + `); + } + + const symbolIconTextColor = theme.getColor(SYMBOL_ICON_TEXT_FOREGROUND); + if (symbolIconTextColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-text { + color: ${symbolIconTextColor} !important; + } + `); + } + + const symbolIconTypeParameterColor = theme.getColor(SYMBOL_ICON_TYPEPARAMETER_FOREGROUND); + if (symbolIconTypeParameterColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-type-parameter { + color: ${symbolIconTypeParameterColor} !important; + } + `); + } + + const symbolIconUnitColor = theme.getColor(SYMBOL_ICON_UNIT_FOREGROUND); + if (symbolIconUnitColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-unit { + color: ${symbolIconUnitColor} !important; + } + `); + } + + const symbolIconVariableColor = theme.getColor(SYMBOL_ICON_VARIABLE_FOREGROUND); + if (symbolIconVariableColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-variable { + color: ${symbolIconVariableColor} !important; + } + `); + } + +}); diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index f5c7305872f..ae362600757 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -70,7 +70,7 @@ export interface IFindStartOptions { export class CommonFindController extends Disposable implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.findController'; + public static readonly ID = 'editor.contrib.findController'; protected _editor: ICodeEditor; private readonly _findWidgetVisible: IContextKey; @@ -143,10 +143,6 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } } - public getId(): string { - return CommonFindController.ID; - } - private _onStateChanged(e: FindReplaceStateChangedEvent): void { this.saveQueryState(e); @@ -399,11 +395,27 @@ export class FindController extends CommonFindController implements IFindControl this._createFindWidget(); } - if (!this._widget!.getPosition() && this._editor.getOption(EditorOption.find).autoFindInSelection) { - // not visible yet so we need to set search scope if `editor.find.autoFindInSelection` is `true` - opts.updateSearchScope = true; + const selection = this._editor.getSelection(); + let updateSearchScope = false; + + switch (this._editor.getOption(EditorOption.find).autoFindInSelection) { + case 'always': + updateSearchScope = true; + break; + case 'never': + updateSearchScope = false; + break; + case 'multiline': + const isSelectionMultipleLine = !!selection && selection.startLineNumber !== selection.endLineNumber; + updateSearchScope = isSelectionMultipleLine; + break; + + default: + break; } + opts.updateSearchScope = updateSearchScope; + super._start(opts); if (opts.shouldFocus === FindStartFocusAction.FocusReplaceInput) { @@ -493,7 +505,7 @@ export class StartFindWithSelectionAction extends EditorAction { forceRevealReplace: false, seedSearchStringFromSelection: true, seedSearchStringFromGlobalClipboard: false, - shouldFocus: FindStartFocusAction.FocusFindInput, + shouldFocus: FindStartFocusAction.NoFocusChange, shouldAnimate: true, updateSearchScope: false }); @@ -735,7 +747,7 @@ export class StartFindReplaceAction extends EditorAction { } } -registerEditorContribution(FindController); +registerEditorContribution(CommonFindController.ID, FindController); registerEditorAction(StartFindAction); registerEditorAction(StartFindWithSelectionAction); diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index e039801431f..da67f86eb78 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -12,7 +12,7 @@ import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/commo import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { EndOfLinePreference, FindMatch, ITextModel } from 'vs/editor/common/model'; import { SearchParams } from 'vs/editor/common/model/textModelSearch'; diff --git a/src/vs/editor/contrib/find/findOptionsWidget.ts b/src/vs/editor/contrib/find/findOptionsWidget.ts index 76fe78b42de..b3d9b69e1f5 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, inputActiveOptionBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; export class FindOptionsWidget extends Widget implements IOverlayWidget { @@ -200,6 +200,12 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-editor .findOptionsWidget { background-color: ${widgetBackground}; }`); } + const widgetForeground = theme.getColor(editorWidgetForeground); + if (widgetForeground) { + collector.addRule(`.monaco-editor .findOptionsWidget { color: ${widgetForeground}; }`); + } + + const widgetShadowColor = theme.getColor(widgetShadow); if (widgetShadowColor) { collector.addRule(`.monaco-editor .findOptionsWidget { box-shadow: 0 2px 8px ${widgetShadowColor}; }`); @@ -209,4 +215,4 @@ registerThemingParticipant((theme, collector) => { if (hcBorder) { collector.addRule(`.monaco-editor .findOptionsWidget { border: 2px solid ${hcBorder}; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/editor/contrib/find/findState.ts b/src/vs/editor/contrib/find/findState.ts index 777e273148d..22451cf9bed 100644 --- a/src/vs/editor/contrib/find/findState.ts +++ b/src/vs/editor/contrib/find/findState.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { Range } from 'vs/editor/common/core/range'; export interface FindReplaceStateChangedEvent { @@ -57,7 +57,7 @@ function effectiveOptionValue(override: FindOptionOverride, value: boolean): boo return value; } -export class FindReplaceState implements IDisposable { +export class FindReplaceState extends Disposable { private _searchString: string; private _replaceString: string; private _isRevealed: boolean; @@ -74,7 +74,7 @@ export class FindReplaceState implements IDisposable { private _matchesPosition: number; private _matchesCount: number; private _currentMatch: Range | null; - private readonly _onFindReplaceStateChange = new Emitter(); + private readonly _onFindReplaceStateChange = this._register(new Emitter()); public get searchString(): string { return this._searchString; } public get replaceString(): string { return this._replaceString; } @@ -97,6 +97,7 @@ export class FindReplaceState implements IDisposable { public readonly onFindReplaceStateChange: Event = this._onFindReplaceStateChange.event; constructor() { + super(); this._searchString = ''; this._replaceString = ''; this._isRevealed = false; @@ -115,9 +116,6 @@ export class FindReplaceState implements IDisposable { this._currentMatch = null; } - public dispose(): void { - } - public changeMatchInfo(matchesPosition: number, matchesCount: number, currentMatch: Range | undefined): void { let changeEvent: FindReplaceStateChangedEvent = { moveCursor: false, diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index 23cf08a1ca2..5cabcc69c61 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -32,13 +32,17 @@ .monaco-editor .find-widget { position: absolute; z-index: 10; - top: -44px; height: 33px; overflow: hidden; line-height: 19px; - transition: top 200ms linear; + transition: transform 200ms linear; padding: 0 4px; box-sizing: border-box; + transform: translateY(Calc(-100% - 10px)); /* shadow (10px) */ +} + +.monaco-editor .find-widget textarea { + margin: 0px; } .monaco-editor .find-widget.hiddenEditor { @@ -46,30 +50,12 @@ } /* Find widget when replace is toggled on */ -.monaco-editor .find-widget.replaceToggled { - top: -74px; /* find input height + replace input height + shadow (10px) */ -} .monaco-editor .find-widget.replaceToggled > .replace-part { display: flex; - display: -webkit-flex; } -.monaco-editor .find-widget.visible, -.monaco-editor .find-widget.replaceToggled.visible { - top: 0; -} - -/* Multiple line find widget */ - -.monaco-editor .find-widget.multipleline { - top: unset; - bottom: 10px; -} - -.monaco-editor .find-widget.multipleline.visible, -.monaco-editor .find-widget.multipleline.replaceToggled.visible { - top: 0px; - bottom: unset; +.monaco-editor .find-widget.visible { + transform: translateY(0); } .monaco-editor .find-widget .monaco-inputbox.synthetic-focus { @@ -92,7 +78,6 @@ margin: 4px 0 0 17px; font-size: 12px; display: flex; - display: -webkit-flex; } .monaco-editor .find-widget > .find-part .monaco-inputbox, @@ -128,7 +113,6 @@ .monaco-editor .find-widget .monaco-findInput { vertical-align: middle; display: flex; - display: -webkit-flex; flex:1; } @@ -144,7 +128,6 @@ .monaco-editor .find-widget .matchesCount { display: flex; - display: -webkit-flex; flex: initial; margin: 0 0 0 3px; padding: 2px 0 0 2px; @@ -156,11 +139,9 @@ } .monaco-editor .find-widget .button { - min-width: 20px; width: 20px; height: 20px; display: flex; - display: -webkit-flex; flex: initial; margin-left: 3px; background-position: center center; @@ -189,14 +170,10 @@ .monaco-editor .find-widget .button.toggle { position: absolute; top: 0; - left: 0; + left: 3px; width: 18px; height: 100%; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; + box-sizing: border-box; } .monaco-editor .find-widget .button.toggle.disabled { @@ -249,7 +226,6 @@ .monaco-editor .find-widget > .replace-part > .monaco-findInput { position: relative; display: flex; - display: -webkit-flex; vertical-align: middle; flex: auto; flex-grow: 0; @@ -287,12 +263,6 @@ } .monaco-editor .findMatch { - -webkit-animation-duration: 0; - -webkit-animation-name: inherit !important; - -moz-animation-duration: 0; - -moz-animation-name: inherit !important; - -ms-animation-duration: 0; - -ms-animation-name: inherit !important; animation-duration: 0; animation-name: inherit !important; } diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index cb93002ad42..5c9aee4a2ed 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -10,6 +10,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { alert as alertFn } from 'vs/base/browser/ui/aria/aria'; +import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput'; import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox'; import { ReplaceInput } from 'vs/base/browser/ui/findinput/replaceInput'; @@ -120,7 +121,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _matchesCount!: HTMLElement; private _prevBtn!: SimpleButton; private _nextBtn!: SimpleButton; - private _toggleSelectionFind!: SimpleCheckbox; + private _toggleSelectionFind!: Checkbox; private _closeBtn!: SimpleButton; private _replaceBtn!: SimpleButton; private _replaceAllBtn!: SimpleButton; @@ -290,12 +291,6 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _onStateChanged(e: FindReplaceStateChangedEvent): void { if (e.searchString) { - if (this._state.searchString.indexOf('\n') >= 0) { - dom.addClass(this._domNode, 'multipleline'); - } else { - dom.removeClass(this._domNode, 'multipleline'); - } - try { this._ignoreChangeEvent = true; this._findInput.setValue(this._state.searchString); @@ -436,7 +431,11 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas let isSelection = selection ? (selection.startLineNumber !== selection.endLineNumber || selection.startColumn !== selection.endColumn) : false; let isChecked = this._toggleSelectionFind.checked; - this._toggleSelectionFind.setEnabled(this._isVisible && (isChecked || isSelection)); + if (this._isVisible && (isChecked || isSelection)) { + this._toggleSelectionFind.enable(); + } else { + this._toggleSelectionFind.disable(); + } } private _updateButtons(): void { @@ -466,12 +465,23 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._isVisible = true; const selection = this._codeEditor.getSelection(); - const isSelection = selection ? (selection.startLineNumber !== selection.endLineNumber || selection.startColumn !== selection.endColumn) : false; - if (isSelection && this._codeEditor.getOption(EditorOption.find).autoFindInSelection) { - this._toggleSelectionFind.checked = true; - } else { - this._toggleSelectionFind.checked = false; + + switch (this._codeEditor.getOption(EditorOption.find).autoFindInSelection) { + case 'always': + this._toggleSelectionFind.checked = true; + break; + case 'never': + this._toggleSelectionFind.checked = false; + break; + case 'multiline': + const isSelectionMultipleLine = !!selection && selection.startLineNumber !== selection.endLineNumber; + this._toggleSelectionFind.checked = isSelectionMultipleLine; + break; + + default: + break; } + this._tryUpdateWidgetWidth(); this._updateButtons(); @@ -636,6 +646,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas }; this._findInput.style(inputStyles); this._replaceInput.style(inputStyles); + this._toggleSelectionFind.style(inputStyles); } private _tryUpdateWidgetWidth() { @@ -981,26 +992,30 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas actionsContainer.appendChild(this._nextBtn.domNode); // Toggle selection button - this._toggleSelectionFind = this._register(new SimpleCheckbox({ - parent: actionsContainer, + this._toggleSelectionFind = this._register(new Checkbox({ + actionClassName: 'codicon codicon-selection', title: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand), - onChange: () => { - if (this._toggleSelectionFind.checked) { - if (this._codeEditor.hasModel()) { - let selection = this._codeEditor.getSelection(); - if (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) { - selection = selection.setEndPosition(selection.endLineNumber - 1, this._codeEditor.getModel().getLineMaxColumn(selection.endLineNumber - 1)); - } - if (!selection.isEmpty()) { - this._state.change({ searchScope: selection }, true); - } + isChecked: false + })); + + this._register(this._toggleSelectionFind.onChange(() => { + if (this._toggleSelectionFind.checked) { + if (this._codeEditor.hasModel()) { + let selection = this._codeEditor.getSelection(); + if (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) { + selection = selection.setEndPosition(selection.endLineNumber - 1, this._codeEditor.getModel().getLineMaxColumn(selection.endLineNumber - 1)); + } + if (!selection.isEmpty()) { + this._state.change({ searchScope: selection }, true); } - } else { - this._state.change({ searchScope: null }, true); } + } else { + this._state.change({ searchScope: null }, true); } })); + actionsContainer.appendChild(this._toggleSelectionFind.domNode); + // Close button this._closeBtn = this._register(new SimpleButton({ label: NLS_CLOSE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.CloseFindWidgetCommand), @@ -1054,7 +1069,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._prevBtn.focus(); } else if (this._nextBtn.isEnabled()) { this._nextBtn.focus(); - } else if (this._toggleSelectionFind.isEnabled()) { + } else if (this._toggleSelectionFind.enabled) { this._toggleSelectionFind.focus(); } else if (this._closeBtn.isEnabled()) { this._closeBtn.focus(); @@ -1200,91 +1215,6 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } } -interface ISimpleCheckboxOpts { - readonly parent: HTMLElement; - readonly title: string; - readonly onChange: () => void; -} - -class SimpleCheckbox extends Widget { - - private static _COUNTER = 0; - - private readonly _opts: ISimpleCheckboxOpts; - private readonly _domNode: HTMLElement; - private readonly _checkbox: HTMLInputElement; - private readonly _label: HTMLLabelElement; - - constructor(opts: ISimpleCheckboxOpts) { - super(); - this._opts = opts; - - this._domNode = document.createElement('div'); - this._domNode.className = 'monaco-checkbox'; - this._domNode.title = this._opts.title; - this._domNode.tabIndex = 0; - - this._checkbox = document.createElement('input'); - this._checkbox.type = 'checkbox'; - this._checkbox.className = 'checkbox'; - this._checkbox.id = 'checkbox-' + SimpleCheckbox._COUNTER++; - this._checkbox.tabIndex = -1; - - this._label = document.createElement('label'); - this._label.className = 'codicon codicon-selection'; - // Connect the label and the checkbox. Checkbox will get checked when the label receives a click. - this._label.htmlFor = this._checkbox.id; - this._label.tabIndex = -1; - - this._domNode.appendChild(this._checkbox); - this._domNode.appendChild(this._label); - - this._opts.parent.appendChild(this._domNode); - - this.onchange(this._checkbox, () => { - this._opts.onChange(); - }); - } - - public get domNode(): HTMLElement { - return this._domNode; - } - - public isEnabled(): boolean { - return (this._domNode.tabIndex >= 0); - } - - public get checked(): boolean { - return this._checkbox.checked; - } - - public set checked(newValue: boolean) { - this._checkbox.checked = newValue; - } - - public focus(): void { - this._domNode.focus(); - } - - private enable(): void { - this._checkbox.removeAttribute('disabled'); - } - - private disable(): void { - this._checkbox.disabled = true; - } - - public setEnabled(enabled: boolean): void { - if (enabled) { - this.enable(); - this.domNode.tabIndex = 0; - } else { - this.disable(); - this.domNode.tabIndex = -1; - } - } -} - export interface ISimpleButtonOpts { readonly label: string; readonly className: string; @@ -1390,7 +1320,7 @@ registerThemingParticipant((theme, collector) => { const hcBorder = theme.getColor(contrastBorder); if (hcBorder) { - collector.addRule(`.monaco-editor .find-widget { border: 2px solid ${hcBorder}; }`); + collector.addRule(`.monaco-editor .find-widget { border: 1px solid ${hcBorder}; }`); } const foreground = theme.getColor(editorWidgetForeground); diff --git a/src/vs/editor/contrib/find/test/findController.test.ts b/src/vs/editor/contrib/find/test/findController.test.ts index 6ac1767a275..3065cb082f9 100644 --- a/src/vs/editor/contrib/find/test/findController.test.ts +++ b/src/vs/editor/contrib/find/test/findController.test.ts @@ -89,7 +89,7 @@ suite('FindController', () => { assert.ok(true); return; } - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let startFindAction = new StartFindAction(); // I select ABC on the first line editor.setSelection(new Selection(1, 1, 1, 4)); @@ -115,7 +115,7 @@ suite('FindController', () => { return; } - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let findState = findController.getState(); let nextMatchFindAction = new NextMatchFindAction(); @@ -141,7 +141,7 @@ suite('FindController', () => { return; } - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let findState = findController.getState(); findState.change({ searchString: 'ABC' }, true); @@ -161,7 +161,7 @@ suite('FindController', () => { ], { serviceCollection: serviceCollection }, (editor, cursor) => { clipboardState = ''; // The cursor is at the very top, of the file, at the first ABC - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let findState = findController.getState(); let startFindAction = new StartFindAction(); let nextMatchFindAction = new NextMatchFindAction(); @@ -215,7 +215,7 @@ suite('FindController', () => { 'import nls = require(\'vs/nls\');' ], { serviceCollection: serviceCollection }, (editor, cursor) => { clipboardState = ''; - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let nextMatchFindAction = new NextMatchFindAction(); editor.setPosition({ @@ -240,7 +240,7 @@ suite('FindController', () => { 'var z = (3 * 5)', ], { serviceCollection: serviceCollection }, (editor, cursor) => { clipboardState = ''; - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let startFindAction = new StartFindAction(); let nextMatchFindAction = new NextMatchFindAction(); @@ -264,7 +264,7 @@ suite('FindController', () => { 'test', ], { serviceCollection: serviceCollection }, (editor, cursor) => { let testRegexString = 'tes.'; - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let nextMatchFindAction = new NextMatchFindAction(); let startFindReplaceAction = new StartFindReplaceAction(); @@ -294,7 +294,7 @@ suite('FindController', () => { 'var z = (3 * 5)', ], { serviceCollection: serviceCollection }, (editor, cursor) => { clipboardState = ''; - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); findController.start({ forceRevealReplace: false, seedSearchStringFromSelection: false, @@ -322,7 +322,7 @@ suite('FindController', () => { 'HRESULT OnAmbientPropertyChange(DISPID dispid);' ], { serviceCollection: serviceCollection }, (editor, cursor) => { clipboardState = ''; - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let startFindAction = new StartFindAction(); startFindAction.run(null, editor); @@ -349,7 +349,7 @@ suite('FindController', () => { 'line3' ], { serviceCollection: serviceCollection }, (editor, cursor) => { clipboardState = ''; - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let startFindAction = new StartFindAction(); startFindAction.run(null, editor); @@ -376,7 +376,7 @@ suite('FindController', () => { '([funny]' ], { serviceCollection: serviceCollection }, (editor, cursor) => { clipboardState = ''; - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let nextSelectionMatchFindAction = new NextSelectionMatchFindAction(); // toggle regex @@ -403,7 +403,7 @@ suite('FindController', () => { '([funny]' ], { serviceCollection: serviceCollection }, (editor, cursor) => { clipboardState = ''; - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let startFindAction = new StartFindAction(); let nextSelectionMatchFindAction = new NextSelectionMatchFindAction(); @@ -454,7 +454,7 @@ suite('FindController query options persistence', () => { ], { serviceCollection: serviceCollection }, (editor, cursor) => { queryState = { 'editor.isRegex': false, 'editor.matchCase': true, 'editor.wholeWord': false }; // The cursor is at the very top, of the file, at the first ABC - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let findState = findController.getState(); let startFindAction = new StartFindAction(); @@ -481,7 +481,7 @@ suite('FindController query options persistence', () => { ], { serviceCollection: serviceCollection }, (editor, cursor) => { queryState = { 'editor.isRegex': false, 'editor.matchCase': false, 'editor.wholeWord': true }; // The cursor is at the very top, of the file, at the first ABC - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); let findState = findController.getState(); let startFindAction = new StartFindAction(); @@ -506,7 +506,7 @@ suite('FindController query options persistence', () => { ], { serviceCollection: serviceCollection }, (editor, cursor) => { queryState = { 'editor.isRegex': false, 'editor.matchCase': false, 'editor.wholeWord': true }; // The cursor is at the very top, of the file, at the first ABC - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); findController.toggleRegex(); assert.equal(queryState['editor.isRegex'], true); @@ -519,10 +519,10 @@ suite('FindController query options persistence', () => { 'var x = (3 * 5)', 'var y = (3 * 5)', 'var z = (3 * 5)', - ], { serviceCollection: serviceCollection, find: { autoFindInSelection: true, globalFindClipboard: false } }, (editor, cursor) => { + ], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, (editor, cursor) => { // clipboardState = ''; editor.setSelection(new Range(1, 1, 2, 1)); - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); findController.start({ forceRevealReplace: false, @@ -542,10 +542,10 @@ suite('FindController query options persistence', () => { 'var x = (3 * 5)', 'var y = (3 * 5)', 'var z = (3 * 5)', - ], { serviceCollection: serviceCollection, find: { autoFindInSelection: true, globalFindClipboard: false } }, (editor, cursor) => { + ], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, (editor, cursor) => { // clipboardState = ''; editor.setSelection(new Range(1, 2, 1, 2)); - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); findController.start({ forceRevealReplace: false, @@ -565,10 +565,10 @@ suite('FindController query options persistence', () => { 'var x = (3 * 5)', 'var y = (3 * 5)', 'var z = (3 * 5)', - ], { serviceCollection: serviceCollection, find: { autoFindInSelection: true, globalFindClipboard: false } }, (editor, cursor) => { + ], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, (editor, cursor) => { // clipboardState = ''; editor.setSelection(new Range(1, 2, 1, 3)); - let findController = editor.registerAndInstantiateContribution(TestFindController); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); findController.start({ forceRevealReplace: false, @@ -582,4 +582,28 @@ suite('FindController query options persistence', () => { assert.deepEqual(findController.getState().searchScope, new Selection(1, 2, 1, 3)); }); }); + + + test('issue #27083: Find in selection when multiple lines are selected', () => { + withTestCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'multiline', globalFindClipboard: false } }, (editor, cursor) => { + // clipboardState = ''; + editor.setSelection(new Range(1, 6, 2, 1)); + let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController); + + findController.start({ + forceRevealReplace: false, + seedSearchStringFromSelection: false, + seedSearchStringFromGlobalClipboard: false, + shouldFocus: FindStartFocusAction.NoFocusChange, + shouldAnimate: false, + updateSearchScope: true + }); + + assert.deepEqual(findController.getState().searchScope, new Selection(1, 6, 2, 1)); + }); + }); }); diff --git a/src/vs/editor/contrib/find/test/replacePattern.test.ts b/src/vs/editor/contrib/find/test/replacePattern.test.ts index 3371aa02994..5a110c8160a 100644 --- a/src/vs/editor/contrib/find/test/replacePattern.test.ts +++ b/src/vs/editor/contrib/find/test/replacePattern.test.ts @@ -156,91 +156,58 @@ suite('Replace Pattern test', () => { }); test('buildReplaceStringWithCasePreserved test', () => { - let replacePattern = 'Def'; - let actual: string | string[] = 'abc'; + function assertReplace(target: string[], replaceString: string, expected: string): void { + let actual: string = ''; + actual = buildReplaceStringWithCasePreserved(target, replaceString); + assert.equal(actual, expected); + } - assert.equal(buildReplaceStringWithCasePreserved([actual], replacePattern), 'def'); - actual = 'Abc'; - assert.equal(buildReplaceStringWithCasePreserved([actual], replacePattern), 'Def'); - actual = 'ABC'; - assert.equal(buildReplaceStringWithCasePreserved([actual], replacePattern), 'DEF'); - - actual = ['abc', 'Abc']; - assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'def'); - actual = ['Abc', 'abc']; - assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'Def'); - actual = ['ABC', 'abc']; - assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'DEF'); - - actual = ['AbC']; - assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'Def'); - actual = ['aBC']; - assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'Def'); - - actual = ['Foo-Bar']; - assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar'), 'Newfoo-Newbar'); - actual = ['Foo-Bar-Abc']; - assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar-newabc'), 'Newfoo-Newbar-Newabc'); - actual = ['Foo-Bar-abc']; - assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar'), 'Newfoo-newbar'); - - actual = ['Foo_Bar']; - assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar'), 'Newfoo_Newbar'); - actual = ['Foo_Bar_Abc']; - assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar_newabc'), 'Newfoo_Newbar_Newabc'); - actual = ['Foo_Bar_abc']; - assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar'), 'Newfoo_newbar'); - actual = ['Foo_Bar-abc']; - assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo_newbar-abc'), 'Newfoo_newbar-abc'); + assertReplace(['abc'], 'Def', 'def'); + assertReplace(['Abc'], 'Def', 'Def'); + assertReplace(['ABC'], 'Def', 'DEF'); + assertReplace(['abc', 'Abc'], 'Def', 'def'); + assertReplace(['Abc', 'abc'], 'Def', 'Def'); + assertReplace(['ABC', 'abc'], 'Def', 'DEF'); + assertReplace(['AbC'], 'Def', 'Def'); + assertReplace(['aBC'], 'Def', 'Def'); + assertReplace(['Foo-Bar'], 'newfoo-newbar', 'Newfoo-Newbar'); + assertReplace(['Foo-Bar-Abc'], 'newfoo-newbar-newabc', 'Newfoo-Newbar-Newabc'); + assertReplace(['Foo-Bar-abc'], 'newfoo-newbar', 'Newfoo-newbar'); + assertReplace(['foo-Bar'], 'newfoo-newbar', 'newfoo-Newbar'); + assertReplace(['foo-BAR'], 'newfoo-newbar', 'newfoo-NEWBAR'); + assertReplace(['Foo_Bar'], 'newfoo_newbar', 'Newfoo_Newbar'); + assertReplace(['Foo_Bar_Abc'], 'newfoo_newbar_newabc', 'Newfoo_Newbar_Newabc'); + assertReplace(['Foo_Bar_abc'], 'newfoo_newbar', 'Newfoo_newbar'); + assertReplace(['Foo_Bar-abc'], 'newfoo_newbar-abc', 'Newfoo_newbar-abc'); + assertReplace(['foo_Bar'], 'newfoo_newbar', 'newfoo_Newbar'); + assertReplace(['Foo_BAR'], 'newfoo_newbar', 'Newfoo_NEWBAR'); }); 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'); + function assertReplace(target: string[], replaceString: string, expected: string): void { + let replacePattern = parseReplaceString(replaceString); + let actual = replacePattern.buildReplaceString(target, true); + assert.equal(actual, expected); + } - 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'); - - replacePattern = parseReplaceString('newfoo-newbar'); - actual = replacePattern.buildReplaceString(['Foo-Bar'], true); - assert.equal(actual, 'Newfoo-Newbar'); - - replacePattern = parseReplaceString('newfoo-newbar-newabc'); - actual = replacePattern.buildReplaceString(['Foo-Bar-Abc'], true); - assert.equal(actual, 'Newfoo-Newbar-Newabc'); - - replacePattern = parseReplaceString('newfoo-newbar'); - actual = replacePattern.buildReplaceString(['Foo-Bar-abc'], true); - assert.equal(actual, 'Newfoo-newbar'); - - replacePattern = parseReplaceString('newfoo_newbar'); - actual = replacePattern.buildReplaceString(['Foo_Bar'], true); - assert.equal(actual, 'Newfoo_Newbar'); - - replacePattern = parseReplaceString('newfoo_newbar_newabc'); - actual = replacePattern.buildReplaceString(['Foo_Bar_Abc'], true); - assert.equal(actual, 'Newfoo_Newbar_Newabc'); - - replacePattern = parseReplaceString('newfoo_newbar'); - actual = replacePattern.buildReplaceString(['Foo_Bar_abc'], true); - assert.equal(actual, 'Newfoo_newbar'); - - replacePattern = parseReplaceString('newfoo_newbar-abc'); - actual = replacePattern.buildReplaceString(['Foo_Bar-abc'], true); - assert.equal(actual, 'Newfoo_newbar-abc'); + assertReplace(['abc'], 'Def', 'def'); + assertReplace(['Abc'], 'Def', 'Def'); + assertReplace(['ABC'], 'Def', 'DEF'); + assertReplace(['abc', 'Abc'], 'Def', 'def'); + assertReplace(['Abc', 'abc'], 'Def', 'Def'); + assertReplace(['ABC', 'abc'], 'Def', 'DEF'); + assertReplace(['AbC'], 'Def', 'Def'); + assertReplace(['aBC'], 'Def', 'Def'); + assertReplace(['Foo-Bar'], 'newfoo-newbar', 'Newfoo-Newbar'); + assertReplace(['Foo-Bar-Abc'], 'newfoo-newbar-newabc', 'Newfoo-Newbar-Newabc'); + assertReplace(['Foo-Bar-abc'], 'newfoo-newbar', 'Newfoo-newbar'); + assertReplace(['foo-Bar'], 'newfoo-newbar', 'newfoo-Newbar'); + assertReplace(['foo-BAR'], 'newfoo-newbar', 'newfoo-NEWBAR'); + assertReplace(['Foo_Bar'], 'newfoo_newbar', 'Newfoo_Newbar'); + assertReplace(['Foo_Bar_Abc'], 'newfoo_newbar_newabc', 'Newfoo_Newbar_Newabc'); + assertReplace(['Foo_Bar_abc'], 'newfoo_newbar', 'Newfoo_newbar'); + assertReplace(['Foo_Bar-abc'], 'newfoo_newbar-abc', 'Newfoo_newbar-abc'); + assertReplace(['foo_Bar'], 'newfoo_newbar', 'newfoo_Newbar'); + assertReplace(['foo_BAR'], 'newfoo_newbar', 'newfoo_NEWBAR'); }); }); diff --git a/src/vs/editor/contrib/folding/folding.css b/src/vs/editor/contrib/folding/folding.css index df8421ef9c8..d19d4b73531 100644 --- a/src/vs/editor/contrib/folding/folding.css +++ b/src/vs/editor/contrib/folding/folding.css @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-editor .margin-view-overlays .codicon { +.monaco-editor .margin-view-overlays .codicon-chevron-right, +.monaco-editor .margin-view-overlays .codicon-chevron-down { cursor: pointer; opacity: 0; transition: opacity 0.5s; diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index f0ae51e1955..d000560f648 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -14,7 +14,7 @@ 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'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; -import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType } from 'vs/editor/contrib/folding/foldingModel'; +import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType, toggleCollapseState } from 'vs/editor/contrib/folding/foldingModel'; import { FoldingDecorationProvider } from './foldingDecorations'; import { FoldingRegions, FoldingRegion } from './foldingRanges'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; @@ -34,7 +34,6 @@ 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 { readonly id: string; @@ -50,11 +49,12 @@ interface FoldingStateMemento { export class FoldingController extends Disposable implements IEditorContribution { - static MAX_FOLDING_REGIONS = 5000; + public static ID = 'editor.contrib.folding'; + static readonly MAX_FOLDING_REGIONS = 5000; public static get(editor: ICodeEditor): FoldingController { - return editor.getContribution(ID); + return editor.getContribution(FoldingController.ID); } private readonly editor: ICodeEditor; @@ -134,10 +134,6 @@ export class FoldingController extends Disposable implements IEditorContribution this.onModelChanged(); } - public getId(): string { - return ID; - } - /** * Store view state. */ @@ -656,6 +652,30 @@ class FoldAction extends FoldingAction { } } + +class ToggleFoldAction extends FoldingAction { + + constructor() { + super({ + id: 'editor.toggleFold', + label: nls.localize('toggleFoldAction.label', "Toggle Fold"), + alias: 'Toggle Fold', + precondition: CONTEXT_FOLDING_ENABLED, + kbOpts: { + kbExpr: EditorContextKeys.editorTextFocus, + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_L), + weight: KeybindingWeight.EditorContrib + } + }); + } + + invoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void { + let selectedLines = this.getSelectedLines(editor); + toggleCollapseState(foldingModel, 1, selectedLines); + } +} + + class FoldRecursivelyAction extends FoldingAction { constructor() { @@ -832,7 +852,7 @@ class FoldLevelAction extends FoldingAction { } } -registerEditorContribution(FoldingController); +registerEditorContribution(FoldingController.ID, FoldingController); registerEditorAction(UnfoldAction); registerEditorAction(UnFoldRecursivelyAction); registerEditorAction(FoldAction); @@ -842,6 +862,7 @@ registerEditorAction(UnfoldAllAction); registerEditorAction(FoldAllBlockCommentsAction); registerEditorAction(FoldAllRegionsAction); registerEditorAction(UnfoldAllRegionsAction); +registerEditorAction(ToggleFoldAction); for (let i = 1; i <= 7; i++) { registerInstantiatedEditorAction( diff --git a/src/vs/editor/contrib/folding/foldingDecorations.ts b/src/vs/editor/contrib/folding/foldingDecorations.ts index 44554ac1300..333ad459db0 100644 --- a/src/vs/editor/contrib/folding/foldingDecorations.ts +++ b/src/vs/editor/contrib/folding/foldingDecorations.ts @@ -10,18 +10,18 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; export class FoldingDecorationProvider implements IDecorationProvider { - private static COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({ + private static readonly COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, afterContentClassName: 'inline-folded', linesDecorationsClassName: 'codicon codicon-chevron-right' }); - private static EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({ + private static readonly EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, linesDecorationsClassName: 'codicon codicon-chevron-down' }); - private static EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({ + private static readonly EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, linesDecorationsClassName: 'codicon codicon-chevron-down alwaysShowFoldIcons' }); diff --git a/src/vs/editor/contrib/folding/foldingModel.ts b/src/vs/editor/contrib/folding/foldingModel.ts index 15cc62d2098..44feb79cdf2 100644 --- a/src/vs/editor/contrib/folding/foldingModel.ts +++ b/src/vs/editor/contrib/folding/foldingModel.ts @@ -242,6 +242,26 @@ export class FoldingModel { } +/** + * Collapse or expand the regions at the given locations + * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels. + * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model. + */ +export function toggleCollapseState(foldingModel: FoldingModel, levels: number, lineNumbers: number[]) { + let toToggle: FoldingRegion[] = []; + for (let lineNumber of lineNumbers) { + let region = foldingModel.getRegionAtLine(lineNumber); + if (region) { + const doCollapse = !region.isCollapsed; + toToggle.push(region); + if (levels > 1) { + let regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels); + toToggle.push(...regionsInside); + } + } + } + foldingModel.toggleCollapseState(toToggle); +} /** diff --git a/src/vs/editor/contrib/format/formatActions.ts b/src/vs/editor/contrib/format/formatActions.ts index 1af6506e0d8..daded6e3e9d 100644 --- a/src/vs/editor/contrib/format/formatActions.ts +++ b/src/vs/editor/contrib/format/formatActions.ts @@ -28,7 +28,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; class FormatOnType implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.autoFormat'; + public static readonly ID = 'editor.contrib.autoFormat'; private readonly _editor: ICodeEditor; private readonly _callOnDispose = new DisposableStore(); @@ -45,10 +45,6 @@ class FormatOnType implements editorCommon.IEditorContribution { this._callOnDispose.add(OnTypeFormattingEditProviderRegistry.onDidChange(this._update, this)); } - getId(): string { - return FormatOnType.ID; - } - dispose(): void { this._callOnDispose.dispose(); this._callOnModel.dispose(); @@ -155,7 +151,7 @@ class FormatOnType implements editorCommon.IEditorContribution { class FormatOnPaste implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.formatOnPaste'; + public static readonly ID = 'editor.contrib.formatOnPaste'; private readonly _callOnDispose = new DisposableStore(); private readonly _callOnModel = new DisposableStore(); @@ -170,10 +166,6 @@ class FormatOnPaste implements editorCommon.IEditorContribution { this._callOnDispose.add(DocumentRangeFormattingEditProviderRegistry.onDidChange(this._update, this)); } - getId(): string { - return FormatOnPaste.ID; - } - dispose(): void { this._callOnDispose.dispose(); this._callOnModel.dispose(); @@ -278,8 +270,8 @@ class FormatSelectionAction extends EditorAction { } } -registerEditorContribution(FormatOnType); -registerEditorContribution(FormatOnPaste); +registerEditorContribution(FormatOnType.ID, FormatOnType); +registerEditorContribution(FormatOnPaste.ID, FormatOnPaste); registerEditorAction(FormatDocumentAction); registerEditorAction(FormatSelectionAction); diff --git a/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts b/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts index f23c13dcd38..003ed988f84 100644 --- a/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts +++ b/src/vs/editor/contrib/goToDefinition/clickLinkGesture.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./goToDefinitionMouse'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as browser from 'vs/base/browser/browser'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinition.ts b/src/vs/editor/contrib/goToDefinition/goToDefinition.ts index 07a1a1fbd76..5603b142eea 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinition.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinition.ts @@ -9,11 +9,11 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { Position } from 'vs/editor/common/core/position'; import { ITextModel } from 'vs/editor/common/model'; -import { LocationLink, DefinitionProviderRegistry, ImplementationProviderRegistry, TypeDefinitionProviderRegistry, DeclarationProviderRegistry, ProviderResult } from 'vs/editor/common/modes'; +import { LocationLink, DefinitionProviderRegistry, ImplementationProviderRegistry, TypeDefinitionProviderRegistry, DeclarationProviderRegistry, ProviderResult, ReferenceProviderRegistry } from 'vs/editor/common/modes'; import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry'; -function getDefinitions( +function getLocationLinks( model: ITextModel, position: Position, registry: LanguageFeatureRegistry, @@ -35,30 +35,37 @@ function getDefinitions( export function getDefinitionsAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise { - return getDefinitions(model, position, DefinitionProviderRegistry, (provider, model, position) => { + return getLocationLinks(model, position, DefinitionProviderRegistry, (provider, model, position) => { return provider.provideDefinition(model, position, token); }); } export function getDeclarationsAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise { - return getDefinitions(model, position, DeclarationProviderRegistry, (provider, model, position) => { + return getLocationLinks(model, position, DeclarationProviderRegistry, (provider, model, position) => { return provider.provideDeclaration(model, position, token); }); } export function getImplementationsAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise { - return getDefinitions(model, position, ImplementationProviderRegistry, (provider, model, position) => { + return getLocationLinks(model, position, ImplementationProviderRegistry, (provider, model, position) => { return provider.provideImplementation(model, position, token); }); } export function getTypeDefinitionsAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise { - return getDefinitions(model, position, TypeDefinitionProviderRegistry, (provider, model, position) => { + return getLocationLinks(model, position, TypeDefinitionProviderRegistry, (provider, model, position) => { return provider.provideTypeDefinition(model, position, token); }); } +export function getReferencesAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise { + return getLocationLinks(model, position, ReferenceProviderRegistry, (provider, model, position) => { + return provider.provideReferences(model, position, { includeDeclaration: true }, token); + }); +} + registerDefaultLanguageCommand('_executeDefinitionProvider', (model, position) => getDefinitionsAtPosition(model, position, CancellationToken.None)); registerDefaultLanguageCommand('_executeDeclarationProvider', (model, position) => getDeclarationsAtPosition(model, position, CancellationToken.None)); registerDefaultLanguageCommand('_executeImplementationProvider', (model, position) => getImplementationsAtPosition(model, position, CancellationToken.None)); registerDefaultLanguageCommand('_executeTypeDefinitionProvider', (model, position) => getTypeDefinitionsAtPosition(model, position, CancellationToken.None)); +registerDefaultLanguageCommand('_executeReferenceProvider', (model, position) => getReferencesAtPosition(model, position, CancellationToken.None)); diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionAtPosition.ts similarity index 67% rename from src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts rename to src/vs/editor/contrib/goToDefinition/goToDefinitionAtPosition.ts index 7d0dd7ce4e1..e71fffa24fe 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionAtPosition.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./goToDefinitionMouse'; +import 'vs/css!./media/goToDefinitionAtPosition'; import * as nls from 'vs/nls'; import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -13,7 +13,7 @@ import { IModeService } from 'vs/editor/common/services/modeService'; 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 { ICodeEditor, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { getDefinitionsAtPosition } from './goToDefinition'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -21,21 +21,23 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { EditorState, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; -import { DefinitionAction, DefinitionActionConfig } from './goToDefinitionCommands'; +import { DefinitionAction } from './goToDefinitionCommands'; import { ClickLinkGesture, ClickLinkMouseEvent, ClickLinkKeyboardEvent } from 'vs/editor/contrib/goToDefinition/clickLinkGesture'; import { IWordAtPosition, IModelDeltaDecoration, ITextModel, IFoundBracket } from 'vs/editor/common/model'; import { Position } from 'vs/editor/common/core/position'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorContribution { +export class GotoDefinitionAtPositionEditorContribution implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.gotodefinitionwithmouse'; - static MAX_SOURCE_PREVIEW_LINES = 8; + public static readonly ID = 'editor.contrib.gotodefinitionatposition'; + static readonly MAX_SOURCE_PREVIEW_LINES = 8; private readonly editor: ICodeEditor; private readonly toUnhook = new DisposableStore(); - private decorations: string[] = []; - private currentWordUnderMouse: IWordAtPosition | null = null; + private readonly toUnhookForKeyboard = new DisposableStore(); + private linkDecorations: string[] = []; + private currentWordAtPosition: IWordAtPosition | null = null; private previousPromise: CancelablePromise | null = null; constructor( @@ -49,55 +51,96 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC this.toUnhook.add(linkGesture); this.toUnhook.add(linkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => { - this.startFindDefinition(mouseEvent, withNullAsUndefined(keyboardEvent)); + this.startFindDefinitionFromMouse(mouseEvent, withNullAsUndefined(keyboardEvent)); })); this.toUnhook.add(linkGesture.onExecute((mouseEvent: ClickLinkMouseEvent) => { if (this.isEnabled(mouseEvent)) { - this.gotoDefinition(mouseEvent.target, mouseEvent.hasSideBySideModifier).then(() => { - this.removeDecorations(); + this.gotoDefinition(mouseEvent.target.position!, mouseEvent.hasSideBySideModifier).then(() => { + this.removeLinkDecorations(); }, (error: Error) => { - this.removeDecorations(); + this.removeLinkDecorations(); onUnexpectedError(error); }); } })); this.toUnhook.add(linkGesture.onCancel(() => { - this.removeDecorations(); - this.currentWordUnderMouse = null; + this.removeLinkDecorations(); + this.currentWordAtPosition = null; })); - } - private startFindDefinition(mouseEvent: ClickLinkMouseEvent, withKey?: ClickLinkKeyboardEvent): void { + static get(editor: ICodeEditor): GotoDefinitionAtPositionEditorContribution { + return editor.getContribution(GotoDefinitionAtPositionEditorContribution.ID); + } + + startFindDefinitionFromCursor(position: Position) { + // For issue: https://github.com/microsoft/vscode/issues/46257 + // equivalent to mouse move with meta/ctrl key + + // First find the definition and add decorations + // to the editor to be shown with the content hover widget + return this.startFindDefinition(position).then(() => { + + // Add listeners for editor cursor move and key down events + // Dismiss the "extended" editor decorations when the user hides + // the hover widget. There is no event for the widget itself so these + // serve as a best effort. After removing the link decorations, the hover + // widget is clean and will only show declarations per next request. + this.toUnhookForKeyboard.add(this.editor.onDidChangeCursorPosition(() => { + this.currentWordAtPosition = null; + this.removeLinkDecorations(); + this.toUnhookForKeyboard.clear(); + })); + + this.toUnhookForKeyboard.add(this.editor.onKeyDown((e: IKeyboardEvent) => { + if (e) { + this.currentWordAtPosition = null; + this.removeLinkDecorations(); + this.toUnhookForKeyboard.clear(); + } + })); + }); + } + + private startFindDefinitionFromMouse(mouseEvent: ClickLinkMouseEvent, withKey?: ClickLinkKeyboardEvent): void { // check if we are active and on a content widget - if (mouseEvent.target.type === MouseTargetType.CONTENT_WIDGET && this.decorations.length > 0) { + if (mouseEvent.target.type === MouseTargetType.CONTENT_WIDGET && this.linkDecorations.length > 0) { return; } if (!this.editor.hasModel() || !this.isEnabled(mouseEvent, withKey)) { - this.currentWordUnderMouse = null; - this.removeDecorations(); + this.currentWordAtPosition = null; + this.removeLinkDecorations(); return; } - // Find word at mouse position - const word = mouseEvent.target.position ? this.editor.getModel().getWordAtPosition(mouseEvent.target.position) : null; - if (!word) { - this.currentWordUnderMouse = null; - this.removeDecorations(); - return; - } const position = mouseEvent.target.position!; - // Return early if word at position is still the same - if (this.currentWordUnderMouse && this.currentWordUnderMouse.startColumn === word.startColumn && this.currentWordUnderMouse.endColumn === word.endColumn && this.currentWordUnderMouse.word === word.word) { - return; + this.startFindDefinition(position); + } + + private startFindDefinition(position: Position): Promise { + + // Dispose listeners for updating decorations when using keyboard to show definition hover + this.toUnhookForKeyboard.clear(); + + // Find word at mouse position + const word = position ? this.editor.getModel()?.getWordAtPosition(position) : null; + if (!word) { + this.currentWordAtPosition = null; + this.removeLinkDecorations(); + return Promise.resolve(0); } - this.currentWordUnderMouse = word; + // Return early if word at position is still the same + if (this.currentWordAtPosition && this.currentWordAtPosition.startColumn === word.startColumn && this.currentWordAtPosition.endColumn === word.endColumn && this.currentWordAtPosition.word === word.word) { + return Promise.resolve(0); + } + + this.currentWordAtPosition = word; // Find definition and decorate word if found let state = new EditorState(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection | CodeEditorStateFlag.Scroll); @@ -107,11 +150,11 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC this.previousPromise = null; } - this.previousPromise = createCancelablePromise(token => this.findDefinition(mouseEvent.target, token)); + this.previousPromise = createCancelablePromise(token => this.findDefinition(position, token)); - this.previousPromise.then(results => { + return this.previousPromise.then(results => { if (!results || !results.length || !state.validate(this.editor)) { - this.removeDecorations(); + this.removeLinkDecorations(); return; } @@ -170,7 +213,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC 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) { + if (numberOfLinesInRange >= GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES) { rangeToUse = this.getPreviewRangeBasedOnIndentation(textEditorModel, startLineNumber); } @@ -193,7 +236,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC private getPreviewRangeBasedOnIndentation(textEditorModel: ITextModel, startLineNumber: number) { const startIndent = textEditorModel.getLineFirstNonWhitespaceColumn(startLineNumber); - const maxLineNumber = Math.min(textEditorModel.getLineCount(), startLineNumber + GotoDefinitionWithMouseEditorContribution.MAX_SOURCE_PREVIEW_LINES); + const maxLineNumber = Math.min(textEditorModel.getLineCount(), startLineNumber + GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES); let endLineNumber = startLineNumber + 1; for (; endLineNumber < maxLineNumber; endLineNumber++) { @@ -208,7 +251,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC } private getPreviewRangeBasedOnBrackets(textEditorModel: ITextModel, startLineNumber: number) { - const maxLineNumber = Math.min(textEditorModel.getLineCount(), startLineNumber + GotoDefinitionWithMouseEditorContribution.MAX_SOURCE_PREVIEW_LINES); + const maxLineNumber = Math.min(textEditorModel.getLineCount(), startLineNumber + GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES); const brackets: IFoundBracket[] = []; @@ -220,7 +263,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC brackets.push(currentBracket); } else { const lastBracket = brackets[brackets.length - 1]; - if (lastBracket.open === currentBracket.open && lastBracket.isOpen && !currentBracket.isOpen) { + if (lastBracket.open[0] === currentBracket.open[0] && lastBracket.isOpen && !currentBracket.isOpen) { brackets.pop(); } else { brackets.push(currentBracket); @@ -263,12 +306,12 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC } }; - this.decorations = this.editor.deltaDecorations(this.decorations, [newDecorations]); + this.linkDecorations = this.editor.deltaDecorations(this.linkDecorations, [newDecorations]); } - private removeDecorations(): void { - if (this.decorations.length > 0) { - this.decorations = this.editor.deltaDecorations(this.decorations, []); + private removeLinkDecorations(): void { + if (this.linkDecorations.length > 0) { + this.linkDecorations = this.editor.deltaDecorations(this.linkDecorations, []); } } @@ -280,31 +323,27 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC DefinitionProviderRegistry.has(this.editor.getModel()); } - private findDefinition(target: IMouseTarget, token: CancellationToken): Promise { + private findDefinition(position: Position, token: CancellationToken): Promise { const model = this.editor.getModel(); if (!model) { return Promise.resolve(null); } - return getDefinitionsAtPosition(model, target.position!, token); + return getDefinitionsAtPosition(model, position, token); } - 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: undefined }); + private gotoDefinition(position: Position, openToSide: boolean): Promise { + this.editor.setPosition(position); + const action = new DefinitionAction({ openToSide, openInPeek: false, muteMessage: true }, { alias: '', label: '', id: '', precondition: undefined }); return this.editor.invokeWithinContext(accessor => action.run(accessor, this.editor)); } - public getId(): string { - return GotoDefinitionWithMouseEditorContribution.ID; - } - public dispose(): void { this.toUnhook.dispose(); } } -registerEditorContribution(GotoDefinitionWithMouseEditorContribution); +registerEditorContribution(GotoDefinitionAtPositionEditorContribution.ID, GotoDefinitionAtPositionEditorContribution); registerThemingParticipant((theme, collector) => { const activeLinkForeground = theme.getColor(editorActiveLinkForeground); diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts index 1844a9f3456..fdbe3580fea 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts @@ -7,7 +7,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; 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'; +import { isWeb } from 'vs/base/common/platform'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, IActionOptions, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; @@ -21,39 +21,34 @@ import { PeekContext } from 'vs/editor/contrib/referenceSearch/peekViewWidget'; import { ReferencesController } from 'vs/editor/contrib/referenceSearch/referencesController'; import { ReferencesModel } from 'vs/editor/contrib/referenceSearch/referencesModel'; import * as nls from 'vs/nls'; -import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { MenuId } 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 { IEditorProgressService } from 'vs/platform/progress/common/progress'; -import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition } from './goToDefinition'; +import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition, getReferencesAtPosition } 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'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { isStandalone } from 'vs/base/browser/browser'; -export class DefinitionActionConfig { - - constructor( - public readonly openToSide = false, - public readonly openInPeek = false, - public readonly filterCurrent = true, - public readonly showMessage = true, - ) { - // - } +export interface SymbolNavigationActionConfig { + openToSide: boolean;// = false + openInPeek: boolean;// = false + muteMessage: boolean;// = true } -export class DefinitionAction extends EditorAction { +abstract class SymbolNavigationAction extends EditorAction { - private readonly _configuration: DefinitionActionConfig; + private readonly _configuration: SymbolNavigationActionConfig; - constructor(configuration: DefinitionActionConfig, opts: IActionOptions) { + constructor(configuration: SymbolNavigationActionConfig, opts: IActionOptions) { super(opts); this._configuration = configuration; } - public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { + run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { if (!editor.hasModel()) { return Promise.resolve(undefined); } @@ -67,45 +62,28 @@ export class DefinitionAction extends EditorAction { const cts = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position); - const definitionPromise = raceCancellation(this._getTargetLocationForPosition(model, pos, cts.token), cts.token).then(async references => { + const promise = raceCancellation(this._getLocationModel(model, pos, cts.token), cts.token).then(async references => { - if (!references || model.isDisposed()) { - // new model, no more model + if (!references || cts.token.isCancellationRequested) { return; } - // * remove falsy references - // * find reference at the current pos - let idxOfCurrent = -1; - const result: LocationLink[] = []; - for (const reference of references) { - if (!reference || !reference.range) { - continue; - } - const newLen = result.push(reference); - if (this._configuration.filterCurrent - && reference.uri.toString() === model.uri.toString() - && Range.containsPosition(reference.range, pos) - && idxOfCurrent === -1 - ) { - idxOfCurrent = newLen - 1; - } - } + const referenceUnderCusor = references.referenceAt(model.uri, pos); + const referenceCount = references.references.length; - if (result.length === 0) { + if (referenceCount === 0) { // no result -> show message - if (this._configuration.showMessage) { + if (!this._configuration.muteMessage) { const info = model.getWordAtPosition(pos); MessageController.get(editor).showMessage(this._getNoResultFoundMessage(info), pos); } - } else if (result.length === 1 && idxOfCurrent !== -1) { + } else if (referenceCount === 1 && referenceUnderCusor) { // only the position at which we are -> adjust selection - let [current] = result; - return this._openReference(editor, editorService, current, false).then(() => undefined); + return this._openReference(editor, editorService, referenceUnderCusor, false).then(() => undefined); } else { // handle multile results - return this._onResult(editorService, symbolNavService, editor, new ReferencesModel(result)); + return this._onResult(editorService, symbolNavService, editor, references); } }, (err) => { @@ -115,23 +93,15 @@ export class DefinitionAction extends EditorAction { cts.dispose(); }); - progressService.showWhile(definitionPromise, 250); - return definitionPromise; + progressService.showWhile(promise, 250); + return promise; } - protected _getTargetLocationForPosition(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return getDefinitionsAtPosition(model, position, token); - } + protected abstract _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise; - protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { - return info && info.word - ? nls.localize('noResultWord', "No definition found for '{0}'", info.word) - : nls.localize('generic.noResults', "No definition found"); - } + protected abstract _getNoResultFoundMessage(info: IWordAtPosition | null): string; - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('meta.title', " – {0} definitions", model.references.length) : ''; - } + protected abstract _getMetaTitle(model: ReferencesModel): string; private async _onResult(editorService: ICodeEditorService, symbolNavService: ISymbolNavigationService, editor: ICodeEditor, model: ReferencesModel): Promise { @@ -162,7 +132,7 @@ export class DefinitionAction extends EditorAction { } } - private _openReference(editor: ICodeEditor, editorService: ICodeEditorService, reference: Location | LocationLink, sideBySide: boolean): Promise { + private _openReference(editor: ICodeEditor, editorService: ICodeEditorService, reference: Location | LocationLink, sideBySide: boolean): Promise { // range is the target-selection-range when we have one // and the the fallback is the 'full' range let range: IRange | undefined = undefined; @@ -200,16 +170,39 @@ export class DefinitionAction extends EditorAction { } } -const goToDefinitionKb = platform.isWeb +//#region --- DEFINITION + +export class DefinitionAction extends SymbolNavigationAction { + + protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { + return new ReferencesModel(await getDefinitionsAtPosition(model, position, token)); + } + + protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { + return info && info.word + ? nls.localize('noResultWord', "No definition found for '{0}'", info.word) + : nls.localize('generic.noResults', "No definition found"); + } + + protected _getMetaTitle(model: ReferencesModel): string { + return model.references.length > 1 ? nls.localize('meta.title', " – {0} definitions", model.references.length) : ''; + } +} + +const goToDefinitionKb = isWeb && !isStandalone ? KeyMod.CtrlCmd | KeyCode.F12 : KeyCode.F12; -export class GoToDefinitionAction extends DefinitionAction { +registerEditorAction(class GoToDefinitionAction extends DefinitionAction { static readonly id = 'editor.action.revealDefinition'; constructor() { - super(new DefinitionActionConfig(), { + super({ + openToSide: false, + openInPeek: false, + muteMessage: false + }, { id: GoToDefinitionAction.id, label: nls.localize('actions.goToDecl.label', "Go to Definition"), alias: 'Go to Definition', @@ -224,18 +217,28 @@ export class GoToDefinitionAction extends DefinitionAction { menuOpts: { group: 'navigation', order: 1.1 + }, + menubarOpts: { + menuId: MenuId.MenubarGoMenu, + group: '4_symbol_nav', + order: 2, + title: nls.localize({ key: 'miGotoDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Definition") } }); CommandsRegistry.registerCommandAlias('editor.action.goToDeclaration', GoToDefinitionAction.id); } -} +}); -export class OpenDefinitionToSideAction extends DefinitionAction { +registerEditorAction(class OpenDefinitionToSideAction extends DefinitionAction { static readonly id = 'editor.action.revealDefinitionAside'; constructor() { - super(new DefinitionActionConfig(true), { + super({ + openToSide: true, + openInPeek: false, + muteMessage: false + }, { id: OpenDefinitionToSideAction.id, label: nls.localize('actions.goToDeclToSide.label', "Open Definition to the Side"), alias: 'Open Definition to the Side', @@ -250,14 +253,18 @@ export class OpenDefinitionToSideAction extends DefinitionAction { }); CommandsRegistry.registerCommandAlias('editor.action.openDeclarationToTheSide', OpenDefinitionToSideAction.id); } -} +}); -export class PeekDefinitionAction extends DefinitionAction { +registerEditorAction(class PeekDefinitionAction extends DefinitionAction { static readonly id = 'editor.action.peekDefinition'; constructor() { - super(new DefinitionActionConfig(undefined, true, false), { + super({ + openToSide: false, + openInPeek: true, + muteMessage: false + }, { id: PeekDefinitionAction.id, label: nls.localize('actions.previewDecl.label', "Peek Definition"), alias: 'Peek Definition', @@ -278,12 +285,16 @@ export class PeekDefinitionAction extends DefinitionAction { }); CommandsRegistry.registerCommandAlias('editor.action.previewDeclaration', PeekDefinitionAction.id); } -} +}); -export class DeclarationAction extends DefinitionAction { +//#endregion - protected _getTargetLocationForPosition(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return getDeclarationsAtPosition(model, position, token); +//#region --- DECLARATION + +class DeclarationAction extends SymbolNavigationAction { + + protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { + return new ReferencesModel(await getDeclarationsAtPosition(model, position, token)); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -297,12 +308,16 @@ export class DeclarationAction extends DefinitionAction { } } -export class GoToDeclarationAction extends DeclarationAction { +registerEditorAction(class GoToDeclarationAction extends DeclarationAction { static readonly id = 'editor.action.revealDeclaration'; constructor() { - super(new DefinitionActionConfig(), { + super({ + openToSide: false, + openInPeek: false, + muteMessage: false + }, { id: GoToDeclarationAction.id, label: nls.localize('actions.goToDeclaration.label', "Go to Declaration"), alias: 'Go to Declaration', @@ -325,11 +340,15 @@ export class GoToDeclarationAction extends DeclarationAction { protected _getMetaTitle(model: ReferencesModel): string { return model.references.length > 1 ? nls.localize('decl.meta.title', " – {0} declarations", model.references.length) : ''; } -} +}); -export class PeekDeclarationAction extends DeclarationAction { +registerEditorAction(class PeekDeclarationAction extends DeclarationAction { constructor() { - super(new DefinitionActionConfig(undefined, true, false), { + super({ + openToSide: false, + openInPeek: true, + muteMessage: false + }, { id: 'editor.action.peekDeclaration', label: nls.localize('actions.peekDecl.label', "Peek Declaration"), alias: 'Peek Declaration', @@ -343,11 +362,16 @@ export class PeekDeclarationAction extends DeclarationAction { } }); } -} +}); -export class ImplementationAction extends DefinitionAction { - protected _getTargetLocationForPosition(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return getImplementationsAtPosition(model, position, token); +//#endregion + +//#region --- IMPLEMENTATION + +class ImplementationAction extends SymbolNavigationAction { + + protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { + return new ReferencesModel(await getImplementationsAtPosition(model, position, token)); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -361,12 +385,16 @@ export class ImplementationAction extends DefinitionAction { } } -export class GoToImplementationAction extends ImplementationAction { +registerEditorAction(class GoToImplementationAction extends ImplementationAction { public static readonly ID = 'editor.action.goToImplementation'; constructor() { - super(new DefinitionActionConfig(), { + super({ + openToSide: false, + openInPeek: false, + muteMessage: false + }, { id: GoToImplementationAction.ID, label: nls.localize('actions.goToImplementation.label', "Go to Implementation"), alias: 'Go to Implementation', @@ -377,17 +405,26 @@ export class GoToImplementationAction extends ImplementationAction { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyCode.F12, weight: KeybindingWeight.EditorContrib + }, + menubarOpts: { + menuId: MenuId.MenubarGoMenu, + group: '4_symbol_nav', + order: 4, title: nls.localize({ key: 'miGotoImplementation', comment: ['&& denotes a mnemonic'] }, "Go to &&Implementation") } }); } -} +}); -export class PeekImplementationAction extends ImplementationAction { +registerEditorAction(class PeekImplementationAction extends ImplementationAction { public static readonly ID = 'editor.action.peekImplementation'; constructor() { - super(new DefinitionActionConfig(false, true, false), { + super({ + openToSide: false, + openInPeek: true, + muteMessage: false + }, { id: PeekImplementationAction.ID, label: nls.localize('actions.peekImplementation.label', "Peek Implementation"), alias: 'Peek Implementation', @@ -401,11 +438,16 @@ export class PeekImplementationAction extends ImplementationAction { } }); } -} +}); -export class TypeDefinitionAction extends DefinitionAction { - protected _getTargetLocationForPosition(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return getTypeDefinitionsAtPosition(model, position, token); +//#endregion + +//#region --- TYPE DEFINITION + +class TypeDefinitionAction extends SymbolNavigationAction { + + protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { + return new ReferencesModel(await getTypeDefinitionsAtPosition(model, position, token)); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -419,12 +461,16 @@ export class TypeDefinitionAction extends DefinitionAction { } } -export class GoToTypeDefinitionAction extends TypeDefinitionAction { +registerEditorAction(class GoToTypeDefinitionAction extends TypeDefinitionAction { public static readonly ID = 'editor.action.goToTypeDefinition'; constructor() { - super(new DefinitionActionConfig(), { + super({ + openToSide: false, + openInPeek: false, + muteMessage: false + }, { id: GoToTypeDefinitionAction.ID, label: nls.localize('actions.goToTypeDefinition.label', "Go to Type Definition"), alias: 'Go to Type Definition', @@ -439,17 +485,27 @@ export class GoToTypeDefinitionAction extends TypeDefinitionAction { menuOpts: { group: 'navigation', order: 1.4 + }, + menubarOpts: { + menuId: MenuId.MenubarGoMenu, + group: '4_symbol_nav', + order: 3, + title: nls.localize({ key: 'miGotoTypeDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Type Definition") } }); } -} +}); -export class PeekTypeDefinitionAction extends TypeDefinitionAction { +registerEditorAction(class PeekTypeDefinitionAction extends TypeDefinitionAction { public static readonly ID = 'editor.action.peekTypeDefinition'; constructor() { - super(new DefinitionActionConfig(false, true, false), { + super({ + openToSide: false, + openInPeek: true, + muteMessage: false + }, { id: PeekTypeDefinitionAction.ID, label: nls.localize('actions.peekTypeDefinition.label', "Peek Type Definition"), alias: 'Peek Type Definition', @@ -463,42 +519,78 @@ export class PeekTypeDefinitionAction extends TypeDefinitionAction { } }); } +}); + +//#endregion + +//#region --- REFERENCES + +class ReferencesAction extends SymbolNavigationAction { + + protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { + return new ReferencesModel(await getReferencesAtPosition(model, position, token)); + } + + protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { + return info + ? nls.localize('references.no', "No references found for '{0}'", info.word) + : nls.localize('references.noGeneric', "No references found"); + } + + protected _getMetaTitle(model: ReferencesModel): string { + return model.references.length > 1 + ? nls.localize('meta.titleReference', " – {0} references", model.references.length) + : ''; + } } -registerEditorAction(GoToDefinitionAction); -registerEditorAction(OpenDefinitionToSideAction); -registerEditorAction(PeekDefinitionAction); -registerEditorAction(GoToDeclarationAction); -registerEditorAction(PeekDeclarationAction); -registerEditorAction(GoToImplementationAction); -registerEditorAction(PeekImplementationAction); -registerEditorAction(GoToTypeDefinitionAction); -registerEditorAction(PeekTypeDefinitionAction); +registerEditorAction(class GoToReferencesAction extends ReferencesAction { -// Go to menu -MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { - group: '4_symbol_nav', - command: { - id: 'editor.action.goToDeclaration', - title: nls.localize({ key: 'miGotoDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Definition") - }, - order: 2 + constructor() { + super({ + openToSide: false, + openInPeek: false, + muteMessage: false + }, { + id: 'editor.action.goToReferences', + label: nls.localize('goToReferences.label', "Go To References"), + alias: 'Go To References', + precondition: ContextKeyExpr.and( + EditorContextKeys.hasReferenceProvider, + PeekContext.notInPeekEditor, + EditorContextKeys.isInEmbeddedEditor.toNegated() + ) + }); + } }); -MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { - group: '4_symbol_nav', - command: { - id: 'editor.action.goToTypeDefinition', - title: nls.localize({ key: 'miGotoTypeDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Type Definition") - }, - order: 3 +registerEditorAction(class PeekReferencesAction extends ReferencesAction { + + constructor() { + super({ + openToSide: false, + openInPeek: true, + muteMessage: false + }, { + id: 'editor.action.referenceSearch.trigger', + label: nls.localize('references.action.label', "Peek References"), + alias: 'Peek References', + precondition: ContextKeyExpr.and( + EditorContextKeys.hasReferenceProvider, + PeekContext.notInPeekEditor, + EditorContextKeys.isInEmbeddedEditor.toNegated() + ), + kbOpts: { + kbExpr: EditorContextKeys.editorTextFocus, + primary: KeyMod.Shift | KeyCode.F12, + weight: KeybindingWeight.EditorContrib + }, + menuOpts: { + group: 'navigation', + order: 1.5 + } + }); + } }); -MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { - group: '4_symbol_nav', - command: { - id: 'editor.action.goToImplementation', - title: nls.localize({ key: 'miGotoImplementation', comment: ['&& denotes a mnemonic'] }, "Go to &&Implementation") - }, - order: 4 -}); +//#endregion diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts index e52bc043383..bbf2cddd212 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts @@ -18,6 +18,7 @@ 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'; +import { isEqual } from 'vs/base/common/resources'; export const ctxHasSymbols = new RawContextKey('hasSymbols', false); @@ -92,7 +93,7 @@ class SymbolNavigationService implements ISymbolNavigationService { let seenUri: boolean = false; let seenPosition: boolean = false; for (const reference of refModel.references) { - if (reference.uri.toString() === model.uri.toString()) { + if (isEqual(reference.uri, model.uri)) { seenUri = true; seenPosition = seenPosition || Range.containsPosition(reference.range, position); } else if (seenUri) { diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.css b/src/vs/editor/contrib/goToDefinition/media/goToDefinitionAtPosition.css similarity index 100% rename from src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.css rename to src/vs/editor/contrib/goToDefinition/media/goToDefinitionAtPosition.css diff --git a/src/vs/editor/contrib/gotoError/gotoError.ts b/src/vs/editor/contrib/gotoError/gotoError.ts index c16b9be9a6e..8e9a86d65a0 100644 --- a/src/vs/editor/contrib/gotoError/gotoError.ts +++ b/src/vs/editor/contrib/gotoError/gotoError.ts @@ -20,12 +20,13 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { MarkerNavigationWidget } from './gotoErrorWidget'; import { compare } from 'vs/base/common/strings'; -import { binarySearch } from 'vs/base/common/arrays'; +import { binarySearch, find } from 'vs/base/common/arrays'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { onUnexpectedError } from 'vs/base/common/errors'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { Action } from 'vs/base/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { isEqual } from 'vs/base/common/resources'; class MarkerModel { @@ -172,12 +173,7 @@ class MarkerModel { } public findMarkerAtPosition(pos: Position): IMarker | undefined { - for (const marker of this._markers) { - if (Range.containsPosition(marker, pos)) { - return marker; - } - } - return undefined; + return find(this._markers, marker => Range.containsPosition(marker, pos)); } public get total() { @@ -195,7 +191,7 @@ class MarkerModel { export class MarkerController implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.markerController'; + public static readonly ID = 'editor.contrib.markerController'; public static get(editor: ICodeEditor): MarkerController { return editor.getContribution(MarkerController.ID); @@ -219,10 +215,6 @@ export class MarkerController implements editorCommon.IEditorContribution { this._widgetVisible = CONTEXT_MARKERS_NAVIGATION_VISIBLE.bindTo(this._contextKeyService); } - public getId(): string { - return MarkerController.ID; - } - public dispose(): void { this._cleanUp(); this._disposeOnClose.dispose(); @@ -248,8 +240,8 @@ export class MarkerController implements editorCommon.IEditorContribution { const prevMarkerKeybinding = this._keybindingService.lookupKeybinding(PrevMarkerAction.ID); const nextMarkerKeybinding = this._keybindingService.lookupKeybinding(NextMarkerAction.ID); const actions = [ - new Action(PrevMarkerAction.ID, PrevMarkerAction.LABEL + (prevMarkerKeybinding ? ` (${prevMarkerKeybinding.getLabel()})` : ''), 'show-previous-problem chevron-up', this._model.canNavigate(), async () => { if (this._model) { this._model.move(false, true); } }), - new Action(NextMarkerAction.ID, NextMarkerAction.LABEL + (nextMarkerKeybinding ? ` (${nextMarkerKeybinding.getLabel()})` : ''), 'show-next-problem chevron-down', this._model.canNavigate(), async () => { if (this._model) { this._model.move(true, true); } }) + new Action(PrevMarkerAction.ID, PrevMarkerAction.LABEL + (prevMarkerKeybinding ? ` (${prevMarkerKeybinding.getLabel()})` : ''), 'show-previous-problem codicon-chevron-up', this._model.canNavigate(), async () => { if (this._model) { this._model.move(false, true); } }), + new Action(NextMarkerAction.ID, NextMarkerAction.LABEL + (nextMarkerKeybinding ? ` (${nextMarkerKeybinding.getLabel()})` : ''), 'show-next-problem codicon-chevron-down', this._model.canNavigate(), async () => { if (this._model) { this._model.move(true, true); } }) ]; this._widget = new MarkerNavigationWidget(this._editor, actions, this._themeService); this._widgetVisible.set(true); @@ -310,7 +302,7 @@ export class MarkerController implements editorCommon.IEditorContribution { } private _onMarkerChanged(changedResources: URI[]): void { - let editorModel = this._editor.getModel(); + const editorModel = this._editor.getModel(); if (!editorModel) { return; } @@ -319,7 +311,7 @@ export class MarkerController implements editorCommon.IEditorContribution { return; } - if (!changedResources.some(r => editorModel!.uri.toString() === r.toString())) { + if (!changedResources.some(r => isEqual(editorModel.uri, r))) { return; } this._model.setMarkers(this._getMarkers()); @@ -371,7 +363,7 @@ class MarkerNavigationAction extends EditorAction { return Promise.resolve(undefined); } - let editorModel = editor.getModel(); + const editorModel = editor.getModel(); if (!editorModel) { return Promise.resolve(undefined); } @@ -389,7 +381,7 @@ class MarkerNavigationAction extends EditorAction { } let newMarker = markers[idx]; - if (newMarker.resource.toString() === editorModel!.uri.toString()) { + if (isEqual(newMarker.resource, editorModel.uri)) { // the next `resource` is this resource which // means we cycle within this file model.move(this._isNext, true); @@ -483,7 +475,7 @@ class PrevMarkerInFilesAction extends MarkerNavigationAction { } } -registerEditorContribution(MarkerController); +registerEditorContribution(MarkerController.ID, MarkerController); registerEditorAction(NextMarkerAction); registerEditorAction(PrevMarkerAction); registerEditorAction(NextMarkerInFilesAction); @@ -522,4 +514,4 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { title: nls.localize({ key: 'miGotoPreviousProblem', comment: ['&& denotes a mnemonic'] }, "Previous &&Problem") }, order: 2 -}); \ No newline at end of file +}); diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts index 3c94a3b561a..a8aa26cb3a9 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts @@ -283,7 +283,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { : nls.localize('change', "{0} of {1} problem", markerIdx, markerCount); this.setTitle(basename(model.uri), detail); } - this._icon.className = SeverityIcon.className(MarkerSeverity.toSeverity(this._severity)); + this._icon.className = `codicon ${SeverityIcon.className(MarkerSeverity.toSeverity(this._severity))}`; this.editor.revealPositionInCenter(position, ScrollType.Smooth); } diff --git a/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css b/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css index 6680fb166cd..ee02594a087 100644 --- a/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css +++ b/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css @@ -29,8 +29,9 @@ .monaco-editor .marker-widget .descriptioncontainer { position: absolute; white-space: pre; - -webkit-user-select: text; user-select: text; + -webkit-user-select: text; + -ms-user-select: text; padding: 8px 12px 0px 20px; } diff --git a/src/vs/editor/contrib/hover/hover.css b/src/vs/editor/contrib/hover/hover.css index 8190705b9a5..3e34dec5e19 100644 --- a/src/vs/editor/contrib/hover/hover.css +++ b/src/vs/editor/contrib/hover/hover.css @@ -8,12 +8,9 @@ position: absolute; overflow: hidden; z-index: 50; + user-select: text; -webkit-user-select: text; -ms-user-select: text; - -khtml-user-select: text; - -moz-user-select: text; - -o-user-select: text; - user-select: text; box-sizing: initial; animation: fadein 100ms linear; line-height: 1.5em; @@ -37,7 +34,7 @@ margin: 8px 0; } -.monaco-editor-hover p > code { +.monaco-editor-hover code { font-family: var(--monaco-monospace-font); } diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index 215ddd5844c..f39db5bbe41 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, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore, MutableDisposable } 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'; @@ -21,34 +21,35 @@ import { ModesContentHoverWidget } from 'vs/editor/contrib/hover/modesContentHov import { ModesGlyphHoverWidget } from 'vs/editor/contrib/hover/modesGlyphHover'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverStatusBarBackground } from 'vs/platform/theme/common/colorRegistry'; +import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverStatusBarBackground, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; 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 { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/goToDefinition/goToDefinitionAtPosition'; export class ModesHoverController implements IEditorContribution { - private static readonly ID = 'editor.contrib.hover'; + public static readonly ID = 'editor.contrib.hover'; private readonly _toUnhook = new DisposableStore(); private readonly _didChangeConfigurationHandler: IDisposable; - private _contentWidget: ModesContentHoverWidget | null; - private _glyphWidget: ModesGlyphHoverWidget | null; + private readonly _contentWidget = new MutableDisposable(); + private readonly _glyphWidget = new MutableDisposable(); get contentWidget(): ModesContentHoverWidget { - if (!this._contentWidget) { + if (!this._contentWidget.value) { this._createHoverWidgets(); } - return this._contentWidget!; + return this._contentWidget.value!; } get glyphWidget(): ModesGlyphHoverWidget { - if (!this._glyphWidget) { + if (!this._glyphWidget.value) { this._createHoverWidgets(); } - return this._glyphWidget!; + return this._glyphWidget.value!; } private _isMouseDown: boolean; @@ -69,8 +70,6 @@ export class ModesHoverController implements IEditorContribution { ) { this._isMouseDown = false; this._hoverClicked = false; - this._contentWidget = null; - this._glyphWidget = null; this._hookEvents(); @@ -197,38 +196,29 @@ export class ModesHoverController implements IEditorContribution { } private _hideWidgets(): void { - if (!this._glyphWidget || !this._contentWidget || (this._isMouseDown && this._hoverClicked && this._contentWidget.isColorPickerVisible())) { + if (!this._glyphWidget.value || !this._contentWidget.value || (this._isMouseDown && this._hoverClicked && this._contentWidget.value.isColorPickerVisible())) { return; } - this._glyphWidget!.hide(); - this._contentWidget.hide(); + this._glyphWidget.value.hide(); + this._contentWidget.value.hide(); } private _createHoverWidgets() { - 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); + this._contentWidget.value = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._themeService, this._keybindingService, this._modeService, this._openerService); + this._glyphWidget.value = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService); } public showContentHover(range: Range, mode: HoverStartMode, focus: boolean): void { this.contentWidget.startShowingAt(range, mode, focus); } - public getId(): string { - return ModesHoverController.ID; - } - public dispose(): void { this._unhookEvents(); this._toUnhook.dispose(); this._didChangeConfigurationHandler.dispose(); - - if (this._glyphWidget) { - this._glyphWidget.dispose(); - } - if (this._contentWidget) { - this._contentWidget.dispose(); - } + this._glyphWidget.dispose(); + this._contentWidget.dispose(); } } @@ -269,8 +259,50 @@ class ShowHoverAction extends EditorAction { } } -registerEditorContribution(ModesHoverController); +class ShowDefinitionPreviewHoverAction extends EditorAction { + + constructor() { + super({ + id: 'editor.action.showDefinitionPreviewHover', + label: nls.localize({ + key: 'showDefinitionPreviewHover', + comment: [ + 'Label for action that will trigger the showing of definition preview hover in the editor.', + 'This allows for users to show the definition preview hover without using the mouse.' + ] + }, "Show Definition Preview Hover"), + alias: 'Show Definition Preview Hover', + precondition: undefined + }); + } + + public run(accessor: ServicesAccessor, editor: ICodeEditor): void { + let controller = ModesHoverController.get(editor); + if (!controller) { + return; + } + const position = editor.getPosition(); + + if (!position) { + return; + } + + const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column); + const goto = GotoDefinitionAtPositionEditorContribution.get(editor); + const promise = goto.startFindDefinitionFromCursor(position); + if (promise) { + promise.then(() => { + controller.showContentHover(range, HoverStartMode.Immediate, true); + }); + } else { + controller.showContentHover(range, HoverStartMode.Immediate, true); + } + } +} + +registerEditorContribution(ModesHoverController.ID, ModesHoverController); registerEditorAction(ShowHoverAction); +registerEditorAction(ShowDefinitionPreviewHoverAction); // theming registerThemingParticipant((theme, collector) => { @@ -293,6 +325,10 @@ registerThemingParticipant((theme, collector) => { if (link) { collector.addRule(`.monaco-editor .monaco-editor-hover a { color: ${link}; }`); } + const hoverForeground = theme.getColor(editorHoverForeground); + if (hoverForeground) { + collector.addRule(`.monaco-editor .monaco-editor-hover { color: ${hoverForeground}; }`); + } const actionsBackground = theme.getColor(editorHoverStatusBarBackground); if (actionsBackground) { collector.addRule(`.monaco-editor .monaco-editor-hover .hover-row .actions { background-color: ${actionsBackground}; }`); diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index 06877b671d5..485175ffa7a 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -38,6 +38,7 @@ import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { Constants } from 'vs/base/common/uint'; const $ = dom.$; @@ -333,7 +334,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { this._colorPicker = null; // update column from which to show - let renderColumn = Number.MAX_VALUE; + let renderColumn = Constants.MAX_SAFE_SMALL_INTEGER; let highlightRange: Range | null = messages[0].range ? Range.lift(messages[0].range) : null; let fragment = document.createDocumentFragment(); let isEmptyHoverContent = true; @@ -353,7 +354,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { containColorPicker = true; const { red, green, blue, alpha } = msg.color; - const rgba = new RGBA(red * 255, green * 255, blue * 255, alpha); + const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha); const color = new Color(rgba); if (!this._editor.hasModel()) { @@ -505,7 +506,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { e.stopPropagation(); e.preventDefault(); if (this._openerService) { - this._openerService.open(resource.with({ fragment: `${startLineNumber},${startColumn}` })).catch(onUnexpectedError); + this._openerService.open(resource.with({ fragment: `${startLineNumber},${startColumn}` }), { fromUserGesture: true }).catch(onUnexpectedError); } }; const messageElement = dom.append(relatedInfoContainer, $('span')); diff --git a/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts b/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts index fce6fc23383..70f9fbf73cc 100644 --- a/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts +++ b/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts @@ -24,7 +24,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis class InPlaceReplaceController implements IEditorContribution { - private static readonly ID = 'editor.contrib.inPlaceReplaceController'; + public static readonly ID = 'editor.contrib.inPlaceReplaceController'; static get(editor: ICodeEditor): InPlaceReplaceController { return editor.getContribution(InPlaceReplaceController.ID); @@ -51,10 +51,6 @@ class InPlaceReplaceController implements IEditorContribution { public dispose(): void { } - public getId(): string { - return InPlaceReplaceController.ID; - } - public run(source: string, up: boolean): Promise | undefined { // cancel any pending request @@ -183,7 +179,7 @@ class InPlaceReplaceDown extends EditorAction { } } -registerEditorContribution(InPlaceReplaceController); +registerEditorContribution(InPlaceReplaceController.ID, InPlaceReplaceController); registerEditorAction(InPlaceReplaceUp); registerEditorAction(InPlaceReplaceDown); diff --git a/src/vs/editor/contrib/indentation/indentation.ts b/src/vs/editor/contrib/indentation/indentation.ts index 1295fe114fe..bbddafa5346 100644 --- a/src/vs/editor/contrib/indentation/indentation.ts +++ b/src/vs/editor/contrib/indentation/indentation.ts @@ -422,7 +422,7 @@ export class AutoIndentOnPasteCommand implements ICommand { } export class AutoIndentOnPaste implements IEditorContribution { - private static readonly ID = 'editor.contrib.autoIndentOnPaste'; + public static readonly ID = 'editor.contrib.autoIndentOnPaste'; private readonly editor: ICodeEditor; private readonly callOnDispose = new DisposableStore(); @@ -604,10 +604,6 @@ export class AutoIndentOnPaste implements IEditorContribution { return false; } - public getId(): string { - return AutoIndentOnPaste.ID; - } - public dispose(): void { this.callOnDispose.dispose(); this.callOnModel.dispose(); @@ -681,7 +677,7 @@ export class IndentationToTabsCommand implements ICommand { } } -registerEditorContribution(AutoIndentOnPaste); +registerEditorContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste); registerEditorAction(IndentationToSpacesAction); registerEditorAction(IndentationToTabsAction); registerEditorAction(IndentUsingTabs); diff --git a/src/vs/editor/contrib/linesOperations/linesOperations.ts b/src/vs/editor/contrib/linesOperations/linesOperations.ts index 7f1d517236a..b615da8257b 100644 --- a/src/vs/editor/contrib/linesOperations/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/linesOperations.ts @@ -8,7 +8,7 @@ import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands'; import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, IActionOptions, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; -import { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand'; +import { ReplaceCommand, ReplaceCommandThatPreservesSelection, ReplaceCommandThatSelectsText } from 'vs/editor/common/commands/replaceCommand'; import { TrimTrailingWhitespaceCommand } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand'; import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; import { EditOperation } from 'vs/editor/common/core/editOperation'; @@ -97,6 +97,47 @@ class CopyLinesDownAction extends AbstractCopyLinesAction { } } +export class DuplicateSelectionAction extends EditorAction { + + constructor() { + super({ + id: 'editor.action.duplicateSelection', + label: nls.localize('duplicateSelection', "Duplicate Selection"), + alias: 'Duplicate Selection', + precondition: EditorContextKeys.writable, + menubarOpts: { + menuId: MenuId.MenubarSelectionMenu, + group: '2_line', + title: nls.localize({ key: 'miDuplicateSelection', comment: ['&& denotes a mnemonic'] }, "&&Duplicate Selection"), + order: 5 + } + }); + } + + public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { + if (!editor.hasModel()) { + return; + } + + const commands: ICommand[] = []; + const selections = editor.getSelections(); + const model = editor.getModel(); + + for (const selection of selections) { + if (selection.isEmpty()) { + commands.push(new CopyLinesCommand(selection, true)); + } else { + const insertSelection = new Selection(selection.endLineNumber, selection.endColumn, selection.endLineNumber, selection.endColumn); + commands.push(new ReplaceCommandThatSelectsText(insertSelection, model.getValueInRange(selection))); + } + } + + editor.pushUndoStop(); + editor.executeCommands(this.id, commands); + editor.pushUndoStop(); + } +} + // move lines abstract class AbstractMoveLinesAction extends EditorAction { @@ -989,6 +1030,7 @@ export class TitleCaseAction extends AbstractCaseAction { registerEditorAction(CopyLinesUpAction); registerEditorAction(CopyLinesDownAction); +registerEditorAction(DuplicateSelectionAction); registerEditorAction(MoveLinesUpAction); registerEditorAction(MoveLinesDownAction); registerEditorAction(SortLinesAscendingAction); diff --git a/src/vs/editor/contrib/linesOperations/sortLinesCommand.ts b/src/vs/editor/contrib/linesOperations/sortLinesCommand.ts index 6c52081947c..a201370cea3 100644 --- a/src/vs/editor/contrib/linesOperations/sortLinesCommand.ts +++ b/src/vs/editor/contrib/linesOperations/sortLinesCommand.ts @@ -11,6 +11,14 @@ import { IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/mod export class SortLinesCommand implements editorCommon.ICommand { + private static _COLLATOR: Intl.Collator | null = null; + public static getCollator(): Intl.Collator { + if (!SortLinesCommand._COLLATOR) { + SortLinesCommand._COLLATOR = new Intl.Collator(); + } + return SortLinesCommand._COLLATOR; + } + private readonly selection: Selection; private readonly descending: boolean; private selectionId: string | null; @@ -76,9 +84,7 @@ function getSortData(model: ITextModel, selection: Selection, descending: boolea } let sorted = linesToSort.slice(0); - sorted.sort((a, b) => { - return a.toLowerCase().localeCompare(b.toLowerCase()); - }); + sorted.sort(SortLinesCommand.getCollator().compare); // If descending, reverse the order. if (descending === true) { diff --git a/src/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts b/src/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts index 7767e3fe13f..446c947cf8d 100644 --- a/src/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts +++ b/src/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts @@ -3,9 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as assert from 'assert'; import { Selection } from 'vs/editor/common/core/selection'; import { CopyLinesCommand } from 'vs/editor/contrib/linesOperations/copyLinesCommand'; import { testCommand } from 'vs/editor/test/browser/testCommand'; +import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; +import { DuplicateSelectionAction } from 'vs/editor/contrib/linesOperations/linesOperations'; function testCopyLinesDownCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { testCommand(lines, null, selection, (sel) => new CopyLinesCommand(sel, true), expectedLines, expectedSelection); @@ -195,3 +198,61 @@ suite('Editor Contrib - Copy Lines Command', () => { ); }); }); + +suite('Editor Contrib - Duplicate Selection', () => { + + const duplicateSelectionAction = new DuplicateSelectionAction(); + + function testDuplicateSelectionAction(lines: string[], selections: Selection[], expectedLines: string[], expectedSelections: Selection[]): void { + withTestCodeEditor(lines.join('\n'), {}, (editor, cursor) => { + editor.setSelections(selections); + duplicateSelectionAction.run(null!, editor, {}); + assert.deepEqual(editor.getValue(), expectedLines.join('\n')); + assert.deepEqual(editor.getSelections()!.map(s => s.toString()), expectedSelections.map(s => s.toString())); + }); + } + + test('empty selection', function () { + testDuplicateSelectionAction( + [ + 'first', + 'second line', + 'third line', + 'fourth line', + 'fifth' + ], + [new Selection(2, 2, 2, 2), new Selection(3, 2, 3, 2)], + [ + 'first', + 'second line', + 'second line', + 'third line', + 'third line', + 'fourth line', + 'fifth' + ], + [new Selection(3, 2, 3, 2), new Selection(5, 2, 5, 2)] + ); + }); + + test('with selection', function () { + testDuplicateSelectionAction( + [ + 'first', + 'second line', + 'third line', + 'fourth line', + 'fifth' + ], + [new Selection(2, 1, 2, 4), new Selection(3, 1, 3, 4)], + [ + 'first', + 'secsecond line', + 'thithird line', + 'fourth line', + 'fifth' + ], + [new Selection(2, 4, 2, 7), new Selection(3, 4, 3, 7)] + ); + }); +}); diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index 1eee5898a96..1f0551e6d10 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -44,8 +44,7 @@ function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString { : nls.localize('links.navigate.kb.alt', "alt + click"); if (link.url) { - const hoverMessage = new MarkdownString().appendMarkdown(`[${label}](${link.url.toString()}) (${kb})`); - hoverMessage.isTrusted = true; + const hoverMessage = new MarkdownString('', true).appendMarkdown(`[${label}](${link.url.toString()}) (${kb})`); return hoverMessage; } else { return new MarkdownString().appendText(`${label} (${kb})`); @@ -100,13 +99,13 @@ class LinkOccurrence { class LinkDetector implements editorCommon.IEditorContribution { - private static readonly ID: string = 'editor.linkDetector'; + public static readonly ID: string = 'editor.linkDetector'; public static get(editor: ICodeEditor): LinkDetector { return editor.getContribution(LinkDetector.ID); } - static RECOMPUTE_TIME = 1000; // ms + static readonly RECOMPUTE_TIME = 1000; // ms private readonly editor: ICodeEditor; private enabled: boolean; @@ -171,10 +170,6 @@ class LinkDetector implements editorCommon.IEditorContribution { this.beginCompute(); } - public getId(): string { - return LinkDetector.ID; - } - private onModelChanged(): void { this.currentOccurrences = {}; this.activeLinkDecorationId = null; @@ -284,10 +279,10 @@ class LinkDetector implements editorCommon.IEditorContribution { if (!occurrence) { return; } - this.openLinkOccurrence(occurrence, mouseEvent.hasSideBySideModifier); + this.openLinkOccurrence(occurrence, mouseEvent.hasSideBySideModifier, true /* from user gesture */); } - public openLinkOccurrence(occurrence: LinkOccurrence, openToSide: boolean): void { + public openLinkOccurrence(occurrence: LinkOccurrence, openToSide: boolean, fromUserGesture = false): void { if (!this.openerService) { return; @@ -297,7 +292,7 @@ class LinkDetector implements editorCommon.IEditorContribution { link.resolve(CancellationToken.None).then(uri => { // open the uri - return this.openerService.open(uri, { openToSide }); + return this.openerService.open(uri, { openToSide, fromUserGesture }); }, err => { const messageOrError = @@ -391,7 +386,7 @@ class OpenLinkAction extends EditorAction { } } -registerEditorContribution(LinkDetector); +registerEditorContribution(LinkDetector.ID, LinkDetector); registerEditorAction(OpenLinkAction); registerThemingParticipant((theme, collector) => { diff --git a/src/vs/editor/contrib/markdown/markdownRenderer.ts b/src/vs/editor/contrib/markdown/markdownRenderer.ts index e8165ed3e7a..eb17228cfa8 100644 --- a/src/vs/editor/contrib/markdown/markdownRenderer.ts +++ b/src/vs/editor/contrib/markdown/markdownRenderer.ts @@ -71,7 +71,7 @@ export class MarkdownRenderer extends Disposable { // ignore } if (uri && this._openerService) { - this._openerService.open(uri).catch(onUnexpectedError); + this._openerService.open(uri, { fromUserGesture: true }).catch(onUnexpectedError); } }, disposeables diff --git a/src/vs/editor/contrib/message/messageController.ts b/src/vs/editor/contrib/message/messageController.ts index e57a0987498..e8214f9a0d9 100644 --- a/src/vs/editor/contrib/message/messageController.ts +++ b/src/vs/editor/contrib/message/messageController.ts @@ -21,20 +21,16 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis export class MessageController extends Disposable implements editorCommon.IEditorContribution { - private static readonly _id = 'editor.contrib.messageController'; + public static readonly ID = 'editor.contrib.messageController'; - static MESSAGE_VISIBLE = new RawContextKey('messageVisible', false); + static readonly MESSAGE_VISIBLE = new RawContextKey('messageVisible', false); static get(editor: ICodeEditor): MessageController { - return editor.getContribution(MessageController._id); + 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 readonly _messageWidget = this._register(new MutableDisposable()); @@ -184,7 +180,7 @@ class MessageWidget implements IContentWidget { } } -registerEditorContribution(MessageController); +registerEditorContribution(MessageController.ID, MessageController); registerThemingParticipant((theme, collector) => { const border = theme.getColor(inputValidationInfoBorder); diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index a76a1d62e96..cadc1efd03f 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -14,7 +14,7 @@ import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/comm import { CursorMoveCommands } from 'vs/editor/common/controller/cursorMoveCommands'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { FindMatch, ITextModel, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; @@ -27,6 +27,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; export class InsertCursorAbove extends EditorAction { @@ -423,7 +424,7 @@ export class MultiCursorSession { export class MultiCursorSelectionController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.multiCursorController'; + public static readonly ID = 'editor.contrib.multiCursorController'; private readonly _editor: ICodeEditor; private _ignoreSelectionChange: boolean; @@ -446,10 +447,6 @@ export class MultiCursorSelectionController extends Disposable implements IEdito super.dispose(); } - public getId(): string { - return MultiCursorSelectionController.ID; - } - private _beginSessionIfNeeded(findController: CommonFindController): void { if (!this._session) { // Create a new session @@ -606,6 +603,17 @@ export class MultiCursorSelectionController extends Disposable implements IEdito matches = this._session.selectAll(); } + if (findState.searchScope) { + const state = findState.searchScope; + let inSelection: FindMatch[] | null = []; + for (let i = 0; i < matches.length; i++) { + if (matches[i].range.endLineNumber <= state.endLineNumber && matches[i].range.startLineNumber >= state.startLineNumber) { + inSelection.push(matches[i]); + } + } + matches = inSelection; + } + if (matches.length > 0) { const editorSelection = this._editor.getSelection(); // Have the primary cursor remain the one where the action was invoked @@ -751,7 +759,7 @@ export class CompatChangeAll extends MultiCursorSelectionControllerAction { id: 'editor.action.changeAll', label: nls.localize('changeAll.label', "Change All Occurrences"), alias: 'Change All Occurrences', - precondition: EditorContextKeys.writable, + precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.editorTextFocus), kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyCode.F2, @@ -798,7 +806,7 @@ class SelectionHighlighterState { } export class SelectionHighlighter extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.selectionHighlighter'; + public static readonly ID = 'editor.contrib.selectionHighlighter'; private readonly editor: ICodeEditor; private _isEnabled: boolean; @@ -848,10 +856,6 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut })); } - public getId(): string { - return SelectionHighlighter.ID; - } - private _update(): void { this._setState(SelectionHighlighter._createState(this._isEnabled, this.editor)); } @@ -1041,8 +1045,8 @@ function getValueInRange(model: ITextModel, range: Range, toLowerCase: boolean): return (toLowerCase ? text.toLowerCase() : text); } -registerEditorContribution(MultiCursorSelectionController); -registerEditorContribution(SelectionHighlighter); +registerEditorContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController); +registerEditorContribution(SelectionHighlighter.ID, SelectionHighlighter); registerEditorAction(InsertCursorAbove); registerEditorAction(InsertCursorBelow); diff --git a/src/vs/editor/contrib/multicursor/test/multicursor.test.ts b/src/vs/editor/contrib/multicursor/test/multicursor.test.ts index ff69c853e8a..7724699eded 100644 --- a/src/vs/editor/contrib/multicursor/test/multicursor.test.ts +++ b/src/vs/editor/contrib/multicursor/test/multicursor.test.ts @@ -79,8 +79,8 @@ suite('Multicursor selection', () => { 'var z = (3 * 5)', ], { serviceCollection: serviceCollection }, (editor, cursor) => { - let findController = editor.registerAndInstantiateContribution(CommonFindController); - let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let findController = editor.registerAndInstantiateContribution(CommonFindController.ID, CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController); let selectHighlightsAction = new SelectHighlightsAction(); editor.setSelection(new Selection(2, 9, 2, 16)); @@ -109,8 +109,8 @@ suite('Multicursor selection', () => { 'nothing' ], { serviceCollection: serviceCollection }, (editor, cursor) => { - let findController = editor.registerAndInstantiateContribution(CommonFindController); - let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let findController = editor.registerAndInstantiateContribution(CommonFindController.ID, CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController); let selectHighlightsAction = new SelectHighlightsAction(); editor.setSelection(new Selection(1, 1, 1, 1)); @@ -143,8 +143,8 @@ suite('Multicursor selection', () => { 'rty' ], { serviceCollection: serviceCollection }, (editor, cursor) => { - let findController = editor.registerAndInstantiateContribution(CommonFindController); - let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let findController = editor.registerAndInstantiateContribution(CommonFindController.ID, CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController); let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); editor.setSelection(new Selection(2, 1, 3, 4)); @@ -171,8 +171,8 @@ suite('Multicursor selection', () => { 'abcabc', ], { serviceCollection: serviceCollection }, (editor, cursor) => { - let findController = editor.registerAndInstantiateContribution(CommonFindController); - let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let findController = editor.registerAndInstantiateContribution(CommonFindController.ID, CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController); let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); editor.setSelection(new Selection(1, 1, 1, 4)); @@ -228,8 +228,8 @@ suite('Multicursor selection', () => { editor.getModel()!.setEOL(EndOfLineSequence.CRLF); - let findController = editor.registerAndInstantiateContribution(CommonFindController); - let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let findController = editor.registerAndInstantiateContribution(CommonFindController.ID, CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController); let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); editor.setSelection(new Selection(2, 1, 3, 4)); @@ -251,8 +251,8 @@ suite('Multicursor selection', () => { function testMulticursor(text: string[], callback: (editor: TestCodeEditor, findController: CommonFindController) => void): void { withTestCodeEditor(text, { serviceCollection: serviceCollection }, (editor, cursor) => { - let findController = editor.registerAndInstantiateContribution(CommonFindController); - let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController); + let findController = editor.registerAndInstantiateContribution(CommonFindController.ID, CommonFindController); + let multiCursorSelectController = editor.registerAndInstantiateContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController); callback(editor, findController); diff --git a/src/vs/editor/contrib/parameterHints/parameterHints.ts b/src/vs/editor/contrib/parameterHints/parameterHints.ts index 04011709292..6240091c268 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHints.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHints.ts @@ -20,7 +20,7 @@ import { TriggerContext } from 'vs/editor/contrib/parameterHints/parameterHintsM class ParameterHintsController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.controller.parameterHints'; + public static readonly ID = 'editor.controller.parameterHints'; public static get(editor: ICodeEditor): ParameterHintsController { return editor.getContribution(ParameterHintsController.ID); @@ -35,10 +35,6 @@ class ParameterHintsController extends Disposable implements IEditorContribution this.widget = this._register(instantiationService.createInstance(ParameterHintsWidget, this.editor)); } - getId(): string { - return ParameterHintsController.ID; - } - cancel(): void { this.widget.cancel(); } @@ -82,7 +78,7 @@ export class TriggerParameterHintsAction extends EditorAction { } } -registerEditorContribution(ParameterHintsController); +registerEditorContribution(ParameterHintsController.ID, ParameterHintsController); registerEditorAction(TriggerParameterHintsAction); const weight = KeybindingWeight.EditorContrib + 75; diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts index 6c3c9cb9ae6..7ff13c6182c 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts @@ -55,6 +55,7 @@ export class ParameterHintsModel extends Disposable { private readonly editor: ICodeEditor; private triggerOnType = false; private _state: ParameterHintState.State = ParameterHintState.Default; + private _pendingTriggers: TriggerContext[] = []; private readonly _lastSignatureHelpResult = this._register(new MutableDisposable()); private triggerChars = new CharacterSet(); private retriggerChars = new CharacterSet(); @@ -109,13 +110,12 @@ export class ParameterHintsModel extends Disposable { } const triggerId = ++this.triggerId; - this.throttledDelayer.trigger( - () => this.doTrigger({ - triggerKind: context.triggerKind, - triggerCharacter: context.triggerCharacter, - isRetrigger: this.state.type === ParameterHintState.Type.Active || this.state.type === ParameterHintState.Type.Pending, - activeSignatureHelp: this.state.type === ParameterHintState.Type.Active ? this.state.hints : undefined - }, triggerId), delay).then(undefined, onUnexpectedError); + + this._pendingTriggers.push(context); + this.throttledDelayer.trigger(() => { + return this.doTrigger(triggerId); + }, delay) + .catch(onUnexpectedError); } public next(): void { @@ -165,11 +165,28 @@ export class ParameterHintsModel extends Disposable { this._onChangedHints.fire(this.state.hints); } - private doTrigger(triggerContext: modes.SignatureHelpContext, triggerId: number): Promise { + private async doTrigger(triggerId: number): Promise { + const isRetrigger = this.state.type === ParameterHintState.Type.Active || this.state.type === ParameterHintState.Type.Pending; + const activeSignatureHelp = this.state.type === ParameterHintState.Type.Active ? this.state.hints : undefined; + this.cancel(true); + if (this._pendingTriggers.length === 0) { + return false; + } + + const context: TriggerContext = this._pendingTriggers.reduce(mergeTriggerContexts); + this._pendingTriggers = []; + + const triggerContext = { + triggerKind: context.triggerKind, + triggerCharacter: context.triggerCharacter, + isRetrigger: isRetrigger, + activeSignatureHelp: activeSignatureHelp + }; + if (!this.editor.hasModel()) { - return Promise.resolve(false); + return false; } const model = this.editor.getModel(); @@ -178,19 +195,18 @@ export class ParameterHintsModel extends Disposable { this.state = new ParameterHintState.Pending(createCancelablePromise(token => provideSignatureHelp(model, position, triggerContext, token))); - return this.state.request.then(result => { + try { + const result = await this.state.request; + // Check that we are still resolving the correct signature help if (triggerId !== this.triggerId) { - if (result) { - result.dispose(); - } + result?.dispose(); + return false; } if (!result || !result.value.signatures || result.value.signatures.length === 0) { - if (result) { - result.dispose(); - } + result?.dispose(); this._lastSignatureHelpResult.clear(); this.cancel(); return false; @@ -200,13 +216,13 @@ export class ParameterHintsModel extends Disposable { this._onChangedHints.fire(this.state.hints); return true; } - }).catch(error => { + } catch (error) { if (triggerId === this.triggerId) { this.state = ParameterHintState.Default; } onUnexpectedError(error); return false; - }); + } } private get isTriggered(): boolean { @@ -284,3 +300,19 @@ export class ParameterHintsModel extends Disposable { super.dispose(); } } + +function mergeTriggerContexts(previous: TriggerContext, current: TriggerContext) { + switch (current.triggerKind) { + case modes.SignatureHelpTriggerKind.Invoke: + // Invoke overrides previous triggers. + return current; + + case modes.SignatureHelpTriggerKind.ContentChange: + // Ignore content changes triggers + return previous; + + case modes.SignatureHelpTriggerKind.TriggerCharacter: + default: + return current; + } +} diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts index 2b1b9c8fbfa..2ac6ede62fe 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 { IDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import 'vs/css!./parameterHints'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; @@ -19,28 +19,32 @@ import { Context } from 'vs/editor/contrib/parameterHints/provideSignatureHelp'; import * as nls from 'vs/nls'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { editorHoverBackground, editorHoverBorder, textCodeBlockBackground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; +import { editorHoverBackground, editorHoverBorder, textCodeBlockBackground, textLinkForeground, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; import { HIGH_CONTRAST, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameterHints/parameterHintsModel'; const $ = dom.$; -export class ParameterHintsWidget extends Disposable implements IContentWidget, IDisposable { +export class ParameterHintsWidget extends Disposable implements IContentWidget { private static readonly ID = 'editor.widget.parameterHintsWidget'; private readonly markdownRenderer: MarkdownRenderer; private readonly renderDisposeables = this._register(new DisposableStore()); - private readonly model = this._register(new MutableDisposable()); + private readonly model: ParameterHintsModel; private readonly keyVisible: IContextKey; private readonly keyMultipleSignatures: IContextKey; - private element: HTMLElement; - private signature: HTMLElement; - private docs: HTMLElement; - private overloads: HTMLElement; - private visible: boolean; - private announcedLabel: string | null; - private scrollbar: DomScrollableElement; + + private domNodes?: { + readonly element: HTMLElement; + readonly signature: HTMLElement; + readonly docs: HTMLElement; + readonly overloads: HTMLElement; + readonly scrollbar: DomScrollableElement; + }; + + private visible: boolean = false; + private announcedLabel: string | null = null; // Editor.IContentWidget.allowEditorOverflow allowEditorOverflow = true; @@ -53,12 +57,11 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, ) { super(); this.markdownRenderer = this._register(new MarkdownRenderer(editor, modeService, openerService)); - this.model.value = new ParameterHintsModel(editor); + this.model = this._register(new ParameterHintsModel(editor)); this.keyVisible = Context.Visible.bindTo(contextKeyService); this.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService); - this.visible = false; - this._register(this.model.value.onChangedHints(newParameterHints => { + this._register(this.model.onChangedHints(newParameterHints => { if (newParameterHints) { this.show(); this.render(newParameterHints); @@ -69,8 +72,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } private createParamaterHintDOMNodes() { - this.element = $('.editor-widget.parameter-hints-widget'); - const wrapper = dom.append(this.element, $('.wrapper')); + const element = $('.editor-widget.parameter-hints-widget'); + const wrapper = dom.append(element, $('.wrapper')); wrapper.tabIndex = -1; const buttons = dom.append(wrapper, $('.buttons')); @@ -83,21 +86,29 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, const onNextClick = stop(domEvent(next, 'click')); this._register(onNextClick(this.next, this)); - this.overloads = dom.append(wrapper, $('.overloads')); + const overloads = dom.append(wrapper, $('.overloads')); const body = $('.body'); - this.scrollbar = new DomScrollableElement(body, {}); - this._register(this.scrollbar); - wrapper.appendChild(this.scrollbar.getDomNode()); + const scrollbar = new DomScrollableElement(body, {}); + this._register(scrollbar); + wrapper.appendChild(scrollbar.getDomNode()); - this.signature = dom.append(body, $('.signature')); + const signature = dom.append(body, $('.signature')); + const docs = dom.append(body, $('.docs')); - this.docs = dom.append(body, $('.docs')); + element.style.userSelect = 'text'; + + this.domNodes = { + element, + signature, + overloads, + docs, + scrollbar, + }; this.editor.addContentWidget(this); this.hide(); - this.element.style.userSelect = 'text'; this._register(this.editor.onDidChangeCursorSelection(e => { if (this.visible) { this.editor.layoutContentWidget(this); @@ -105,8 +116,11 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, })); const updateFont = () => { + if (!this.domNodes) { + return; + } const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this.element.style.fontSize = `${fontInfo.fontSize}px`; + this.domNodes.element.style.fontSize = `${fontInfo.fontSize}px`; }; updateFont(); @@ -120,33 +134,35 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } private show(): void { - if (!this.model || this.visible) { + if (this.visible) { return; } - if (!this.element) { + if (!this.domNodes) { this.createParamaterHintDOMNodes(); } this.keyVisible.set(true); this.visible = true; - setTimeout(() => dom.addClass(this.element, 'visible'), 100); + setTimeout(() => { + if (this.domNodes) { + dom.addClass(this.domNodes.element, 'visible'); + } + }, 100); this.editor.layoutContentWidget(this); } private hide(): void { - if (!this.model || !this.visible) { + if (!this.visible) { return; } - if (!this.element) { - this.createParamaterHintDOMNodes(); - } - this.keyVisible.reset(); this.visible = false; this.announcedLabel = null; - dom.removeClass(this.element, 'visible'); + if (this.domNodes) { + dom.removeClass(this.domNodes.element, 'visible'); + } this.editor.layoutContentWidget(this); } @@ -161,20 +177,23 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } private render(hints: modes.SignatureHelp): void { + if (!this.domNodes) { + return; + } + const multiple = hints.signatures.length > 1; - dom.toggleClass(this.element, 'multiple', multiple); + dom.toggleClass(this.domNodes.element, 'multiple', multiple); this.keyMultipleSignatures.set(multiple); - this.signature.innerHTML = ''; - this.docs.innerHTML = ''; + this.domNodes.signature.innerHTML = ''; + this.domNodes.docs.innerHTML = ''; const signature = hints.signatures[hints.activeSignature]; - if (!signature) { return; } - const code = dom.append(this.signature, $('.code')); + const code = dom.append(this.domNodes.signature, $('.code')); const hasParameters = signature.parameters.length > 0; const fontInfo = this.editor.getOption(EditorOption.fontInfo); @@ -184,14 +203,13 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, if (!hasParameters) { const label = dom.append(code, $('span')); label.textContent = signature.label; - } else { this.renderParameters(code, signature, hints.activeParameter); } this.renderDisposeables.clear(); - const activeParameter = signature.parameters[hints.activeParameter]; + const activeParameter: modes.ParameterInformation | undefined = signature.parameters[hints.activeParameter]; if (activeParameter && activeParameter.documentation) { const documentation = $('span.documentation'); @@ -203,43 +221,30 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, this.renderDisposeables.add(renderedContents); documentation.appendChild(renderedContents.element); } - dom.append(this.docs, $('p', {}, documentation)); + dom.append(this.domNodes.docs, $('p', {}, documentation)); } if (signature.documentation === undefined) { /** no op */ } else if (typeof signature.documentation === 'string') { - dom.append(this.docs, $('p', {}, signature.documentation)); + dom.append(this.domNodes.docs, $('p', {}, signature.documentation)); } else { const renderedContents = this.markdownRenderer.render(signature.documentation); dom.addClass(renderedContents.element, 'markdown-docs'); this.renderDisposeables.add(renderedContents); - dom.append(this.docs, renderedContents.element); + dom.append(this.domNodes.docs, renderedContents.element); } - let hasDocs = false; - if (activeParameter && typeof (activeParameter.documentation) === 'string' && activeParameter.documentation.length > 0) { - hasDocs = true; - } - if (activeParameter && typeof (activeParameter.documentation) === 'object' && activeParameter.documentation.value.length > 0) { - hasDocs = true; - } - if (typeof (signature.documentation) === 'string' && signature.documentation.length > 0) { - hasDocs = true; - } - if (typeof (signature.documentation) === 'object' && signature.documentation.value.length > 0) { - hasDocs = true; - } + const hasDocs = this.hasDocs(signature, activeParameter); - dom.toggleClass(this.signature, 'has-docs', hasDocs); - dom.toggleClass(this.docs, 'empty', !hasDocs); + dom.toggleClass(this.domNodes.signature, 'has-docs', hasDocs); + dom.toggleClass(this.domNodes.docs, 'empty', !hasDocs); let currentOverload = String(hints.activeSignature + 1); - if (hints.signatures.length < 10) { currentOverload += `/${hints.signatures.length}`; } - this.overloads.textContent = currentOverload; + this.domNodes.overloads.textContent = currentOverload; if (activeParameter) { const labelToAnnounce = this.getParameterLabel(signature, hints.activeParameter); @@ -253,11 +258,26 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } this.editor.layoutContentWidget(this); - this.scrollbar.scanDomNode(); + this.domNodes.scrollbar.scanDomNode(); + } + + private hasDocs(signature: modes.SignatureInformation, activeParameter: modes.ParameterInformation | undefined): boolean { + if (activeParameter && typeof (activeParameter.documentation) === 'string' && activeParameter.documentation.length > 0) { + return true; + } + if (activeParameter && typeof (activeParameter.documentation) === 'object' && activeParameter.documentation.value.length > 0) { + return true; + } + if (typeof (signature.documentation) === 'string' && signature.documentation.length > 0) { + return true; + } + if (typeof (signature.documentation) === 'object' && signature.documentation.value.length > 0) { + return true; + } + return false; } private renderParameters(parent: HTMLElement, signature: modes.SignatureInformation, currentParameter: number): void { - const [start, end] = this.getParameterLabelOffsets(signature, currentParameter); const beforeSpan = document.createElement('span'); @@ -297,27 +317,24 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } next(): void { - if (this.model.value) { - this.editor.focus(); - this.model.value.next(); - } + this.editor.focus(); + this.model.next(); } previous(): void { - if (this.model.value) { - this.editor.focus(); - this.model.value.previous(); - } + this.editor.focus(); + this.model.previous(); } cancel(): void { - if (this.model.value) { - this.model.value.cancel(); - } + this.model.cancel(); } getDomNode(): HTMLElement { - return this.element; + if (!this.domNodes) { + this.createParamaterHintDOMNodes(); + } + return this.domNodes!.element; } getId(): string { @@ -325,16 +342,17 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } trigger(context: TriggerContext): void { - if (this.model.value) { - this.model.value.trigger(context, 0); - } + this.model.trigger(context, 0); } private updateMaxHeight(): void { + if (!this.domNodes) { + return; + } const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); const maxHeight = `${height}px`; - this.element.style.maxHeight = maxHeight; - const wrapper = this.element.getElementsByClassName('wrapper') as HTMLCollectionOf; + this.domNodes.element.style.maxHeight = maxHeight; + const wrapper = this.domNodes.element.getElementsByClassName('wrapper') as HTMLCollectionOf; if (wrapper.length) { wrapper[0].style.maxHeight = maxHeight; } @@ -359,6 +377,11 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-editor .parameter-hints-widget a { color: ${link}; }`); } + const foreground = theme.getColor(editorHoverForeground); + if (foreground) { + collector.addRule(`.monaco-editor .parameter-hints-widget { color: ${foreground}; }`); + } + const codeBackground = theme.getColor(textCodeBlockBackground); if (codeBackground) { collector.addRule(`.monaco-editor .parameter-hints-widget code { background-color: ${codeBackground}; }`); diff --git a/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts b/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts index a6ffca40e20..2aa301d692a 100644 --- a/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts +++ b/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts @@ -96,24 +96,29 @@ suite('ParameterHintsModel', () => { provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { ++invokeCount; - if (invokeCount === 1) { - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.strictEqual(context.triggerCharacter, triggerChar); - assert.strictEqual(context.isRetrigger, false); - assert.strictEqual(context.activeSignatureHelp, undefined); + try { + if (invokeCount === 1) { + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.strictEqual(context.triggerCharacter, triggerChar); + assert.strictEqual(context.isRetrigger, false); + assert.strictEqual(context.activeSignatureHelp, undefined); - // Retrigger - setTimeout(() => editor.trigger('keyboard', Handler.Type, { text: triggerChar }), 50); - } else { - assert.strictEqual(invokeCount, 2); - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.strictEqual(context.isRetrigger, true); - assert.strictEqual(context.triggerCharacter, triggerChar); - assert.strictEqual(context.activeSignatureHelp, emptySigHelp); + // Retrigger + setTimeout(() => editor.trigger('keyboard', Handler.Type, { text: triggerChar }), 50); + } else { + assert.strictEqual(invokeCount, 2); + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.strictEqual(context.isRetrigger, true); + assert.strictEqual(context.triggerCharacter, triggerChar); + assert.strictEqual(context.activeSignatureHelp, emptySigHelp); - done(); + done(); + } + return emptySigHelpResult; + } catch (err) { + console.error(err); + throw err; } - return emptySigHelpResult; } })); @@ -133,25 +138,30 @@ suite('ParameterHintsModel', () => { signatureHelpRetriggerCharacters = []; provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { - ++invokeCount; - if (invokeCount === 1) { - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.strictEqual(context.triggerCharacter, triggerChar); - assert.strictEqual(context.isRetrigger, false); - assert.strictEqual(context.activeSignatureHelp, undefined); + try { + ++invokeCount; + if (invokeCount === 1) { + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.strictEqual(context.triggerCharacter, triggerChar); + assert.strictEqual(context.isRetrigger, false); + assert.strictEqual(context.activeSignatureHelp, undefined); - // Cancel and retrigger - hintModel.cancel(); - editor.trigger('keyboard', Handler.Type, { text: triggerChar }); - } else { - assert.strictEqual(invokeCount, 2); - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.strictEqual(context.triggerCharacter, triggerChar); - assert.strictEqual(context.isRetrigger, true); - assert.strictEqual(context.activeSignatureHelp, undefined); - done(); + // Cancel and retrigger + hintModel.cancel(); + editor.trigger('keyboard', Handler.Type, { text: triggerChar }); + } else { + assert.strictEqual(invokeCount, 2); + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.strictEqual(context.triggerCharacter, triggerChar); + assert.strictEqual(context.isRetrigger, true); + assert.strictEqual(context.activeSignatureHelp, undefined); + done(); + } + return emptySigHelpResult; + } catch (err) { + console.error(err); + throw err; } - return emptySigHelpResult; } })); @@ -168,19 +178,24 @@ suite('ParameterHintsModel', () => { signatureHelpRetriggerCharacters = []; provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext) { - ++invokeCount; + try { + ++invokeCount; - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.strictEqual(context.isRetrigger, false); - assert.strictEqual(context.triggerCharacter, 'c'); + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.strictEqual(context.isRetrigger, false); + assert.strictEqual(context.triggerCharacter, 'c'); - // Give some time to allow for later triggers - setTimeout(() => { - assert.strictEqual(invokeCount, 1); + // Give some time to allow for later triggers + setTimeout(() => { + assert.strictEqual(invokeCount, 1); - done(); - }, 50); - return undefined; + done(); + }, 50); + return undefined; + } catch (err) { + console.error(err); + throw err; + } } })); @@ -199,23 +214,28 @@ suite('ParameterHintsModel', () => { signatureHelpRetriggerCharacters = []; provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { - ++invokeCount; - if (invokeCount === 1) { - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.strictEqual(context.triggerCharacter, 'a'); + try { + ++invokeCount; + if (invokeCount === 1) { + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.strictEqual(context.triggerCharacter, 'a'); - // retrigger after delay for widget to show up - setTimeout(() => editor.trigger('keyboard', Handler.Type, { text: 'b' }), 50); - } else if (invokeCount === 2) { - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.ok(context.isRetrigger); - assert.strictEqual(context.triggerCharacter, 'b'); - done(); - } else { - assert.fail('Unexpected invoke'); + // retrigger after delay for widget to show up + setTimeout(() => editor.trigger('keyboard', Handler.Type, { text: 'b' }), 50); + } else if (invokeCount === 2) { + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.ok(context.isRetrigger); + assert.strictEqual(context.triggerCharacter, 'b'); + done(); + } else { + assert.fail('Unexpected invoke'); + } + + return emptySigHelpResult; + } catch (err) { + console.error(err); + throw err; } - - return emptySigHelpResult; } })); @@ -234,29 +254,34 @@ suite('ParameterHintsModel', () => { provideSignatureHelp(_model: ITextModel, _position: Position, token: CancellationToken): modes.SignatureHelpResult | Promise { - const count = invokeCount++; - token.onCancellationRequested(() => { didRequestCancellationOf = count; }); + try { + const count = invokeCount++; + token.onCancellationRequested(() => { didRequestCancellationOf = count; }); - // retrigger on first request - if (count === 0) { - hintsModel.trigger({ triggerKind: modes.SignatureHelpTriggerKind.Invoke }, 0); + // retrigger on first request + if (count === 0) { + hintsModel.trigger({ triggerKind: modes.SignatureHelpTriggerKind.Invoke }, 0); + } + + return new Promise(resolve => { + setTimeout(() => { + resolve({ + value: { + signatures: [{ + label: '' + count, + parameters: [] + }], + activeParameter: 0, + activeSignature: 0 + }, + dispose: () => { } + }); + }, 100); + }); + } catch (err) { + console.error(err); + throw err; } - - return new Promise(resolve => { - setTimeout(() => { - resolve({ - value: { - signatures: [{ - label: '' + count, - parameters: [] - }], - activeParameter: 0, - activeSignature: 0 - }, - dispose: () => { } - }); - }, 100); - }); } }; @@ -290,23 +315,28 @@ suite('ParameterHintsModel', () => { signatureHelpRetriggerCharacters = [retriggerChar]; provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { - ++invokeCount; - if (invokeCount === 1) { - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.strictEqual(context.triggerCharacter, triggerChar); + try { + ++invokeCount; + if (invokeCount === 1) { + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.strictEqual(context.triggerCharacter, triggerChar); - // retrigger after delay for widget to show up - setTimeout(() => editor.trigger('keyboard', Handler.Type, { text: retriggerChar }), 50); - } else if (invokeCount === 2) { - assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); - assert.ok(context.isRetrigger); - assert.strictEqual(context.triggerCharacter, retriggerChar); - done(); - } else { - assert.fail('Unexpected invoke'); + // retrigger after delay for widget to show up + setTimeout(() => editor.trigger('keyboard', Handler.Type, { text: retriggerChar }), 50); + } else if (invokeCount === 2) { + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.ok(context.isRetrigger); + assert.strictEqual(context.triggerCharacter, retriggerChar); + done(); + } else { + assert.fail('Unexpected invoke'); + } + + return emptySigHelpResult; + } catch (err) { + console.error(err); + throw err; } - - return emptySigHelpResult; } })); @@ -332,26 +362,31 @@ suite('ParameterHintsModel', () => { signatureHelpRetriggerCharacters = []; 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); + try { + if (!context.isRetrigger) { + // retrigger after delay for widget to show up + setTimeout(() => editor.trigger('keyboard', Handler.Type, { text: triggerChar }), 50); - return { - value: { - activeParameter: 0, - activeSignature: 0, - signatures: [{ - label: firstProviderId, - parameters: [ - { label: paramterLabel } - ] - }] - }, - dispose: () => { } - }; + return { + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: firstProviderId, + parameters: [ + { label: paramterLabel } + ] + }] + }, + dispose: () => { } + }; + } + + return undefined; + } catch (err) { + console.error(err); + throw err; } - - return undefined; } })); @@ -390,6 +425,43 @@ suite('ParameterHintsModel', () => { assert.strictEqual(secondHint.activeSignature, 1); assert.strictEqual(secondHint.signatures[0].parameters[0].label, paramterLabel); }); + + test('Quick typing should use the first trigger character', async () => { + const editor = createMockEditor(''); + const model = new ParameterHintsModel(editor, 50); + disposables.add(model); + + const triggerCharacter = 'a'; + + let invokeCount = 0; + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + signatureHelpTriggerCharacters = [triggerCharacter]; + signatureHelpRetriggerCharacters = []; + + provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { + try { + ++invokeCount; + + if (invokeCount === 1) { + assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); + assert.strictEqual(context.triggerCharacter, triggerCharacter); + } else { + assert.fail('Unexpected invoke'); + } + + return emptySigHelpResult; + } catch (err) { + console.error(err); + throw err; + } + } + })); + + editor.trigger('keyboard', Handler.Type, { text: triggerCharacter }); + editor.trigger('keyboard', Handler.Type, { text: 'x' }); + + await getNextHint(model); + }); }); function getNextHint(model: ParameterHintsModel) { diff --git a/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css b/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css index b0d1fefcf21..3c13476a594 100644 --- a/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css +++ b/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css @@ -4,10 +4,6 @@ *--------------------------------------------------------------------------------------------*/ .monaco-editor .peekview-widget .head { - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; box-sizing: border-box; display: flex; } @@ -52,7 +48,7 @@ background-position: center center; } -.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label.octicon { +.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label.codicon { margin: 0; } @@ -60,3 +56,7 @@ border-top: 1px solid; position: relative; } + +.monaco-editor .peekview-widget .head .peekview-title .codicon { + margin-right: 4px; +} diff --git a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts index 2d2d5113f7b..10ac07c51b7 100644 --- a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts @@ -3,25 +3,27 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'vs/css!./media/peekViewWidget'; import * as dom from 'vs/base/browser/dom'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { ActionBar, IActionBarOptions } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; import { Color } from 'vs/base/common/color'; -import { Emitter, Event } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import * as objects from 'vs/base/common/objects'; import * as strings from 'vs/base/common/strings'; -import 'vs/css!./media/peekViewWidget'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { IOptions, IStyles, ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget'; import * as nls from 'vs/nls'; -import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { IEditorContribution } from 'vs/editor/common/editorCommon'; export const IPeekViewService = createDecorator('IPeekViewService'); @@ -33,7 +35,7 @@ export interface IPeekViewService { registerSingleton(IPeekViewService, class implements IPeekViewService { _serviceBrand: undefined; - private _widgets = new Map(); + private readonly _widgets = new Map(); addExclusiveWidget(editor: ICodeEditor, widget: PeekViewWidget): void { const existing = this._widgets.get(editor); @@ -57,8 +59,26 @@ export namespace PeekContext { export const notInPeekEditor: ContextKeyExpr = inPeekEditor.toNegated(); } -export function getOuterEditor(accessor: ServicesAccessor): ICodeEditor | undefined { - const editor = accessor.get(ICodeEditorService).getFocusedCodeEditor(); +class PeekContextController implements IEditorContribution { + + static readonly ID = 'editor.contrib.referenceController'; + + constructor( + editor: ICodeEditor, + @IContextKeyService contextKeyService: IContextKeyService + ) { + if (editor instanceof EmbeddedCodeEditorWidget) { + PeekContext.inPeekEditor.bindTo(contextKeyService); + } + } + + dispose(): void { } +} + +registerEditorContribution(PeekContextController.ID, PeekContextController); + +export function getOuterEditor(accessor: ServicesAccessor): ICodeEditor | null { + let editor = accessor.get(ICodeEditorService).getFocusedCodeEditor(); if (editor instanceof EmbeddedCodeEditorWidget) { return editor.getParentEditor(); } @@ -81,9 +101,10 @@ const defaultOptions: IPeekViewOptions = { export abstract class PeekViewWidget extends ZoneWidget { - public _serviceBrand: undefined; + _serviceBrand: undefined; private readonly _onDidClose = new Emitter(); + readonly onDidClose = this._onDidClose.event; protected _headElement?: HTMLDivElement; protected _primaryHeading?: HTMLElement; @@ -97,16 +118,12 @@ export abstract class PeekViewWidget extends ZoneWidget { objects.mixin(this.options, defaultOptions, false); } - public dispose(): void { + dispose(): void { super.dispose(); this._onDidClose.fire(this); } - public get onDidClose(): Event { - return this._onDidClose.event; - } - - public style(styles: IPeekViewStyles): void { + style(styles: IPeekViewStyles): void { let options = this.options; if (styles.headerBackgroundColor) { options.headerBackgroundColor = styles.headerBackgroundColor; @@ -185,7 +202,7 @@ export abstract class PeekViewWidget extends ZoneWidget { // implement me } - public setTitle(primaryHeading: string, secondaryHeading?: string): void { + setTitle(primaryHeading: string, secondaryHeading?: string): void { if (this._primaryHeading && this._secondaryHeading) { this._primaryHeading.innerHTML = strings.escape(primaryHeading); this._primaryHeading.setAttribute('aria-label', primaryHeading); @@ -197,7 +214,7 @@ export abstract class PeekViewWidget extends ZoneWidget { } } - public setMetaTitle(value: string): void { + setMetaTitle(value: string): void { if (this._metaHeading) { if (value) { this._metaHeading.innerHTML = strings.escape(value); @@ -209,7 +226,7 @@ export abstract class PeekViewWidget extends ZoneWidget { protected abstract _fillBody(container: HTMLElement): void; - public _doLayout(heightInPixel: number, widthInPixel: number): void { + protected _doLayout(heightInPixel: number, widthInPixel: number): void { if (!this._isShowing && heightInPixel < 0) { // Looks like the view zone got folded away! diff --git a/src/vs/editor/contrib/referenceSearch/referenceSearch.ts b/src/vs/editor/contrib/referenceSearch/referenceSearch.ts index 97d8aa5dbf0..49f51a2585e 100644 --- a/src/vs/editor/contrib/referenceSearch/referenceSearch.ts +++ b/src/vs/editor/contrib/referenceSearch/referenceSearch.ts @@ -4,100 +4,26 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { Position, IPosition } from 'vs/editor/common/core/position'; -import * as editorCommon from 'vs/editor/common/editorCommon'; -import { registerEditorAction, ServicesAccessor, EditorAction, registerEditorContribution, registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions'; -import { Location, ReferenceProviderRegistry } from 'vs/editor/common/modes'; +import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { Location } from 'vs/editor/common/modes'; import { Range } from 'vs/editor/common/core/range'; -import { PeekContext, getOuterEditor } from './peekViewWidget'; -import { ReferencesController, RequestOptions, ctxReferenceSearchVisible } from './referencesController'; -import { ReferencesModel, OneReference } from './referencesModel'; +import { ReferencesController, RequestOptions } from './referencesController'; +import { ReferencesModel } from './referencesModel'; import { createCancelablePromise } from 'vs/base/common/async'; -import { onUnexpectedExternalError } from 'vs/base/common/errors'; -import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; -import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; -import { ITextModel } from 'vs/editor/common/model'; -import { IListService } from 'vs/platform/list/browser/listService'; -import { ctxReferenceWidgetSearchTreeFocused } from 'vs/editor/contrib/referenceSearch/referencesWidget'; +import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; 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'; +import { getReferencesAtPosition } from 'vs/editor/contrib/goToDefinition/goToDefinition'; -export const defaultReferenceSearchOptions: RequestOptions = { +const defaultReferenceSearchOptions: RequestOptions = { getMetaTitle(model) { return model.references.length > 1 ? nls.localize('meta.titleReference', " – {0} references", model.references.length) : ''; } }; -export class ReferenceController implements editorCommon.IEditorContribution { - - private static readonly ID = 'editor.contrib.referenceController'; - - constructor( - editor: ICodeEditor, - @IContextKeyService contextKeyService: IContextKeyService - ) { - if (editor instanceof EmbeddedCodeEditorWidget) { - PeekContext.inPeekEditor.bindTo(contextKeyService); - } - } - - public dispose(): void { - } - - public getId(): string { - return ReferenceController.ID; - } -} - -export class ReferenceAction extends EditorAction { - - constructor() { - super({ - id: 'editor.action.referenceSearch.trigger', - label: nls.localize('references.action.label', "Peek References"), - alias: 'Peek References', - precondition: ContextKeyExpr.and( - EditorContextKeys.hasReferenceProvider, - PeekContext.notInPeekEditor, - EditorContextKeys.isInEmbeddedEditor.toNegated()), - kbOpts: { - kbExpr: EditorContextKeys.editorTextFocus, - primary: KeyMod.Shift | KeyCode.F12, - weight: KeybindingWeight.EditorContrib - }, - menuOpts: { - group: 'navigation', - order: 1.5 - } - }); - } - - public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - let controller = ReferencesController.get(editor); - if (!controller) { - return; - } - if (editor.hasModel()) { - const range = editor.getSelection(); - const model = editor.getModel(); - const references = createCancelablePromise(token => provideReferences(model, range.getStartPosition(), token).then(references => new ReferencesModel(references))); - controller.toggleWidget(range, references, defaultReferenceSearchOptions); - } - } -} - -registerEditorContribution(ReferenceController); - -registerEditorAction(ReferenceAction); - -let findReferencesCommand: ICommandHandler = (accessor: ServicesAccessor, resource: URI, position: IPosition) => { +const findReferencesCommand: ICommandHandler = (accessor: ServicesAccessor, resource: URI, position: IPosition) => { if (!(resource instanceof URI)) { throw new Error('illegal argument, uri'); } @@ -116,13 +42,13 @@ let findReferencesCommand: ICommandHandler = (accessor: ServicesAccessor, resour return undefined; } - let references = createCancelablePromise(token => provideReferences(control.getModel(), Position.lift(position), token).then(references => new ReferencesModel(references))); + let references = createCancelablePromise(token => getReferencesAtPosition(control.getModel(), Position.lift(position), token).then(references => new ReferencesModel(references))); let range = new Range(position.lineNumber, position.column, position.lineNumber, position.column); return Promise.resolve(controller.toggleWidget(range, references, defaultReferenceSearchOptions)); }); }; -let showReferencesCommand: ICommandHandler = (accessor: ServicesAccessor, resource: URI, position: IPosition, references: Location[]) => { +const showReferencesCommand: ICommandHandler = (accessor: ServicesAccessor, resource: URI, position: IPosition, references: Location[]) => { if (!(resource instanceof URI)) { throw new Error('illegal argument, uri expected'); } @@ -170,125 +96,3 @@ CommandsRegistry.registerCommand({ } }); -function closeActiveReferenceSearch(accessor: ServicesAccessor, args: any) { - withController(accessor, controller => controller.closeWidget()); -} - -function openReferenceToSide(accessor: ServicesAccessor, args: any) { - const listService = accessor.get(IListService); - - const focus = listService.lastFocusedList && listService.lastFocusedList.getFocus(); - if (focus instanceof OneReference) { - withController(accessor, controller => controller.openReference(focus, true)); - } -} - -function withController(accessor: ServicesAccessor, fn: (controller: ReferencesController) => void): void { - const outerEditor = getOuterEditor(accessor); - if (!outerEditor) { - return; - } - - let controller = ReferencesController.get(outerEditor); - if (!controller) { - return; - } - - fn(controller); -} - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'goToNextReference', - weight: KeybindingWeight.WorkbenchContrib + 50, - primary: KeyCode.F4, - when: ctxReferenceSearchVisible, - handler(accessor) { - withController(accessor, controller => { - controller.goToNextOrPreviousReference(true); - }); - } -}); - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'goToNextReferenceFromEmbeddedEditor', - weight: KeybindingWeight.EditorContrib + 50, - primary: KeyCode.F4, - when: PeekContext.inPeekEditor, - handler(accessor) { - withController(accessor, controller => { - controller.goToNextOrPreviousReference(true); - }); - } -}); - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'goToPreviousReference', - weight: KeybindingWeight.WorkbenchContrib + 50, - primary: KeyMod.Shift | KeyCode.F4, - when: ctxReferenceSearchVisible, - handler(accessor) { - withController(accessor, controller => { - controller.goToNextOrPreviousReference(false); - }); - } -}); - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'goToPreviousReferenceFromEmbeddedEditor', - weight: KeybindingWeight.EditorContrib + 50, - primary: KeyMod.Shift | KeyCode.F4, - when: PeekContext.inPeekEditor, - handler(accessor) { - withController(accessor, controller => { - controller.goToNextOrPreviousReference(false); - }); - } -}); - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'closeReferenceSearch', - weight: KeybindingWeight.WorkbenchContrib + 50, - primary: KeyCode.Escape, - secondary: [KeyMod.Shift | KeyCode.Escape], - when: ContextKeyExpr.and(ctxReferenceSearchVisible, ContextKeyExpr.not('config.editor.stablePeek')), - handler: closeActiveReferenceSearch -}); - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'closeReferenceSearchEditor', - weight: KeybindingWeight.EditorContrib - 101, - primary: KeyCode.Escape, - secondary: [KeyMod.Shift | KeyCode.Escape], - when: ContextKeyExpr.and(PeekContext.inPeekEditor, ContextKeyExpr.not('config.editor.stablePeek')), - handler: closeActiveReferenceSearch -}); - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'openReferenceToSide', - weight: KeybindingWeight.EditorContrib, - primary: KeyMod.CtrlCmd | KeyCode.Enter, - mac: { - primary: KeyMod.WinCtrl | KeyCode.Enter - }, - when: ContextKeyExpr.and(ctxReferenceSearchVisible, ctxReferenceWidgetSearchTreeFocused), - handler: openReferenceToSide -}); - -export function provideReferences(model: ITextModel, position: Position, token: CancellationToken): Promise { - - // collect references from all providers - const promises = ReferenceProviderRegistry.ordered(model).map(provider => { - return Promise.resolve(provider.provideReferences(model, position, { includeDeclaration: true }, token)).then(result => { - if (Array.isArray(result)) { - return result; - } - return undefined; - }, err => { - onUnexpectedExternalError(err); - }); - }); - - 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 6f0dcdff9de..c23d6180833 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesController.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesController.ts @@ -7,19 +7,23 @@ import * as nls from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; 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'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IContextKey, IContextKeyService, RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { ReferencesModel } from './referencesModel'; -import { ReferenceWidget, LayoutData } from './referencesWidget'; +import { ReferencesModel, OneReference } from './referencesModel'; +import { ReferenceWidget, LayoutData, ctxReferenceWidgetSearchTreeFocused } from './referencesWidget'; import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; import { Location } from 'vs/editor/common/modes'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { CancelablePromise } from 'vs/base/common/async'; +import { getOuterEditor, PeekContext } from 'vs/editor/contrib/referenceSearch/peekViewWidget'; +import { IListService } from 'vs/platform/list/browser/listService'; +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; export const ctxReferenceSearchVisible = new RawContextKey('referenceSearchVisible', false); @@ -30,10 +34,10 @@ export interface RequestOptions { export abstract class ReferencesController implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.referencesController'; + static readonly ID = 'editor.contrib.referencesController'; private readonly _disposables = new DisposableStore(); - private readonly _editor: ICodeEditor; + private _widget?: ReferenceWidget; private _model?: ReferencesModel; private _requestIdPool = 0; @@ -41,13 +45,13 @@ export abstract class ReferencesController implements editorCommon.IEditorContri private readonly _referenceSearchVisible: IContextKey; - public static get(editor: ICodeEditor): ReferencesController { + static get(editor: ICodeEditor): ReferencesController { return editor.getContribution(ReferencesController.ID); } - public constructor( + constructor( private readonly _defaultTreeKeyboardSupport: boolean, - editor: ICodeEditor, + private readonly _editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, @ICodeEditorService private readonly _editorService: ICodeEditorService, @INotificationService private readonly _notificationService: INotificationService, @@ -55,28 +59,20 @@ export abstract class ReferencesController implements editorCommon.IEditorContri @IStorageService private readonly _storageService: IStorageService, @IConfigurationService private readonly _configurationService: IConfigurationService, ) { - this._editor = editor; + this._referenceSearchVisible = ctxReferenceSearchVisible.bindTo(contextKeyService); } - public getId(): string { - return ReferencesController.ID; - } - - public dispose(): void { + dispose(): void { this._referenceSearchVisible.reset(); - dispose(this._disposables); - if (this._widget) { - dispose(this._widget); - this._widget = undefined; - } - if (this._model) { - dispose(this._model); - this._model = undefined; - } + this._disposables.dispose(); + dispose(this._widget); + dispose(this._model); + this._widget = undefined; + this._model = undefined; } - public toggleWidget(range: Range, modelPromise: CancelablePromise, options: RequestOptions): void { + toggleWidget(range: Range, modelPromise: CancelablePromise, options: RequestOptions): void { // close current widget and return early is position didn't change let widgetPosition: Position | undefined; @@ -177,7 +173,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri }); } - public async goToNextOrPreviousReference(fwd: boolean) { + async goToNextOrPreviousReference(fwd: boolean) { if (!this._editor.hasModel() || !this._model || !this._widget) { // can be called while still resolving... return; @@ -199,7 +195,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri } } - public closeWidget(): void { + closeWidget(): void { if (this._widget) { dispose(this._widget); this._widget = undefined; @@ -251,7 +247,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri }); } - public openReference(ref: Location, sideBySide: boolean): void { + openReference(ref: Location, sideBySide: boolean): void { // clear stage if (!sideBySide) { this.closeWidget(); @@ -264,3 +260,101 @@ export abstract class ReferencesController implements editorCommon.IEditorContri }, this._editor, sideBySide); } } + +function withController(accessor: ServicesAccessor, fn: (controller: ReferencesController) => void): void { + const outerEditor = getOuterEditor(accessor); + if (!outerEditor) { + return; + } + let controller = ReferencesController.get(outerEditor); + if (controller) { + fn(controller); + } +} + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'goToNextReference', + weight: KeybindingWeight.WorkbenchContrib + 50, + primary: KeyCode.F4, + when: ctxReferenceSearchVisible, + handler(accessor) { + withController(accessor, controller => { + controller.goToNextOrPreviousReference(true); + }); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'goToNextReferenceFromEmbeddedEditor', + weight: KeybindingWeight.EditorContrib + 50, + primary: KeyCode.F4, + when: PeekContext.inPeekEditor, + handler(accessor) { + withController(accessor, controller => { + controller.goToNextOrPreviousReference(true); + }); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'goToPreviousReference', + weight: KeybindingWeight.WorkbenchContrib + 50, + primary: KeyMod.Shift | KeyCode.F4, + when: ctxReferenceSearchVisible, + handler(accessor) { + withController(accessor, controller => { + controller.goToNextOrPreviousReference(false); + }); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'goToPreviousReferenceFromEmbeddedEditor', + weight: KeybindingWeight.EditorContrib + 50, + primary: KeyMod.Shift | KeyCode.F4, + when: PeekContext.inPeekEditor, + handler(accessor) { + withController(accessor, controller => { + controller.goToNextOrPreviousReference(false); + }); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'closeReferenceSearch', + weight: KeybindingWeight.WorkbenchContrib + 50, + primary: KeyCode.Escape, + secondary: [KeyMod.Shift | KeyCode.Escape], + when: ContextKeyExpr.and(ctxReferenceSearchVisible, ContextKeyExpr.not('config.editor.stablePeek')), + handler(accessor: ServicesAccessor) { + withController(accessor, controller => controller.closeWidget()); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'closeReferenceSearchEditor', + weight: KeybindingWeight.EditorContrib - 101, + primary: KeyCode.Escape, + secondary: [KeyMod.Shift | KeyCode.Escape], + when: ContextKeyExpr.and(PeekContext.inPeekEditor, ContextKeyExpr.not('config.editor.stablePeek')), + handler(accessor: ServicesAccessor) { + withController(accessor, controller => controller.closeWidget()); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'openReferenceToSide', + weight: KeybindingWeight.EditorContrib, + primary: KeyMod.CtrlCmd | KeyCode.Enter, + mac: { + primary: KeyMod.WinCtrl | KeyCode.Enter + }, + when: ContextKeyExpr.and(ctxReferenceSearchVisible, ctxReferenceWidgetSearchTreeFocused), + handler(accessor: ServicesAccessor) { + const listService = accessor.get(IListService); + const focus = listService.lastFocusedList && listService.lastFocusedList.getFocus(); + if (focus instanceof OneReference) { + withController(accessor, controller => controller.openReference(focus, true)); + } + } +}); diff --git a/src/vs/editor/contrib/referenceSearch/referencesModel.ts b/src/vs/editor/contrib/referenceSearch/referencesModel.ts index 36d54e60852..390087d266e 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesModel.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesModel.ts @@ -15,20 +15,18 @@ 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'; +import { Constants } from 'vs/base/common/uint'; export class OneReference { - readonly id: string; - private readonly _onRefChanged = new Emitter(); - readonly onRefChanged: Event = this._onRefChanged.event; + readonly id: string = defaultGenerator.nextId(); constructor( + readonly isProviderFirst: boolean, readonly parent: FileReferences, private _range: IRange, - readonly isProviderFirst: boolean - ) { - this.id = defaultGenerator.nextId(); - } + private _rangeCallback: (ref: OneReference) => void + ) { } get uri(): URI { return this.parent.uri; @@ -40,7 +38,7 @@ export class OneReference { set range(value: IRange) { this._range = value; - this._onRefChanged.fire(this); + this._rangeCallback(this); } getAriaMessage(): string { @@ -55,8 +53,7 @@ export class FilePreview implements IDisposable { constructor( private readonly _modelReference: IReference - ) { - } + ) { } dispose(): void { dispose(this._modelReference); @@ -72,7 +69,7 @@ export class FilePreview implements IDisposable { const { startLineNumber, startColumn, endLineNumber, endColumn } = range; const word = model.getWordUntilPosition({ lineNumber: startLineNumber, column: startColumn - n }); const beforeRange = new Range(startLineNumber, word.startColumn, startLineNumber, startColumn); - const afterRange = new Range(endLineNumber, endColumn, endLineNumber, Number.MAX_VALUE); + const afterRange = new Range(endLineNumber, endColumn, endLineNumber, Constants.MAX_SAFE_SMALL_INTEGER); const before = model.getValueInRange(beforeRange).replace(/^\s+/, ''); const inside = model.getValueInRange(range); @@ -87,29 +84,20 @@ export class FilePreview implements IDisposable { export class FileReferences implements IDisposable { - private _children: OneReference[]; + readonly children: OneReference[] = []; + private _preview?: FilePreview; private _resolved?: boolean; - private _loadFailure: any; + private _loadFailure?: any; - constructor(private readonly _parent: ReferencesModel, private readonly _uri: URI) { - this._children = []; - } + constructor( + readonly parent: ReferencesModel, + readonly uri: URI + ) { } - get id(): string { - return this._uri.toString(); - } - - get parent(): ReferencesModel { - return this._parent; - } - - get children(): OneReference[] { - return this._children; - } - - get uri(): URI { - return this._uri; + dispose(): void { + dispose(this._preview); + this._preview = undefined; } get preview(): FilePreview | undefined { @@ -135,7 +123,7 @@ export class FileReferences implements IDisposable { return Promise.resolve(this); } - return Promise.resolve(textModelResolverService.createModelReference(this._uri).then(modelReference => { + return Promise.resolve(textModelResolverService.createModelReference(this.uri).then(modelReference => { const model = modelReference.object; if (!model) { @@ -149,19 +137,12 @@ export class FileReferences implements IDisposable { }, err => { // something wrong here - this._children = []; + this.children.length = 0; this._resolved = true; this._loadFailure = err; return this; })); } - - dispose(): void { - if (this._preview) { - this._preview.dispose(); - this._preview = undefined; - } - } } export class ReferencesModel implements IDisposable { @@ -173,38 +154,46 @@ export class ReferencesModel implements IDisposable { readonly _onDidChangeReferenceRange = new Emitter(); readonly onDidChangeReferenceRange: Event = this._onDidChangeReferenceRange.event; - constructor(references: LocationLink[]) { + constructor(links: LocationLink[]) { // grouping and sorting - const [providersFirst] = references; - references.sort(ReferencesModel._compareReferences); + const [providersFirst] = links; + links.sort(ReferencesModel._compareReferences); let current: FileReferences | undefined; - for (let ref of references) { - if (!current || current.uri.toString() !== ref.uri.toString()) { + for (let link of links) { + if (!current || current.uri.toString() !== link.uri.toString()) { // new group - current = new FileReferences(this, ref.uri); + current = new FileReferences(this, link.uri); this.groups.push(current); } // append, check for equality first! - if (current.children.length === 0 - || !Range.equalsRange(ref.range, current.children[current.children.length - 1].range)) { + if (current.children.length === 0 || !Range.equalsRange(link.range, current.children[current.children.length - 1].range)) { - let oneRef = new OneReference(current, ref.targetSelectionRange || ref.range, providersFirst === ref); - this._disposables.add(oneRef.onRefChanged((e) => this._onDidChangeReferenceRange.fire(e))); + const oneRef = new OneReference( + providersFirst === link, current, link.targetSelectionRange || link.range, + ref => this._onDidChangeReferenceRange.fire(ref) + ); this.references.push(oneRef); current.children.push(oneRef); } } } - get empty(): boolean { + dispose(): void { + dispose(this.groups); + this._disposables.dispose(); + this._onDidChangeReferenceRange.dispose(); + this.groups.length = 0; + } + + get isEmpty(): boolean { return this.groups.length === 0; } getAriaMessage(): string { - if (this.empty) { + if (this.isEmpty) { return localize('aria.result.0', "No results found"); } else if (this.references.length === 1) { return localize('aria.result.1', "Found 1 symbol in {0}", this.references[0].uri.fsPath); @@ -271,6 +260,17 @@ export class ReferencesModel implements IDisposable { return undefined; } + referenceAt(resource: URI, position: Position): OneReference | undefined { + for (const ref of this.references) { + if (ref.uri.toString() === resource.toString()) { + if (Range.containsPosition(ref.range, position)) { + return ref; + } + } + } + return undefined; + } + firstReference(): OneReference | undefined { for (const ref of this.references) { if (ref.isProviderFirst) { @@ -280,21 +280,7 @@ export class ReferencesModel implements IDisposable { return this.references[0]; } - dispose(): void { - dispose(this.groups); - this._disposables.dispose(); - this.groups.length = 0; - } - private static _compareReferences(a: Location, b: Location): number { - const auri = a.uri.toString(); - const buri = b.uri.toString(); - if (auri < buri) { - return -1; - } else if (auri > buri) { - return 1; - } else { - return Range.compareRangesUsingStarts(a.range, b.range); - } + return strings.compare(a.uri.toString(), b.uri.toString()) || Range.compareRangesUsingStarts(a.range, b.range); } } diff --git a/src/vs/editor/contrib/referenceSearch/referencesTree.ts b/src/vs/editor/contrib/referenceSearch/referencesTree.ts index e563158bda9..03ab2701f04 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesTree.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesTree.ts @@ -101,7 +101,7 @@ export class StringRepresentationProvider implements IKeyboardNavigationLabelPro export class IdentityProvider implements IIdentityProvider { getId(element: TreeElement): { toString(): string; } { - return element.id; + return element.uri; } } diff --git a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts index 627902b09b9..7d2127c011e 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts @@ -10,7 +10,7 @@ import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; 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 { basenameOrAuthority, dirname, isEqual } from 'vs/base/common/resources'; import 'vs/css!./media/referencesWidget'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; @@ -31,9 +31,7 @@ import { activeContrastBorder, contrastBorder, registerColor } from 'vs/platform import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { PeekViewWidget, IPeekViewService } from './peekViewWidget'; import { FileReferences, OneReference, ReferencesModel } from './referencesModel'; -import { ITreeRenderer, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; import { IAsyncDataTreeOptions } from 'vs/base/browser/ui/tree/asyncDataTree'; -import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { FuzzyScore } from 'vs/base/common/filters'; import { SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview'; @@ -55,7 +53,7 @@ class DecorationsManager implements IDisposable { this._onModelChanged(); } - public dispose(): void { + dispose(): void { this._callOnModelChange.dispose(); this._callOnDispose.dispose(); this.removeDecorations(); @@ -66,7 +64,7 @@ class DecorationsManager implements IDisposable { const model = this._editor.getModel(); if (model) { for (const ref of this._model.groups) { - if (ref.uri.toString() === model.uri.toString()) { + if (isEqual(ref.uri, model.uri)) { this._addDecorations(ref); return; } @@ -147,7 +145,7 @@ class DecorationsManager implements IDisposable { this._editor.deltaDecorations(toRemove, []); } - public removeDecorations(): void { + removeDecorations(): void { let toRemove: string[] = []; this._decorations.forEach((value, key) => { toRemove.push(key); @@ -179,9 +177,9 @@ export class LayoutData { } export interface SelectionEvent { - kind: 'goto' | 'show' | 'side' | 'open'; - source: 'editor' | 'tree' | 'title'; - element?: Location; + readonly kind: 'goto' | 'show' | 'side' | 'open'; + readonly source: 'editor' | 'tree' | 'title'; + readonly element?: Location; } export const ctxReferenceWidgetSearchTreeFocused = new RawContextKey('referenceSearchTreeFocused', true); @@ -311,7 +309,7 @@ export class ReferenceWidget extends PeekViewWidget { keyboardNavigationLabelProvider: this._instantiationService.createInstance(StringRepresentationProvider), identityProvider: new IdentityProvider() }; - this._tree = this._instantiationService.createInstance, ITreeRenderer[], IAsyncDataSource, IAsyncDataTreeOptions, WorkbenchAsyncDataTree>( + this._tree = this._instantiationService.createInstance>( WorkbenchAsyncDataTree, 'ReferencesWidget', this._treeContainer, @@ -366,21 +364,6 @@ export class ReferenceWidget extends PeekViewWidget { this._tree.onDidChangeFocus(e => { onEvent(e.elements[0], 'show'); }); - this._tree.onDidChangeSelection(e => { - let aside = false; - let goto = false; - if (e.browserEvent instanceof KeyboardEvent) { - // todo@joh make this a command - goto = true; - } - if (aside) { - onEvent(e.elements[0], 'side'); - } else if (goto) { - onEvent(e.elements[0], 'goto'); - } else { - onEvent(e.elements[0], 'show'); - } - }); this._tree.onDidOpen(e => { const aside = (e.browserEvent instanceof MouseEvent) && (e.browserEvent.ctrlKey || e.browserEvent.metaKey || e.browserEvent.altKey); let goto = !e.browserEvent || ((e.browserEvent instanceof MouseEvent) && e.browserEvent.detail === 2); @@ -414,7 +397,7 @@ export class ReferenceWidget extends PeekViewWidget { this._splitView.resizeView(0, widthInPixel * this.layoutData.ratio); } - public setSelection(selection: OneReference): Promise { + setSelection(selection: OneReference): Promise { return this._revealReference(selection, true).then(() => { if (!this._model) { // disposed @@ -426,7 +409,7 @@ export class ReferenceWidget extends PeekViewWidget { }); } - public setModel(newModel: ReferencesModel | undefined): Promise { + setModel(newModel: ReferencesModel | undefined): Promise { // clean up this._disposeOnNewModel.clear(); this._model = newModel; @@ -441,7 +424,7 @@ export class ReferenceWidget extends PeekViewWidget { return Promise.resolve(undefined); } - if (this._model.empty) { + if (this._model.isEmpty) { this.setTitle(''); this._messageContainer.innerHTML = nls.localize('noResults', "No results"); dom.show(this._messageContainer); diff --git a/src/vs/editor/contrib/rename/rename.ts b/src/vs/editor/contrib/rename/rename.ts index ab06982895b..8eb67d9fe04 100644 --- a/src/vs/editor/contrib/rename/rename.ts +++ b/src/vs/editor/contrib/rename/rename.ts @@ -20,15 +20,16 @@ import { Position, IPosition } from 'vs/editor/common/core/position'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { Range } from 'vs/editor/common/core/range'; import { MessageController } from 'vs/editor/contrib/message/messageController'; -import { EditorState, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; +import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/browser/core/editorState'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IdleValue, raceCancellation } from 'vs/base/common/async'; +import { withNullAsUndefined } from 'vs/base/common/types'; class RenameSkeleton { @@ -45,15 +46,15 @@ class RenameSkeleton { return this._providers.length > 0; } - async resolveRenameLocation(token: CancellationToken): Promise { + async resolveRenameLocation(token: CancellationToken): Promise { const firstProvider = this._providers[0]; if (!firstProvider) { return undefined; } - let res: RenameLocation & Rejection | null | undefined; + let res: RenameLocation & Rejection | undefined; if (firstProvider.resolveRenameLocation) { - res = await firstProvider.resolveRenameLocation(this.model, this.position, token); + res = withNullAsUndefined(await firstProvider.resolveRenameLocation(this.model, this.position, token)); } if (!res) { @@ -94,21 +95,17 @@ export async function rename(model: ITextModel, position: Position, newName: str // --- register actions and commands -class RenameController extends Disposable implements IEditorContribution { +class RenameController implements IEditorContribution { - private static readonly ID = 'editor.contrib.renameController'; + public static readonly ID = 'editor.contrib.renameController'; - public static get(editor: ICodeEditor): RenameController { + static get(editor: ICodeEditor): RenameController { return editor.getContribution(RenameController.ID); } - private _renameInputField?: RenameInputField; - private _renameOperationIdPool = 1; - - private _activeRename?: { - readonly id: number; - readonly operation: CancelablePromise; - }; + private readonly _renameInputField: IdleValue; + private readonly _dispoableStore = new DisposableStore(); + private _cts: CancellationTokenSource = new CancellationTokenSource(); constructor( private readonly editor: ICodeEditor, @@ -118,37 +115,18 @@ class RenameController extends Disposable implements IEditorContribution { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IThemeService private readonly _themeService: IThemeService, ) { - super(); - this._register(this.editor.onDidChangeModel(() => this.onModelChanged())); - this._register(this.editor.onDidChangeModelLanguage(() => this.onModelChanged())); - this._register(this.editor.onDidChangeCursorSelection(() => this.onModelChanged())); + this._renameInputField = new IdleValue(() => this._dispoableStore.add(new RenameInputField(this.editor, this._themeService, this._contextKeyService))); } - private get renameInputField(): RenameInputField { - if (!this._renameInputField) { - this._renameInputField = this._register(new RenameInputField(this.editor, this._themeService, this._contextKeyService)); - } - return this._renameInputField; - } - - getId(): string { - return RenameController.ID; + dispose(): void { + this._dispoableStore.dispose(); + this._cts.dispose(true); } async run(): Promise { - if (this._activeRename) { - this._activeRename.operation.cancel(); - } - const id = this._renameOperationIdPool++; - this._activeRename = { - id, - operation: createCancelablePromise(token => this.doRename(token, id)) - }; - return this._activeRename.operation; - } + this._cts.dispose(true); - private async doRename(token: CancellationToken, id: number): Promise { if (!this.editor.hasModel()) { return undefined; } @@ -160,9 +138,12 @@ class RenameController extends Disposable implements IEditorContribution { return undefined; } - let loc: RenameLocation & Rejection | null | undefined; + this._cts = new EditorStateCancellationTokenSource(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value); + + // resolve rename location + let loc: RenameLocation & Rejection | undefined; try { - const resolveLocationOperation = skeleton.resolveRenameLocation(token); + const resolveLocationOperation = skeleton.resolveRenameLocation(this._cts.token); this._progressService.showWhile(resolveLocationOperation, 250); loc = await resolveLocationOperation; } catch (e) { @@ -179,10 +160,11 @@ class RenameController extends Disposable implements IEditorContribution { return undefined; } - if (!this._activeRename || this._activeRename.id !== id) { + if (this._cts.token.isCancellationRequested) { return undefined; } + // do rename at location let selection = this.editor.getSelection(); let selectionStart = 0; let selectionEnd = loc.text.length; @@ -192,69 +174,52 @@ class RenameController extends Disposable implements IEditorContribution { selectionEnd = Math.min(loc.range.endColumn, selection.endColumn) - loc.range.startColumn; } - return this.renameInputField.getInput(loc.range, loc.text, selectionStart, selectionEnd).then(newNameOrFocusFlag => { + const newNameOrFocusFlag = await this._renameInputField.getValue().getInput(loc.range, loc.text, selectionStart, selectionEnd); - if (typeof newNameOrFocusFlag === 'boolean') { - if (newNameOrFocusFlag) { - this.editor.focus(); - } - return undefined; + + if (typeof newNameOrFocusFlag === 'boolean') { + if (newNameOrFocusFlag) { + this.editor.focus(); + } + return undefined; + } + + this.editor.focus(); + + const renameOperation = raceCancellation(skeleton.provideRenameEdits(newNameOrFocusFlag, 0, [], this._cts.token), this._cts.token).then(async renameResult => { + + if (!renameResult || !this.editor.hasModel()) { + return; } - this.editor.focus(); + if (renameResult.rejectReason) { + this._notificationService.info(renameResult.rejectReason); + return; + } - const state = new EditorState(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection | CodeEditorStateFlag.Scroll); + const editResult = await this._bulkEditService.apply(renameResult, { editor: this.editor }); - const renameOperation = Promise.resolve(skeleton.provideRenameEdits(newNameOrFocusFlag, 0, [], token).then(result => { - - if (!this.editor.hasModel()) { - return undefined; - } - - if (result.rejectReason) { - if (state.validate(this.editor)) { - MessageController.get(this.editor).showMessage(result.rejectReason, this.editor.getPosition()); - } else { - this._notificationService.info(result.rejectReason); - } - return undefined; - } - - return this._bulkEditService.apply(result, { editor: this.editor }).then(result => { - // alert - if (result.ariaSummary) { - alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc!.text, newNameOrFocusFlag, result.ariaSummary)); - } - }); - - }, err => { - this._notificationService.error(nls.localize('rename.failed', "Rename failed to execute.")); - return Promise.reject(err); - })); - - this._progressService.showWhile(renameOperation, 250); - return renameOperation; + // alert + if (editResult.ariaSummary) { + alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc!.text, newNameOrFocusFlag, editResult.ariaSummary)); + } + }, err => { + this._notificationService.error(nls.localize('rename.failed', "Rename failed to execute.")); + return Promise.reject(err); }); + + this._progressService.showWhile(renameOperation, 250); + return renameOperation; + } - public acceptRenameInput(): void { - if (this._renameInputField) { - this._renameInputField.acceptInput(); - } + acceptRenameInput(): void { + this._renameInputField.getValue().acceptInput(); } - public cancelRenameInput(): void { - if (this._renameInputField) { - this._renameInputField.cancelInput(true); - } - } - - private onModelChanged(): void { - if (this._activeRename) { - this._activeRename.operation.cancel(); - this._activeRename = undefined; - } + cancelRenameInput(): void { + this._renameInputField.getValue().cancelInput(true); } } @@ -309,7 +274,7 @@ export class RenameAction extends EditorAction { } } -registerEditorContribution(RenameController); +registerEditorContribution(RenameController.ID, RenameController); registerEditorAction(RenameAction); const RenameCommand = EditorCommand.bindToContribution(RenameController.get); diff --git a/src/vs/editor/contrib/rename/renameInputField.ts b/src/vs/editor/contrib/rename/renameInputField.ts index 1113144c6c4..a87899a71a1 100644 --- a/src/vs/editor/contrib/rename/renameInputField.ts +++ b/src/vs/editor/contrib/rename/renameInputField.ts @@ -89,14 +89,14 @@ export class RenameInputField implements IContentWidget, IDisposable { const widgetShadowColor = theme.getColor(widgetShadow); const border = theme.getColor(inputBorder); - this._inputField.style.backgroundColor = background ? background.toString() : null; + this._inputField.style.backgroundColor = background ? background.toString() : ''; this._inputField.style.color = foreground ? foreground.toString() : null; this._inputField.style.borderWidth = border ? '1px' : '0px'; this._inputField.style.borderStyle = border ? 'solid' : 'none'; this._inputField.style.borderColor = border ? border.toString() : 'none'; - this._domNode!.style.boxShadow = widgetShadowColor ? ` 0 2px 8px ${widgetShadowColor}` : null; + this._domNode!.style.boxShadow = widgetShadowColor ? ` 0 2px 8px ${widgetShadowColor}` : ''; } private updateFont(): void { diff --git a/src/vs/editor/contrib/smartSelect/bracketSelections.ts b/src/vs/editor/contrib/smartSelect/bracketSelections.ts index 728c4573f8b..69bbb6eadea 100644 --- a/src/vs/editor/contrib/smartSelect/bracketSelections.ts +++ b/src/vs/editor/contrib/smartSelect/bracketSelections.ts @@ -51,7 +51,7 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider { setTimeout(() => BracketSelectionRangeProvider._bracketsRightYield(resolve, round + 1, model, pos, ranges)); break; } - const key = bracket.close; + const key = bracket.close[0]; if (bracket.isOpen) { // wait for closing let val = counts.has(key) ? counts.get(key)! : 0; @@ -96,7 +96,7 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider { setTimeout(() => BracketSelectionRangeProvider._bracketsLeftYield(resolve, round + 1, model, pos, ranges, bucket)); break; } - const key = bracket.close; + const key = bracket.close[0]; if (!bracket.isOpen) { // wait for opening let val = counts.has(key) ? counts.get(key)! : 0; diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index 43401ee00e8..81b60e73d91 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -47,10 +47,10 @@ class SelectionRanges { class SmartSelectController implements IEditorContribution { - private static readonly _id = 'editor.contrib.smartSelectController'; + public static readonly ID = 'editor.contrib.smartSelectController'; static get(editor: ICodeEditor): SmartSelectController { - return editor.getContribution(SmartSelectController._id); + return editor.getContribution(SmartSelectController.ID); } private readonly _editor: ICodeEditor; @@ -67,10 +67,6 @@ class SmartSelectController implements IEditorContribution { dispose(this._selectionListener); } - getId(): string { - return SmartSelectController._id; - } - run(forward: boolean): Promise | void { if (!this._editor.hasModel()) { return; @@ -210,7 +206,7 @@ class ShrinkSelectionAction extends AbstractSmartSelect { } } -registerEditorContribution(SmartSelectController); +registerEditorContribution(SmartSelectController.ID, SmartSelectController); registerEditorAction(GrowSelectionAction); registerEditorAction(ShrinkSelectionAction); diff --git a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts index b918921b059..f0eedb8324d 100644 --- a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts @@ -12,33 +12,11 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { javascriptOnEnterRules } from 'vs/editor/test/common/modes/supports/javascriptOnEnterRules'; -import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { isLinux, isMacintosh } from 'vs/base/common/platform'; import { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bracketSelections'; import { provideSelectionRanges } from 'vs/editor/contrib/smartSelect/smartSelect'; import { CancellationToken } from 'vs/base/common/cancellation'; import { WordSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/wordSelections'; - -class TestTextResourcePropertiesService implements ITextResourcePropertiesService { - - _serviceBrand: undefined; - - constructor( - @IConfigurationService private readonly configurationService: IConfigurationService, - ) { - } - - getEOL(resource: URI | undefined): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files'); - if (filesConfiguration && filesConfiguration.eol) { - if (filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; - } - } - return (isLinux || isMacintosh) ? '\n' : '\r\n'; - } -} +import { TestTextResourcePropertiesService } from 'vs/editor/test/common/services/modelService.test'; class MockJSMode extends MockMode { diff --git a/src/vs/editor/contrib/snippet/snippetController2.ts b/src/vs/editor/contrib/snippet/snippetController2.ts index cec786f46fe..322b36075ca 100644 --- a/src/vs/editor/contrib/snippet/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/snippetController2.ts @@ -40,13 +40,15 @@ const _defaultOptions: ISnippetInsertOptions = { export class SnippetController2 implements IEditorContribution { + public static ID = 'snippetController2'; + static get(editor: ICodeEditor): SnippetController2 { - return editor.getContribution('snippetController2'); + return editor.getContribution(SnippetController2.ID); } - static InSnippetMode = new RawContextKey('inSnippetMode', false); - static HasNextTabstop = new RawContextKey('hasNextTabstop', false); - static HasPrevTabstop = new RawContextKey('hasPrevTabstop', false); + static readonly InSnippetMode = new RawContextKey('inSnippetMode', false); + static readonly HasNextTabstop = new RawContextKey('hasNextTabstop', false); + static readonly HasPrevTabstop = new RawContextKey('hasPrevTabstop', false); private readonly _inSnippet: IContextKey; private readonly _hasNextTabstop: IContextKey; @@ -75,10 +77,6 @@ export class SnippetController2 implements IEditorContribution { this._snippetListener.dispose(); } - getId(): string { - return 'snippetController2'; - } - insert( template: string, opts?: Partial @@ -249,7 +247,7 @@ export class SnippetController2 implements IEditorContribution { } -registerEditorContribution(SnippetController2); +registerEditorContribution(SnippetController2.ID, SnippetController2); const CommandCtor = EditorCommand.bindToContribution(SnippetController2.get); diff --git a/src/vs/editor/contrib/snippet/snippetParser.ts b/src/vs/editor/contrib/snippet/snippetParser.ts index 61e0fd2a802..7823405f14e 100644 --- a/src/vs/editor/contrib/snippet/snippetParser.ts +++ b/src/vs/editor/contrib/snippet/snippetParser.ts @@ -664,27 +664,23 @@ export class SnippetParser { } private _until(type: TokenType): false | string { - if (this._token.type === TokenType.EOF) { - return false; - } - let res = ''; - let pos = this._token.pos; - let prevToken = { type: TokenType.EOF, pos: 0, len: 0 }; - - while (this._token.type !== type || prevToken.type === TokenType.Backslash) { - if (this._token.type === type) { - res += this._scanner.value.substring(pos, prevToken.pos); - pos = this._token.pos; - } - prevToken = this._token; - this._token = this._scanner.next(); + const start = this._token; + while (this._token.type !== type) { if (this._token.type === TokenType.EOF) { return false; + } else if (this._token.type === TokenType.Backslash) { + const nextToken = this._scanner.next(); + if (nextToken.type !== TokenType.Dollar + && nextToken.type !== TokenType.CurlyClose + && nextToken.type !== TokenType.Backslash) { + return false; + } } + this._token = this._scanner.next(); } - res += this._scanner.value.substring(pos, this._token.pos); + const value = this._scanner.value.substring(start.pos, this._token.pos).replace(/\\(\$|}|\\)/g, '$1'); this._token = this._scanner.next(); - return res; + return value; } private _parse(marker: Marker): boolean { diff --git a/src/vs/editor/contrib/snippet/snippetSession.ts b/src/vs/editor/contrib/snippet/snippetSession.ts index 8bc84ccfd52..8af3c14063b 100644 --- a/src/vs/editor/contrib/snippet/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/snippetSession.ts @@ -18,7 +18,7 @@ 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, Marker } from './snippetParser'; -import { ClipboardBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, SelectionBasedVariableResolver, TimeBasedVariableResolver, CommentBasedVariableResolver, WorkspaceBasedVariableResolver } from './snippetVariables'; +import { ClipboardBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, SelectionBasedVariableResolver, TimeBasedVariableResolver, CommentBasedVariableResolver, WorkspaceBasedVariableResolver, RandomBasedVariableResolver } 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'; @@ -333,7 +333,7 @@ const _defaultOptions: ISnippetSessionInsertOptions = { export class SnippetSession { - static adjustWhitespace(model: ITextModel, position: IPosition, snippet: TextmateSnippet): void { + static adjustWhitespace(model: ITextModel, position: IPosition, snippet: TextmateSnippet, adjustIndentation: boolean, adjustNewlines: boolean): void { const line = model.getLineContent(position.lineNumber); const lineLeadingWhitespace = getLeadingWhitespace(line, 0, position.column - 1); @@ -342,13 +342,19 @@ export class SnippetSession { // adjust indentation of text markers, except for choise elements // which get adjusted when being selected const lines = marker.value.split(/\r\n|\r|\n/); - for (let i = 1; i < lines.length; i++) { - let templateLeadingWhitespace = getLeadingWhitespace(lines[i]); - lines[i] = model.normalizeIndentation(lineLeadingWhitespace + templateLeadingWhitespace) + lines[i].substr(templateLeadingWhitespace.length); + + if (adjustIndentation) { + for (let i = 1; i < lines.length; i++) { + let templateLeadingWhitespace = getLeadingWhitespace(lines[i]); + lines[i] = model.normalizeIndentation(lineLeadingWhitespace + templateLeadingWhitespace) + lines[i].substr(templateLeadingWhitespace.length); + } } - const newValue = lines.join(model.getEOL()); - if (newValue !== marker.value) { - marker.parent.replace(marker, [new Text(newValue)]); + + if (adjustNewlines) { + const newValue = lines.join(model.getEOL()); + if (newValue !== marker.value) { + marker.parent.replace(marker, [new Text(newValue)]); + } } } return true; @@ -392,7 +398,7 @@ export class SnippetSession { 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(); + const readClipboardText = () => clipboardText || clipboardService && clipboardService.readTextSync(); let delta = 0; @@ -439,17 +445,20 @@ export class SnippetSession { // happens when being asked for (default) or when this is a secondary // cursor and the leading whitespace is different const start = snippetSelection.getStartPosition(); - if (adjustWhitespace || (idx > 0 && firstLineFirstNonWhitespace !== model.getLineFirstNonWhitespaceColumn(selection.positionLineNumber))) { - SnippetSession.adjustWhitespace(model, start, snippet); - } + SnippetSession.adjustWhitespace( + model, start, snippet, + adjustWhitespace || (idx > 0 && firstLineFirstNonWhitespace !== model.getLineFirstNonWhitespaceColumn(selection.positionLineNumber)), + true + ); snippet.resolveVariables(new CompositeSnippetVariableResolver([ modelBasedVariableResolver, - new ClipboardBasedVariableResolver(clipboardText, idx, indexedSelections.length, editor.getOption(EditorOption.multiCursorPaste) === 'spread'), + new ClipboardBasedVariableResolver(readClipboardText, idx, indexedSelections.length, editor.getOption(EditorOption.multiCursorPaste) === 'spread'), new SelectionBasedVariableResolver(model, selection), new CommentBasedVariableResolver(model), new TimeBasedVariableResolver, new WorkspaceBasedVariableResolver(workspaceService), + new RandomBasedVariableResolver, ])); const offset = model.getOffsetAt(start) + delta; diff --git a/src/vs/editor/contrib/snippet/snippetVariables.ts b/src/vs/editor/contrib/snippet/snippetVariables.ts index 4f289c2af95..09fd3ca9806 100644 --- a/src/vs/editor/contrib/snippet/snippetVariables.ts +++ b/src/vs/editor/contrib/snippet/snippetVariables.ts @@ -12,8 +12,10 @@ import { VariableResolver, Variable, Text } from 'vs/editor/contrib/snippet/snip import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { getLeadingWhitespace, commonPrefixLength, isFalsyOrWhitespace, pad, endsWith } from 'vs/base/common/strings'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; +import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ILabelService } from 'vs/platform/label/common/label'; +import { normalizeDriveLetter } from 'vs/base/common/labels'; +import { URI } from 'vs/base/common/uri'; export const KnownSnippetVariableNames: { [key: string]: true } = Object.freeze({ 'CURRENT_YEAR': true, @@ -43,6 +45,9 @@ export const KnownSnippetVariableNames: { [key: string]: true } = Object.freeze( 'BLOCK_COMMENT_END': true, 'LINE_COMMENT': true, 'WORKSPACE_NAME': true, + 'WORKSPACE_FOLDER': true, + 'RANDOM': true, + 'RANDOM_HEX': true, }); export class CompositeSnippetVariableResolver implements VariableResolver { @@ -164,10 +169,14 @@ export class ModelBasedVariableResolver implements VariableResolver { } } +export interface IReadClipboardText { + (): string | undefined; +} + export class ClipboardBasedVariableResolver implements VariableResolver { constructor( - private readonly _clipboardText: string | undefined, + private readonly _readClipboardText: IReadClipboardText, private readonly _selectionIdx: number, private readonly _selectionCount: number, private readonly _spread: boolean @@ -180,7 +189,8 @@ export class ClipboardBasedVariableResolver implements VariableResolver { return undefined; } - if (!this._clipboardText) { + const clipboardText = this._readClipboardText(); + if (!clipboardText) { return undefined; } @@ -188,12 +198,12 @@ export class ClipboardBasedVariableResolver implements VariableResolver { // text whenever there the line count equals the cursor count // and when enabled if (this._spread) { - const lines = this._clipboardText.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); + const lines = clipboardText.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); if (lines.length === this._selectionCount) { return lines[this._selectionIdx]; } } - return this._clipboardText; + return clipboardText; } } export class CommentBasedVariableResolver implements VariableResolver { @@ -267,7 +277,7 @@ export class WorkspaceBasedVariableResolver implements VariableResolver { } resolve(variable: Variable): string | undefined { - if (variable.name !== 'WORKSPACE_NAME' || !this._workspaceService) { + if (!this._workspaceService) { return undefined; } @@ -276,6 +286,15 @@ export class WorkspaceBasedVariableResolver implements VariableResolver { return undefined; } + if (variable.name === 'WORKSPACE_NAME') { + return this._resolveWorkspaceName(workspaceIdentifier); + } else if (variable.name === 'WORKSPACE_FOLDER') { + return this._resoveWorkspacePath(workspaceIdentifier); + } + + return undefined; + } + private _resolveWorkspaceName(workspaceIdentifier: IWorkspaceIdentifier | URI): string | undefined { if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier)) { return path.basename(workspaceIdentifier.path); } @@ -286,4 +305,31 @@ export class WorkspaceBasedVariableResolver implements VariableResolver { } return filename; } + private _resoveWorkspacePath(workspaceIdentifier: IWorkspaceIdentifier | URI): string | undefined { + if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier)) { + return normalizeDriveLetter(workspaceIdentifier.fsPath); + } + + let filename = path.basename(workspaceIdentifier.configPath.path); + let folderpath = workspaceIdentifier.configPath.fsPath; + if (endsWith(folderpath, filename)) { + folderpath = folderpath.substr(0, folderpath.length - filename.length - 1); + } + return (folderpath ? normalizeDriveLetter(folderpath) : '/'); + } +} + +export class RandomBasedVariableResolver implements VariableResolver { + resolve(variable: Variable): string | undefined { + const { name } = variable; + + if (name === 'RANDOM') { + return Math.random().toString().slice(-6); + } + else if (name === 'RANDOM_HEX') { + return Math.random().toString(16).slice(-6); + } + + return undefined; + } } 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 c9751d0504d..05db9b1f12b 100644 --- a/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts @@ -45,7 +45,7 @@ suite('SnippetController', () => { editor.getModel()!.updateOptions({ insertSpaces: false }); - let snippetController = editor.registerAndInstantiateContribution(TestSnippetController); + let snippetController = editor.registerAndInstantiateContribution(TestSnippetController.ID, TestSnippetController); let template = [ 'for (var ${1:index}; $1 < ${2:array}.length; $1++) {', '\tvar element = $2[$1];', diff --git a/src/vs/editor/contrib/snippet/test/snippetParser.test.ts b/src/vs/editor/contrib/snippet/test/snippetParser.test.ts index f999da850bc..ba019cdc3cb 100644 --- a/src/vs/editor/contrib/snippet/test/snippetParser.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetParser.test.ts @@ -767,4 +767,17 @@ suite('SnippetParser', () => { assert.equal((variable.transform!.children[0]).ifValue, 'import { hello } from world'); assert.equal((variable.transform!.children[0]).elseValue, undefined); }); + + test('Snippet escape backslashes inside conditional insertion variable replacement #80394', function () { + + let snippet = new SnippetParser().parse('${CURRENT_YEAR/(.+)/${1:+\\\\}/}'); + let variable = snippet.children[0]; + assert.equal(snippet.children.length, 1); + assert.ok(variable instanceof Variable); + assert.ok(variable.transform); + assert.equal(variable.transform!.children.length, 1); + assert.ok(variable.transform!.children[0] instanceof FormatString); + assert.equal((variable.transform!.children[0]).ifValue, '\\'); + assert.equal((variable.transform!.children[0]).elseValue, undefined); + }); }); diff --git a/src/vs/editor/contrib/snippet/test/snippetSession.test.ts b/src/vs/editor/contrib/snippet/test/snippetSession.test.ts index 23122b2b836..d4ae07a4a49 100644 --- a/src/vs/editor/contrib/snippet/test/snippetSession.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetSession.test.ts @@ -41,7 +41,7 @@ suite('SnippetSession', function () { function assertNormalized(position: IPosition, input: string, expected: string): void { const snippet = new SnippetParser().parse(input); - SnippetSession.adjustWhitespace(model, position, snippet); + SnippetSession.adjustWhitespace(model, position, snippet, true, true); assert.equal(snippet.toTextmateString(), expected); } diff --git a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts index 0189cc0de2e..06eb5f8777c 100644 --- a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts @@ -236,28 +236,28 @@ suite('Snippet Variables Resolver', function () { test('Add variable to insert value from clipboard to a snippet #40153', function () { - assertVariableResolve(new ClipboardBasedVariableResolver(undefined, 1, 0, true), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(() => undefined, 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver(null!, 1, 0, true), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(() => null!, 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('', 1, 0, true), 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(() => '', 1, 0, true), 'CLIPBOARD', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'CLIPBOARD', 'foo'); + assertVariableResolve(new ClipboardBasedVariableResolver(() => 'foo', 1, 0, true), 'CLIPBOARD', 'foo'); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'foo', undefined); - assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0, true), 'cLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(() => 'foo', 1, 0, true), 'foo', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(() => 'foo', 1, 0, true), 'cLIPBOARD', undefined); }); test('Add variable to insert value from clipboard to a snippet #40153', function () { - assertVariableResolve(new ClipboardBasedVariableResolver('line1', 1, 2, true), 'CLIPBOARD', 'line1'); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2\nline3', 1, 2, true), 'CLIPBOARD', 'line1\nline2\nline3'); + assertVariableResolve(new ClipboardBasedVariableResolver(() => 'line1', 1, 2, true), 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver(() => 'line1\nline2\nline3', 1, 2, true), 'CLIPBOARD', 'line1\nline2\nline3'); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 1, 2, true), 'CLIPBOARD', 'line2'); - resolver = new ClipboardBasedVariableResolver('line1\nline2', 0, 2, true); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2, true), 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver(() => 'line1\nline2', 1, 2, true), 'CLIPBOARD', 'line2'); + resolver = new ClipboardBasedVariableResolver(() => 'line1\nline2', 0, 2, true); + assertVariableResolve(new ClipboardBasedVariableResolver(() => 'line1\nline2', 0, 2, true), 'CLIPBOARD', 'line1'); - assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2, false), 'CLIPBOARD', 'line1\nline2'); + assertVariableResolve(new ClipboardBasedVariableResolver(() => 'line1\nline2', 0, 2, false), 'CLIPBOARD', 'line1\nline2'); }); @@ -296,7 +296,7 @@ suite('Snippet Variables Resolver', function () { assert.equal(snippet.toString(), 'It is not line 10'); }); - test('Add workspace name variable for snippets #68261', function () { + test('Add workspace name and folder variables for snippets #68261', function () { let workspace: IWorkspace; let resolver: VariableResolver; @@ -319,14 +319,21 @@ suite('Snippet Variables Resolver', function () { // empty workspace workspace = new Workspace(''); assertVariableResolve(resolver, 'WORKSPACE_NAME', undefined); + assertVariableResolve(resolver, 'WORKSPACE_FOLDER', undefined); // single folder workspace without config workspace = new Workspace('', [toWorkspaceFolder(URI.file('/folderName'))]); assertVariableResolve(resolver, 'WORKSPACE_NAME', 'folderName'); + if (!isWindows) { + assertVariableResolve(resolver, 'WORKSPACE_FOLDER', '/folderName'); + } // workspace with config const workspaceConfigPath = URI.file('testWorkspace.code-workspace'); workspace = new Workspace('', toWorkspaceFolders([{ path: 'folderName' }], workspaceConfigPath), workspaceConfigPath); assertVariableResolve(resolver, 'WORKSPACE_NAME', 'testWorkspace'); + if (!isWindows) { + assertVariableResolve(resolver, 'WORKSPACE_FOLDER', '/'); + } }); }); diff --git a/src/vs/editor/contrib/suggest/completionModel.ts b/src/vs/editor/contrib/suggest/completionModel.ts index f1bbdb462f7..c1349fa7935 100644 --- a/src/vs/editor/contrib/suggest/completionModel.ts +++ b/src/vs/editor/contrib/suggest/completionModel.ts @@ -160,7 +160,7 @@ export class CompletionModel { // 'word' is that remainder of the current line that we // filter and score against. In theory each suggestion uses a // different word, but in practice not - that's why we cache - const overwriteBefore = item.position.column - item.completion.range.startColumn; + const overwriteBefore = item.position.column - item.editStart.column; const wordLen = overwriteBefore + characterCountDelta - (item.position.column - this._column); if (word.length !== wordLen) { word = wordLen === 0 ? '' : leadingLineContent.slice(-wordLen); diff --git a/src/vs/editor/contrib/suggest/media/class-dark.svg b/src/vs/editor/contrib/suggest/media/class-dark.svg deleted file mode 100644 index a71e221f6bd..00000000000 --- a/src/vs/editor/contrib/suggest/media/class-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/class-light.svg b/src/vs/editor/contrib/suggest/media/class-light.svg deleted file mode 100644 index aa106f18f87..00000000000 --- a/src/vs/editor/contrib/suggest/media/class-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/close-dark.svg b/src/vs/editor/contrib/suggest/media/close-dark.svg deleted file mode 100644 index 556e2e20992..00000000000 --- a/src/vs/editor/contrib/suggest/media/close-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/close-light.svg b/src/vs/editor/contrib/suggest/media/close-light.svg deleted file mode 100644 index c84816a0324..00000000000 --- a/src/vs/editor/contrib/suggest/media/close-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/color-dark.svg b/src/vs/editor/contrib/suggest/media/color-dark.svg deleted file mode 100644 index 0914abcdbd3..00000000000 --- a/src/vs/editor/contrib/suggest/media/color-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/color-light.svg b/src/vs/editor/contrib/suggest/media/color-light.svg deleted file mode 100644 index ca089a1bf2a..00000000000 --- a/src/vs/editor/contrib/suggest/media/color-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/constant-dark.svg b/src/vs/editor/contrib/suggest/media/constant-dark.svg deleted file mode 100644 index 0e90ecafcd8..00000000000 --- a/src/vs/editor/contrib/suggest/media/constant-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/suggest/media/constant-light.svg b/src/vs/editor/contrib/suggest/media/constant-light.svg deleted file mode 100644 index 1a369c1d8aa..00000000000 --- a/src/vs/editor/contrib/suggest/media/constant-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/suggest/media/enumerator-dark.svg b/src/vs/editor/contrib/suggest/media/enumerator-dark.svg deleted file mode 100644 index 82d4ff29c44..00000000000 --- a/src/vs/editor/contrib/suggest/media/enumerator-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg b/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg deleted file mode 100644 index 23c697fdf17..00000000000 --- a/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg b/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg deleted file mode 100644 index a99045d3352..00000000000 --- a/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/enumerator-light.svg b/src/vs/editor/contrib/suggest/media/enumerator-light.svg deleted file mode 100644 index e2441a0dc16..00000000000 --- a/src/vs/editor/contrib/suggest/media/enumerator-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/event-dark.svg b/src/vs/editor/contrib/suggest/media/event-dark.svg deleted file mode 100644 index 712344d1f92..00000000000 --- a/src/vs/editor/contrib/suggest/media/event-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/event-light.svg b/src/vs/editor/contrib/suggest/media/event-light.svg deleted file mode 100644 index 712344d1f92..00000000000 --- a/src/vs/editor/contrib/suggest/media/event-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/field-dark.svg b/src/vs/editor/contrib/suggest/media/field-dark.svg deleted file mode 100644 index 15623061c5d..00000000000 --- a/src/vs/editor/contrib/suggest/media/field-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/field-light.svg b/src/vs/editor/contrib/suggest/media/field-light.svg deleted file mode 100644 index 72dd79504f6..00000000000 --- a/src/vs/editor/contrib/suggest/media/field-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/file-dark.svg b/src/vs/editor/contrib/suggest/media/file-dark.svg deleted file mode 100644 index 5ed5762a1f0..00000000000 --- a/src/vs/editor/contrib/suggest/media/file-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/file-light.svg b/src/vs/editor/contrib/suggest/media/file-light.svg deleted file mode 100644 index ad54e13b1b1..00000000000 --- a/src/vs/editor/contrib/suggest/media/file-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/folder-dark.svg b/src/vs/editor/contrib/suggest/media/folder-dark.svg deleted file mode 100644 index 43d454e7e5a..00000000000 --- a/src/vs/editor/contrib/suggest/media/folder-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/folder-light.svg b/src/vs/editor/contrib/suggest/media/folder-light.svg deleted file mode 100644 index 8daecdac6a3..00000000000 --- a/src/vs/editor/contrib/suggest/media/folder-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/info-dark.svg b/src/vs/editor/contrib/suggest/media/info-dark.svg deleted file mode 100644 index 3f2d84fa649..00000000000 --- a/src/vs/editor/contrib/suggest/media/info-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/info-light.svg b/src/vs/editor/contrib/suggest/media/info-light.svg deleted file mode 100644 index f25ac7c78d6..00000000000 --- a/src/vs/editor/contrib/suggest/media/info-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/interface-dark.svg b/src/vs/editor/contrib/suggest/media/interface-dark.svg deleted file mode 100644 index 6d482b2abde..00000000000 --- a/src/vs/editor/contrib/suggest/media/interface-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/interface-light.svg b/src/vs/editor/contrib/suggest/media/interface-light.svg deleted file mode 100644 index a397dd00b00..00000000000 --- a/src/vs/editor/contrib/suggest/media/interface-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/keyword-dark.svg b/src/vs/editor/contrib/suggest/media/keyword-dark.svg deleted file mode 100644 index 70ba6ea9331..00000000000 --- a/src/vs/editor/contrib/suggest/media/keyword-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/keyword-light.svg b/src/vs/editor/contrib/suggest/media/keyword-light.svg deleted file mode 100644 index fc57528a3ef..00000000000 --- a/src/vs/editor/contrib/suggest/media/keyword-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/method-dark.svg b/src/vs/editor/contrib/suggest/media/method-dark.svg deleted file mode 100644 index 970d7b61480..00000000000 --- a/src/vs/editor/contrib/suggest/media/method-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/method-light.svg b/src/vs/editor/contrib/suggest/media/method-light.svg deleted file mode 100644 index 403a9b90dd9..00000000000 --- a/src/vs/editor/contrib/suggest/media/method-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/namespace-dark.svg b/src/vs/editor/contrib/suggest/media/namespace-dark.svg deleted file mode 100644 index 9a725bb41fd..00000000000 --- a/src/vs/editor/contrib/suggest/media/namespace-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/namespace-light.svg b/src/vs/editor/contrib/suggest/media/namespace-light.svg deleted file mode 100644 index 1339da7ce21..00000000000 --- a/src/vs/editor/contrib/suggest/media/namespace-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/operator-dark.svg b/src/vs/editor/contrib/suggest/media/operator-dark.svg deleted file mode 100644 index 957f5f44f17..00000000000 --- a/src/vs/editor/contrib/suggest/media/operator-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/operator-light.svg b/src/vs/editor/contrib/suggest/media/operator-light.svg deleted file mode 100644 index bf6ed57996a..00000000000 --- a/src/vs/editor/contrib/suggest/media/operator-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/property-dark.svg b/src/vs/editor/contrib/suggest/media/property-dark.svg deleted file mode 100644 index 23e07ffa19b..00000000000 --- a/src/vs/editor/contrib/suggest/media/property-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/property-light.svg b/src/vs/editor/contrib/suggest/media/property-light.svg deleted file mode 100644 index be642dd152d..00000000000 --- a/src/vs/editor/contrib/suggest/media/property-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/reference-dark.svg b/src/vs/editor/contrib/suggest/media/reference-dark.svg deleted file mode 100644 index ed302ae1398..00000000000 --- a/src/vs/editor/contrib/suggest/media/reference-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/reference-light.svg b/src/vs/editor/contrib/suggest/media/reference-light.svg deleted file mode 100644 index 392a840c5ef..00000000000 --- a/src/vs/editor/contrib/suggest/media/reference-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/ruler-dark.svg b/src/vs/editor/contrib/suggest/media/ruler-dark.svg deleted file mode 100644 index 1957dbad34e..00000000000 --- a/src/vs/editor/contrib/suggest/media/ruler-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/ruler-light.svg b/src/vs/editor/contrib/suggest/media/ruler-light.svg deleted file mode 100644 index bc321cdffa3..00000000000 --- a/src/vs/editor/contrib/suggest/media/ruler-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/snippet-dark.svg b/src/vs/editor/contrib/suggest/media/snippet-dark.svg deleted file mode 100644 index 79799f98c26..00000000000 --- a/src/vs/editor/contrib/suggest/media/snippet-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/snippet-light.svg b/src/vs/editor/contrib/suggest/media/snippet-light.svg deleted file mode 100644 index 45fa3a001e8..00000000000 --- a/src/vs/editor/contrib/suggest/media/snippet-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/string-dark.svg b/src/vs/editor/contrib/suggest/media/string-dark.svg deleted file mode 100644 index 80fb9d6567d..00000000000 --- a/src/vs/editor/contrib/suggest/media/string-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/string-light.svg b/src/vs/editor/contrib/suggest/media/string-light.svg deleted file mode 100644 index 02a0282e906..00000000000 --- a/src/vs/editor/contrib/suggest/media/string-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/structure-dark.svg b/src/vs/editor/contrib/suggest/media/structure-dark.svg deleted file mode 100644 index 13766a5dcea..00000000000 --- a/src/vs/editor/contrib/suggest/media/structure-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/structure-light.svg b/src/vs/editor/contrib/suggest/media/structure-light.svg deleted file mode 100644 index c96bcfa61b0..00000000000 --- a/src/vs/editor/contrib/suggest/media/structure-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index b5b5519fe9c..a58882341b8 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -53,7 +53,7 @@ padding-left: 20px; } -.monaco-editor .suggest-widget > .details p > code { +.monaco-editor .suggest-widget > .details p code { font-family: var(--monaco-monospace-font); } @@ -68,12 +68,9 @@ } .monaco-editor .suggest-widget .monaco-list { - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: -moz-none; - -ms-user-select: none; - -o-user-select: none; user-select: none; + -webkit-user-select: none; + -ms-user-select: none; } /** Styles for each row in the list element **/ @@ -110,28 +107,22 @@ /** Icon styles **/ -.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore::before { + color: inherit; opacity: 0.6; - background-position: center center; - background-repeat: no-repeat; - background-size: 70%; + font-size: 14px; + margin-left: 4px; cursor: pointer; } -.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close { - background-image: url('./close-light.svg'); +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close { position: absolute; - top: 0; - right: 0; - margin-right: 5px; + top: 2px; + right: 2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { - background-image: url('./info-light.svg'); -} - -.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close:hover, +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close:hover, .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore:hover { opacity: 1; } @@ -193,45 +184,17 @@ display: none; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon { + display: flex; + align-items: center; + margin-right: 4px; +} + .monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .icon, -.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .monaco-icon-label.suggest-icon::before { +.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .suggest-icon::before { display: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.suggest-icon::before { - content: ' '; - background-repeat: no-repeat; - background-position: center; - background-size: 75%; -} - -.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-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-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-light.svg'); } - .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.customcolor .colorspan { margin: 0 0 0 0.3em; border: 0.1em solid #000; @@ -313,90 +276,3 @@ border-radius: 3px; padding: 0 0.4em; } - -/* High Contrast and Dark Theming */ - -.monaco-editor.vs-dark .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close, -.monaco-editor.hc-black .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close { - background-image: url('./close-dark.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-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-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-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-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('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-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-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-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-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-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-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-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-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-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('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('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-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('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('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('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-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-dark.svg'); } diff --git a/src/vs/editor/contrib/suggest/media/template-dark.svg b/src/vs/editor/contrib/suggest/media/template-dark.svg deleted file mode 100644 index 425ced36f0e..00000000000 --- a/src/vs/editor/contrib/suggest/media/template-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/template-light.svg b/src/vs/editor/contrib/suggest/media/template-light.svg deleted file mode 100644 index 496d8f7c85c..00000000000 --- a/src/vs/editor/contrib/suggest/media/template-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/variable-dark.svg b/src/vs/editor/contrib/suggest/media/variable-dark.svg deleted file mode 100644 index 687fcabfff5..00000000000 --- a/src/vs/editor/contrib/suggest/media/variable-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/variable-light.svg b/src/vs/editor/contrib/suggest/media/variable-light.svg deleted file mode 100644 index ede7e9434dd..00000000000 --- a/src/vs/editor/contrib/suggest/media/variable-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts index 09f1b9a4d06..d28423e1602 100644 --- a/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -31,6 +31,11 @@ export class CompletionItem { readonly resolve: (token: CancellationToken) => Promise; + // + readonly editStart: IPosition; + readonly editInsertEnd: IPosition; + readonly editReplaceEnd: IPosition; + // perf readonly labelLow: string; readonly sortTextLow?: string; @@ -54,6 +59,17 @@ export class CompletionItem { this.sortTextLow = completion.sortText && completion.sortText.toLowerCase(); this.filterTextLow = completion.filterText && completion.filterText.toLowerCase(); + // normalize ranges + if (Range.isIRange(completion.range)) { + this.editStart = new Position(completion.range.startLineNumber, completion.range.startColumn); + this.editInsertEnd = new Position(completion.range.endLineNumber, completion.range.endColumn); + this.editReplaceEnd = new Position(completion.range.endLineNumber, completion.range.endColumn); + } else { + this.editStart = new Position(completion.range.insert.startLineNumber, completion.range.insert.startColumn); + this.editInsertEnd = new Position(completion.range.insert.endLineNumber, completion.range.insert.endColumn); + this.editReplaceEnd = new Position(completion.range.replace.endLineNumber, completion.range.replace.endColumn); + } + // create the suggestion resolver const { resolveCompletionItem } = provider; if (typeof resolveCompletionItem !== 'function') { @@ -122,8 +138,12 @@ export function provideSuggestionItems( token: CancellationToken = CancellationToken.None ): Promise { - const wordUntil = model.getWordUntilPosition(position); - const defaultRange = new Range(position.lineNumber, wordUntil.startColumn, position.lineNumber, wordUntil.endColumn); + const word = model.getWordAtPosition(position); + const defaultReplaceRange = word ? new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn) : Range.fromPositions(position); + const defaultInsertRange = defaultReplaceRange.setEndPosition(position.lineNumber, position.column); + + // const wordUntil = model.getWordUntilPosition(position); + // const defaultRange = new Range(position.lineNumber, wordUntil.startColumn, position.lineNumber, wordUntil.endColumn); position = position.clone(); @@ -159,7 +179,7 @@ export function provideSuggestionItems( // fill in default range when missing if (!suggestion.range) { - suggestion.range = defaultRange; + suggestion.range = { insert: defaultInsertRange, replace: defaultReplaceRange }; } // fill in default sortText when missing if (!suggestion.sortText) { diff --git a/src/vs/editor/contrib/suggest/suggestAlternatives.ts b/src/vs/editor/contrib/suggest/suggestAlternatives.ts index e8a6ea1a338..6c9a148e618 100644 --- a/src/vs/editor/contrib/suggest/suggestAlternatives.ts +++ b/src/vs/editor/contrib/suggest/suggestAlternatives.ts @@ -11,7 +11,7 @@ import { ISelectedSuggestion } from './suggestWidget'; export class SuggestAlternatives { - static OtherSuggestions = new RawContextKey('hasOtherSuggestions', false); + static readonly OtherSuggestions = new RawContextKey('hasOtherSuggestions', false); private readonly _ckOtherSuggestions: IContextKey; diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index f29143f81dc..007b89d7203 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -19,10 +19,10 @@ import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2 import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser'; import { ISuggestMemoryService } from 'vs/editor/contrib/suggest/suggestMemory'; import * as nls from 'vs/nls'; -import { ICommandService } from 'vs/platform/commands/common/commands'; +import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { Context as SuggestContext, CompletionItem } from './suggest'; import { SuggestAlternatives } from './suggestAlternatives'; import { State, SuggestModel } from './suggestModel'; @@ -86,9 +86,16 @@ class LineSuffix { } } +const enum InsertFlags { + NoBeforeUndoStop = 1, + NoAfterUndoStop = 2, + KeepAlternativeSuggestions = 4, + AlternativeOverwriteConfig = 8 +} + export class SuggestController implements IEditorContribution { - private static readonly ID: string = 'editor.contrib.suggestController'; + public static readonly ID: string = 'editor.contrib.suggestController'; public static get(editor: ICodeEditor): SuggestController { return editor.getContribution(SuggestController.ID); @@ -115,10 +122,10 @@ export class SuggestController implements IEditorContribution { const widget = this._instantiationService.createInstance(SuggestWidget, this._editor); this._toDispose.add(widget); - this._toDispose.add(widget.onDidSelect(item => this._insertSuggestion(item, false, true), this)); + this._toDispose.add(widget.onDidSelect(item => this._insertSuggestion(item, 0), this)); // Wire up logic to accept a suggestion on certain characters - const commitCharacterController = new CommitCharacterController(this._editor, widget, item => this._insertSuggestion(item, false, true)); + const commitCharacterController = new CommitCharacterController(this._editor, widget, item => this._insertSuggestion(item, InsertFlags.NoAfterUndoStop)); this._toDispose.add(commitCharacterController); this._toDispose.add(this._model.onDidSuggest(e => { if (e.completionModel.items.length === 0) { @@ -131,7 +138,7 @@ export class SuggestController implements IEditorContribution { this._toDispose.add(widget.onDidFocus(({ item }) => { const position = this._editor.getPosition()!; - const startColumn = item.completion.range.startColumn; + const startColumn = item.editStart.column; const endColumn = position.column; let value = true; if ( @@ -210,11 +217,6 @@ export class SuggestController implements IEditorContribution { updateFromConfig(); } - - getId(): string { - return SuggestController.ID; - } - dispose(): void { this._alternatives.dispose(); this._toDispose.dispose(); @@ -223,7 +225,10 @@ export class SuggestController implements IEditorContribution { this._lineSuffix.dispose(); } - protected _insertSuggestion(event: ISelectedSuggestion | undefined, keepAlternativeSuggestions: boolean, undoStops: boolean): void { + protected _insertSuggestion( + event: ISelectedSuggestion | undefined, + flags: InsertFlags + ): void { if (!event || !event.item) { this._alternatives.getValue().reset(); this._model.cancel(); @@ -236,13 +241,13 @@ export class SuggestController implements IEditorContribution { const model = this._editor.getModel(); const modelVersionNow = model.getAlternativeVersionId(); - const { completion: suggestion, position } = event.item; - const editorColumn = this._editor.getPosition().column; - const columnDelta = editorColumn - position.column; + const { item } = event; + const { completion: suggestion, position } = item; + const columnDelta = this._editor.getPosition().column - position.column; // pushing undo stops *before* additional text edits and // *after* the main edit - if (undoStops) { + if (!(flags & InsertFlags.NoBeforeUndoStop)) { this._editor.pushUndoStop(); } @@ -251,15 +256,19 @@ export class SuggestController implements IEditorContribution { } // keep item in memory - this._memoryService.memorize(model, this._editor.getPosition(), event.item); + this._memoryService.memorize(model, this._editor.getPosition(), item); let { insertText } = suggestion; if (!(suggestion.insertTextRules! & CompletionItemInsertTextRule.InsertAsSnippet)) { insertText = SnippetParser.escape(insertText); } - const overwriteBefore = position.column - suggestion.range.startColumn; - const overwriteAfter = suggestion.range.endColumn - position.column; + const overwriteConfig = flags & InsertFlags.AlternativeOverwriteConfig + ? !this._editor.getOption(EditorOption.suggest).overwriteOnAccept + : this._editor.getOption(EditorOption.suggest).overwriteOnAccept; + + const overwriteBefore = position.column - item.editStart.column; + const overwriteAfter = (overwriteConfig ? item.editReplaceEnd.column : item.editInsertEnd.column) - position.column; const suffixDelta = this._lineSuffix.value ? this._lineSuffix.value.delta(this._editor.getPosition()) : 0; SnippetController2.get(this._editor).insert(insertText, { @@ -270,7 +279,7 @@ export class SuggestController implements IEditorContribution { adjustWhitespace: !(suggestion.insertTextRules! & CompletionItemInsertTextRule.KeepWhitespace) }); - if (undoStops) { + if (!(flags & InsertFlags.NoAfterUndoStop)) { this._editor.pushUndoStop(); } @@ -291,7 +300,7 @@ export class SuggestController implements IEditorContribution { this._model.cancel(); } - if (keepAlternativeSuggestions) { + if (flags & InsertFlags.KeepAlternativeSuggestions) { this._alternatives.getValue().set(event, next => { // this is not so pretty. when inserting the 'next' // suggestion we undo until we are at the state at @@ -300,7 +309,10 @@ export class SuggestController implements IEditorContribution { if (modelVersionNow !== model.getAlternativeVersionId()) { model.undo(); } - this._insertSuggestion(next, false, false); + this._insertSuggestion( + next, + InsertFlags.NoBeforeUndoStop | InsertFlags.NoAfterUndoStop | (flags & InsertFlags.AlternativeOverwriteConfig ? InsertFlags.AlternativeOverwriteConfig : 0) + ); break; } }); @@ -343,7 +355,7 @@ export class SuggestController implements IEditorContribution { return true; } const position = this._editor.getPosition()!; - const startColumn = item.completion.range.startColumn; + const startColumn = item.editStart.column; const endColumn = position.column; if (endColumn - startColumn !== item.completion.insertText.length) { // unequal lengths -> makes edit @@ -382,7 +394,7 @@ export class SuggestController implements IEditorContribution { return; } this._editor.pushUndoStop(); - this._insertSuggestion({ index, item, model: completionModel }, true, false); + this._insertSuggestion({ index, item, model: completionModel }, InsertFlags.KeepAlternativeSuggestions | InsertFlags.NoBeforeUndoStop | InsertFlags.NoAfterUndoStop); }, undefined, listener); }); @@ -392,9 +404,16 @@ export class SuggestController implements IEditorContribution { this._editor.focus(); } - acceptSelectedSuggestion(keepAlternativeSuggestions?: boolean): void { + acceptSelectedSuggestion(keepAlternativeSuggestions: boolean, alternativeOverwriteConfig: boolean): void { const item = this._widget.getValue().getFocusedItem(); - this._insertSuggestion(item, !!keepAlternativeSuggestions, true); + let flags = 0; + if (keepAlternativeSuggestions) { + flags |= InsertFlags.KeepAlternativeSuggestions; + } + if (alternativeOverwriteConfig) { + flags |= InsertFlags.AlternativeOverwriteConfig; + } + this._insertSuggestion(item, flags); } acceptNextSuggestion() { @@ -478,7 +497,7 @@ export class TriggerSuggestAction extends EditorAction { } } -registerEditorContribution(SuggestController); +registerEditorContribution(SuggestController.ID, SuggestController); registerEditorAction(TriggerSuggestAction); const weight = KeybindingWeight.EditorContrib + 90; @@ -489,24 +508,43 @@ const SuggestCommand = EditorCommand.bindToContribution(Sugge registerEditorCommand(new SuggestCommand({ id: 'acceptSelectedSuggestion', precondition: SuggestContext.Visible, - handler: x => x.acceptSelectedSuggestion(true), - kbOpts: { - weight: weight, - kbExpr: EditorContextKeys.textInputFocus, - primary: KeyCode.Tab + handler(x, args) { + const alternative: boolean = typeof args === 'object' && typeof args.alternative === 'boolean' + ? args.alternative + : false; + x.acceptSelectedSuggestion(true, alternative); } })); -registerEditorCommand(new SuggestCommand({ - id: 'acceptSelectedSuggestionOnEnter', - precondition: SuggestContext.Visible, - handler: x => x.acceptSelectedSuggestion(false), - kbOpts: { - weight: weight, - kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, SuggestContext.AcceptSuggestionsOnEnter, SuggestContext.MakesTextEdit), - primary: KeyCode.Enter - } -})); +// normal tab +KeybindingsRegistry.registerKeybindingRule({ + id: 'acceptSelectedSuggestion', + when: ContextKeyExpr.and(SuggestContext.Visible, EditorContextKeys.textInputFocus), + primary: KeyCode.Tab, + weight +}); + +// accept on enter has special rules +KeybindingsRegistry.registerKeybindingRule({ + id: 'acceptSelectedSuggestion', + when: ContextKeyExpr.and(SuggestContext.Visible, EditorContextKeys.textInputFocus, SuggestContext.AcceptSuggestionsOnEnter, SuggestContext.MakesTextEdit), + primary: KeyCode.Enter, + weight +}); + +// shift+enter and shift+tab use the alternative-flag so that the suggest controller +// is doing the opposite of the editor.suggest.overwriteOnAccept-configuration +KeybindingsRegistry.registerKeybindingRule({ + id: 'acceptSelectedSuggestion', + when: ContextKeyExpr.and(SuggestContext.Visible, EditorContextKeys.textInputFocus), + primary: KeyMod.Shift | KeyCode.Tab, + secondary: [KeyMod.Shift | KeyCode.Enter], + args: { alternative: true }, + weight +}); + +// continue to support the old command +CommandsRegistry.registerCommandAlias('acceptSelectedSuggestionOnEnter', 'acceptSelectedSuggestion'); registerEditorCommand(new SuggestCommand({ id: 'hideSuggestWidget', diff --git a/src/vs/editor/contrib/suggest/suggestModel.ts b/src/vs/editor/contrib/suggest/suggestModel.ts index 8ab8749f4f0..a6b85326cfe 100644 --- a/src/vs/editor/contrib/suggest/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/suggestModel.ts @@ -13,7 +13,7 @@ import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/comm import { Position, IPosition } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; import { ITextModel, IWordAtPosition } from 'vs/editor/common/model'; -import { CompletionItemProvider, StandardTokenType, CompletionContext, CompletionProviderRegistry, CompletionTriggerKind, CompletionItemKind, completionKindFromString } from 'vs/editor/common/modes'; +import { CompletionItemProvider, StandardTokenType, CompletionContext, CompletionProviderRegistry, CompletionTriggerKind, CompletionItemKind } from 'vs/editor/common/modes'; import { CompletionModel } from './completionModel'; import { CompletionItem, getSuggestionComparator, provideSuggestionItems, getSnippetSuggestSupport, SnippetSortOrder, CompletionOptions } from './suggest'; import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; @@ -388,9 +388,7 @@ export class SuggestModel implements IDisposable { this._requestToken = new CancellationTokenSource(); // kind filter and snippet sort rules - const suggestOptions = this._editor.getOption(EditorOption.suggest); const snippetSuggestions = this._editor.getOption(EditorOption.snippetSuggestions); - let itemKindFilter = new Set(); let snippetSortOrder = SnippetSortOrder.Inline; switch (snippetSuggestions) { case 'top': @@ -403,19 +401,9 @@ export class SuggestModel implements IDisposable { case 'bottom': snippetSortOrder = SnippetSortOrder.Bottom; break; - case 'none': - itemKindFilter.add(CompletionItemKind.Snippet); - break; - } - - // kind filter - for (const key in suggestOptions.filteredTypes) { - const kind = completionKindFromString(key, true); - if (typeof kind !== 'undefined' && suggestOptions.filteredTypes[key] === false) { - itemKindFilter.add(kind); - } } + let itemKindFilter = SuggestModel._createItemKindFilter(this._editor); let wordDistance = WordDistance.create(this._editorWorker, this._editor); let items = provideSuggestionItems( @@ -467,6 +455,48 @@ export class SuggestModel implements IDisposable { }).catch(onUnexpectedError); } + private static _createItemKindFilter(editor: ICodeEditor): Set { + // kind filter and snippet sort rules + const result = new Set(); + + // snippet setting + const snippetSuggestions = editor.getOption(EditorOption.snippetSuggestions); + if (snippetSuggestions === 'none') { + result.add(CompletionItemKind.Snippet); + } + + // type setting + const suggestOptions = editor.getOption(EditorOption.suggest); + if (!suggestOptions.showMethods) { result.add(CompletionItemKind.Method); } + if (!suggestOptions.showFunctions) { result.add(CompletionItemKind.Function); } + if (!suggestOptions.showConstructors) { result.add(CompletionItemKind.Constructor); } + if (!suggestOptions.showFields) { result.add(CompletionItemKind.Field); } + if (!suggestOptions.showVariables) { result.add(CompletionItemKind.Variable); } + if (!suggestOptions.showClasses) { result.add(CompletionItemKind.Class); } + if (!suggestOptions.showStructs) { result.add(CompletionItemKind.Struct); } + if (!suggestOptions.showInterfaces) { result.add(CompletionItemKind.Interface); } + if (!suggestOptions.showModules) { result.add(CompletionItemKind.Module); } + if (!suggestOptions.showProperties) { result.add(CompletionItemKind.Property); } + if (!suggestOptions.showEvents) { result.add(CompletionItemKind.Event); } + if (!suggestOptions.showOperators) { result.add(CompletionItemKind.Operator); } + if (!suggestOptions.showUnits) { result.add(CompletionItemKind.Unit); } + if (!suggestOptions.showValues) { result.add(CompletionItemKind.Value); } + if (!suggestOptions.showConstants) { result.add(CompletionItemKind.Constant); } + if (!suggestOptions.showEnums) { result.add(CompletionItemKind.Enum); } + if (!suggestOptions.showEnumMembers) { result.add(CompletionItemKind.EnumMember); } + if (!suggestOptions.showKeywords) { result.add(CompletionItemKind.Keyword); } + if (!suggestOptions.showWords) { result.add(CompletionItemKind.Text); } + if (!suggestOptions.showColors) { result.add(CompletionItemKind.Color); } + if (!suggestOptions.showFiles) { result.add(CompletionItemKind.File); } + if (!suggestOptions.showReferences) { result.add(CompletionItemKind.Reference); } + if (!suggestOptions.showColors) { result.add(CompletionItemKind.Customcolor); } + if (!suggestOptions.showFolders) { result.add(CompletionItemKind.Folder); } + if (!suggestOptions.showTypeParameters) { result.add(CompletionItemKind.TypeParameter); } + if (!suggestOptions.showSnippets) { result.add(CompletionItemKind.Snippet); } + + return result; + } + private _onNewContext(ctx: LineContext): void { if (!this._context) { diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 67ef86871c7..b3dc600b54b 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -10,8 +10,8 @@ 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, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; -import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener, addStandardDisposableListener } from 'vs/base/browser/dom'; -import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list'; +import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener, addStandardDisposableListener, addClasses } from 'vs/base/browser/dom'; +import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent, IListGestureEvent } 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'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -48,6 +48,7 @@ interface ISuggestionTemplateData { icon: HTMLElement; colorspan: HTMLElement; iconLabel: IconLabel; + iconContainer: HTMLElement; typeLabel: HTMLElement; readMore: HTMLElement; disposables: DisposableStore; @@ -116,12 +117,14 @@ class Renderer implements IListRenderer const text = append(container, $('.contents')); const main = append(text, $('.main')); - data.iconLabel = new IconLabel(main, { supportHighlights: true, supportOcticons: true }); + data.iconContainer = append(main, $('.icon-label.codicon')); + + data.iconLabel = new IconLabel(main, { supportHighlights: true, supportCodicons: true }); data.disposables.add(data.iconLabel); data.typeLabel = append(main, $('span.type-label')); - data.readMore = append(main, $('span.readMore')); + data.readMore = append(main, $('span.readMore.codicon.codicon-info')); data.readMore.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel); const configureFont = () => { @@ -169,19 +172,21 @@ class Renderer implements IListRenderer if (suggestion.kind === CompletionItemKind.Color && extractColor(element, color)) { // special logic for 'color' completion items data.icon.className = 'icon customcolor'; + data.iconContainer.className = 'icon hide'; data.colorspan.style.backgroundColor = color[0]; } else if (suggestion.kind === CompletionItemKind.File && this._themeService.getIconTheme().hasFileIcons) { // special logic for 'file' completion items data.icon.className = 'icon hide'; - labelOptions.extraClasses = flatten([ - getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FILE), - getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FILE) - ]); + data.iconContainer.className = 'icon hide'; + const labelClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FILE); + const detailClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FILE); + labelOptions.extraClasses = labelClasses.length > detailClasses.length ? labelClasses : detailClasses; } else if (suggestion.kind === CompletionItemKind.Folder && this._themeService.getIconTheme().hasFolderIcons) { // special logic for 'folder' completion items data.icon.className = 'icon hide'; + data.iconContainer.className = 'icon hide'; labelOptions.extraClasses = flatten([ getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FOLDER), getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FOLDER) @@ -189,9 +194,8 @@ class Renderer implements IListRenderer } else { // normal icon data.icon.className = 'icon hide'; - labelOptions.extraClasses = [ - `suggest-icon ${completionKindToCssClass(suggestion.kind)}` - ]; + data.iconContainer.className = ''; + addClasses(data.iconContainer, `suggest-icon codicon codicon-symbol-${completionKindToCssClass(suggestion.kind)}`); } if (suggestion.tags && suggestion.tags.indexOf(CompletionItemTag.Deprecated) >= 0) { @@ -268,7 +272,7 @@ class SuggestionDetails { this.disposables.add(this.scrollbar); this.header = append(this.body, $('.header')); - this.close = append(this.header, $('span.close')); + this.close = append(this.header, $('span.codicon.codicon-close')); this.close.title = nls.localize('readLess', "Read less...{0}", this.triggerKeybindingLabel); this.type = append(this.header, $('p.type')); @@ -524,7 +528,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate 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.onMouseDown(e => this.onListMouseDownOrTap(e))); + this.toDispose.add(this.list.onTap(e => this.onListMouseDownOrTap(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())); @@ -572,7 +577,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate): void { + private onListMouseDownOrTap(e: IListMouseEvent | IListGestureEvent): void { if (typeof e.element === 'undefined' || typeof e.index === 'undefined') { return; } diff --git a/src/vs/editor/contrib/suggest/test/completionModel.test.ts b/src/vs/editor/contrib/suggest/test/completionModel.test.ts index c751eddb912..0f4d43d9902 100644 --- a/src/vs/editor/contrib/suggest/test/completionModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/completionModel.test.ts @@ -33,6 +33,40 @@ export function createSuggestItem(label: string, overwriteBefore: number, kind = } suite('CompletionModel', function () { + let defaultOptions = { + overwriteOnAccept: false, + snippetsPreventQuickSuggestions: true, + filterGraceful: true, + localityBonus: false, + shareSuggestSelections: false, + showIcons: true, + maxVisibleSuggestions: 12, + showMethods: true, + showFunctions: true, + showConstructors: true, + showFields: true, + showVariables: true, + showClasses: true, + showStructs: true, + showInterfaces: true, + showModules: true, + showProperties: true, + showEvents: true, + showOperators: true, + showUnits: true, + showValues: true, + showConstants: true, + showEnums: true, + showEnumMembers: true, + showKeywords: true, + showWords: true, + showColors: true, + showFiles: true, + showReferences: true, + showFolders: true, + showTypeParameters: true, + showSnippets: true, + }; let model: CompletionModel; @@ -158,15 +192,7 @@ suite('CompletionModel', function () { ], 1, { leadingLineContent: 's', characterCountDelta: 0 - }, WordDistance.None, { - snippetsPreventQuickSuggestions: true, - filterGraceful: true, - localityBonus: false, - shareSuggestSelections: false, - showIcons: true, - maxVisibleSuggestions: 12, - filteredTypes: Object.create(null) - }, 'top'); + }, WordDistance.None, defaultOptions, 'top'); assert.equal(model.items.length, 2); const [a, b] = model.items; @@ -185,15 +211,7 @@ suite('CompletionModel', function () { ], 1, { leadingLineContent: 's', characterCountDelta: 0 - }, WordDistance.None, { - snippetsPreventQuickSuggestions: true, - filterGraceful: true, - localityBonus: false, - shareSuggestSelections: false, - showIcons: true, - maxVisibleSuggestions: 12, - filteredTypes: Object.create(null) - }, 'bottom'); + }, WordDistance.None, defaultOptions, 'bottom'); assert.equal(model.items.length, 2); const [a, b] = model.items; @@ -211,15 +229,7 @@ suite('CompletionModel', function () { ], 1, { leadingLineContent: 's', characterCountDelta: 0 - }, WordDistance.None, { - snippetsPreventQuickSuggestions: true, - filterGraceful: true, - localityBonus: false, - shareSuggestSelections: false, - showIcons: true, - maxVisibleSuggestions: 12, - filteredTypes: Object.create(null) - }, 'inline'); + }, WordDistance.None, defaultOptions, 'inline'); assert.equal(model.items.length, 2); const [a, b] = model.items; diff --git a/src/vs/editor/contrib/suggest/test/suggestModel.test.ts b/src/vs/editor/contrib/suggest/test/suggestModel.test.ts index d8e629d7c03..c7e14186f2e 100644 --- a/src/vs/editor/contrib/suggest/test/suggestModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/suggestModel.test.ts @@ -59,7 +59,7 @@ function createMockEditor(model: TextModel): TestCodeEditor { }], ), }); - editor.registerAndInstantiateContribution(SnippetController2); + editor.registerAndInstantiateContribution(SnippetController2.ID, SnippetController2); return editor; } @@ -675,12 +675,12 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { return withOracle(async (sugget, editor) => { class TestCtrl extends SuggestController { - _insertSuggestion(item: ISelectedSuggestion) { - super._insertSuggestion(item, false, true); + _insertSuggestion(item: ISelectedSuggestion, flags: number = 0) { + super._insertSuggestion(item, flags); } } - const ctrl = editor.registerAndInstantiateContribution(TestCtrl); - editor.registerAndInstantiateContribution(SnippetController2); + const ctrl = editor.registerAndInstantiateContribution(TestCtrl.ID, TestCtrl); + editor.registerAndInstantiateContribution(SnippetController2.ID, SnippetController2); await assertEvent(sugget.onDidSuggest, () => { editor.setPosition({ lineNumber: 1, column: 3 }); diff --git a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts index 2ca31521aff..d3bc5b4e267 100644 --- a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts @@ -458,7 +458,7 @@ class WordHighlighter { class WordHighlighterContribution extends Disposable implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.wordHighlighter'; + public static readonly ID = 'editor.contrib.wordHighlighter'; public static get(editor: ICodeEditor): WordHighlighterContribution { return editor.getContribution(WordHighlighterContribution.ID); @@ -484,10 +484,6 @@ class WordHighlighterContribution extends Disposable implements editorCommon.IEd createWordHighlighterIfPossible(); } - public getId(): string { - return WordHighlighterContribution.ID; - } - public saveViewState(): boolean { if (this.wordHighligher && this.wordHighligher.hasDecorations()) { return true; @@ -603,7 +599,7 @@ class TriggerWordHighlightAction extends EditorAction { } } -registerEditorContribution(WordHighlighterContribution); +registerEditorContribution(WordHighlighterContribution.ID, WordHighlighterContribution); registerEditorAction(NextWordHighlightAction); registerEditorAction(PrevWordHighlightAction); registerEditorAction(TriggerWordHighlightAction); diff --git a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts index f464b2b14f3..6a0346a2137 100644 --- a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts @@ -50,11 +50,11 @@ const WIDGET_ID = 'vs.editor.contrib.zoneWidget'; export class ViewZoneDelegate implements IViewZone { - public domNode: HTMLElement; - public id: string = ''; // A valid zone id should be greater than 0 - public afterLineNumber: number; - public afterColumn: number; - public heightInLines: number; + domNode: HTMLElement; + id: string = ''; // A valid zone id should be greater than 0 + afterLineNumber: number; + afterColumn: number; + heightInLines: number; private readonly _onDomNodeTop: (top: number) => void; private readonly _onComputedHeight: (height: number) => void; @@ -71,11 +71,11 @@ export class ViewZoneDelegate implements IViewZone { this._onComputedHeight = onComputedHeight; } - public onDomNodeTop(top: number): void { + onDomNodeTop(top: number): void { this._onDomNodeTop(top); } - public onComputedHeight(height: number): void { + onComputedHeight(height: number): void { this._onComputedHeight(height); } } @@ -90,15 +90,15 @@ export class OverlayWidgetDelegate implements IOverlayWidget { this._domNode = domNode; } - public getId(): string { + getId(): string { return this._id; } - public getDomNode(): HTMLElement { + getDomNode(): HTMLElement { return this._domNode; } - public getPosition(): IOverlayWidgetPosition | null { + getPosition(): IOverlayWidgetPosition | null { return null; } } @@ -167,10 +167,10 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { protected _viewZone: ViewZoneDelegate | null = null; protected readonly _disposables = new DisposableStore(); - public container: HTMLElement | null = null; - public domNode: HTMLElement; - public editor: ICodeEditor; - public options: IOptions; + container: HTMLElement | null = null; + domNode: HTMLElement; + editor: ICodeEditor; + options: IOptions; constructor(editor: ICodeEditor, options: IOptions = {}) { @@ -191,7 +191,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { })); } - public dispose(): void { + dispose(): void { if (this._overlayWidget) { this.editor.removeOverlayWidget(this._overlayWidget); this._overlayWidget = null; @@ -212,7 +212,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this._disposables.dispose(); } - public create(): void { + create(): void { dom.addClass(this.domNode, 'zone-widget'); if (this.options.className) { @@ -231,7 +231,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this._applyStyles(); } - public style(styles: IStyles): void { + style(styles: IStyles): void { if (styles.frameColor) { this.options.frameColor = styles.frameColor; } @@ -284,7 +284,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } } - public get position(): Position | undefined { + get position(): Position | undefined { const [id] = this._positionMarkerId; if (!id) { return undefined; @@ -304,18 +304,15 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { protected _isShowing: boolean = false; - public show(rangeOrPos: IRange | IPosition, heightInLines: number): void { - const range = Range.isIRange(rangeOrPos) - ? rangeOrPos - : new Range(rangeOrPos.lineNumber, rangeOrPos.column, rangeOrPos.lineNumber, rangeOrPos.column); - + show(rangeOrPos: IRange | IPosition, heightInLines: number): void { + const range = Range.isIRange(rangeOrPos) ? Range.lift(rangeOrPos) : Range.fromPositions(rangeOrPos); this._isShowing = true; this._showImpl(range, heightInLines); this._isShowing = false; this._positionMarkerId = this.editor.deltaDecorations(this._positionMarkerId, [{ range, options: ModelDecorationOptions.EMPTY }]); } - public hide(): void { + hide(): void { if (this._viewZone) { this.editor.changeViewZones(accessor => { if (this._viewZone) { @@ -350,12 +347,8 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { return result; } - private _showImpl(where: IRange, heightInLines: number): void { - const position = { - lineNumber: where.startLineNumber, - column: where.startColumn - }; - + private _showImpl(where: Range, heightInLines: number): void { + const position = where.getStartPosition(); const layoutInfo = this.editor.getLayoutInfo(); const width = this._getWidth(layoutInfo); this.domNode.style.width = `${width}px`; @@ -432,14 +425,23 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { const model = this.editor.getModel(); if (model) { - // Reveal the line above or below the zone widget, to get the zone widget in the viewport - const revealLineNumber = Math.min(model.getLineCount(), Math.max(1, where.endLineNumber + 1)); - this.revealLine(revealLineNumber); + const revealLine = where.endLineNumber + 1; + if (revealLine <= model.getLineCount()) { + // reveal line below the zone widget + this.revealLine(revealLine, false); + } else { + // reveal last line atop + this.revealLine(model.getLineCount(), true); + } } } - protected revealLine(lineNumber: number) { - this.editor.revealLine(lineNumber, ScrollType.Smooth); + protected revealLine(lineNumber: number, isLastLine: boolean) { + if (isLastLine) { + this.editor.revealLineInCenter(lineNumber, ScrollType.Smooth); + } else { + this.editor.revealLine(lineNumber, ScrollType.Smooth); + } } protected setCssClass(className: string, classToReplace?: string): void { diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index 771d2d5fd0d..29b8a9005bf 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -23,7 +23,7 @@ import 'vs/editor/contrib/folding/folding'; import 'vs/editor/contrib/fontZoom/fontZoom'; import 'vs/editor/contrib/format/formatActions'; import 'vs/editor/contrib/goToDefinition/goToDefinitionCommands'; -import 'vs/editor/contrib/goToDefinition/goToDefinitionMouse'; +import 'vs/editor/contrib/goToDefinition/goToDefinitionAtPosition'; import 'vs/editor/contrib/gotoError/gotoError'; import 'vs/editor/contrib/hover/hover'; import 'vs/editor/contrib/inPlaceReplace/inPlaceReplace'; diff --git a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts index 1b1104e5074..ade5fe6494c 100644 --- a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts +++ b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts @@ -21,7 +21,7 @@ import { Selection } from 'vs/editor/common/core/selection'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode'; -import { IEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor'; +import { IStandaloneEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -37,7 +37,7 @@ const CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE = new RawContextKey('accessi class AccessibilityHelpController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.accessibilityHelpController'; + public static readonly ID = 'editor.contrib.accessibilityHelpController'; public static get(editor: ICodeEditor): AccessibilityHelpController { return editor.getContribution( @@ -60,10 +60,6 @@ class AccessibilityHelpController extends Disposable ); } - public getId(): string { - return AccessibilityHelpController.ID; - } - public show(): void { this._widget.show(); } @@ -164,7 +160,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_H)) { alert(AccessibilityHelpNLS.openingDocs); - let url = (this._editor.getRawOptions()).accessibilityHelpUrl; + let url = (this._editor.getRawOptions()).accessibilityHelpUrl; if (typeof url === 'undefined') { url = 'https://go.microsoft.com/fwlink/?linkid=852450'; } @@ -348,7 +344,7 @@ class ShowAccessibilityHelpAction extends EditorAction { } } -registerEditorContribution(AccessibilityHelpController); +registerEditorContribution(AccessibilityHelpController.ID, AccessibilityHelpController); registerEditorAction(ShowAccessibilityHelpAction); const AccessibilityHelpCommand = EditorCommand.bindToContribution(AccessibilityHelpController.get); diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts index 82ccd6a63f7..e67d6364b57 100644 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts @@ -14,7 +14,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class IPadShowKeyboard extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.iPadShowKeyboard'; + public static readonly ID = 'editor.contrib.iPadShowKeyboard'; private readonly editor: ICodeEditor; private widget: ShowKeyboardWidget | null; @@ -44,10 +44,6 @@ export class IPadShowKeyboard extends Disposable implements IEditorContribution } } - public getId(): string { - return IPadShowKeyboard.ID; - } - public dispose(): void { super.dispose(); if (this.widget) { @@ -103,4 +99,4 @@ class ShowKeyboardWidget extends Disposable implements IOverlayWidget { } } -registerEditorContribution(IPadShowKeyboard); +registerEditorContribution(IPadShowKeyboard.ID, IPadShowKeyboard); diff --git a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.css b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.css index 78b1b178c84..1685c5b9833 100644 --- a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.css +++ b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.css @@ -5,12 +5,9 @@ .monaco-editor .tokens-inspect-widget { z-index: 50; + user-select: text; -webkit-user-select: text; -ms-user-select: text; - -khtml-user-select: text; - -moz-user-select: text; - -o-user-select: text; - user-select: text; padding: 10px; } diff --git a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts index 47a2da412ef..3c32536b239 100644 --- a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts +++ b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts @@ -18,14 +18,14 @@ import { FontStyle, IState, ITokenizationSupport, LanguageIdentifier, StandardTo import { NULL_STATE, nullTokenize, nullTokenize2 } from 'vs/editor/common/modes/nullMode'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; -import { editorHoverBackground, editorHoverBorder } from 'vs/platform/theme/common/colorRegistry'; +import { editorHoverBackground, editorHoverBorder, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; import { HIGH_CONTRAST, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { InspectTokensNLS } from 'vs/editor/common/standaloneStrings'; class InspectTokensController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.inspectTokens'; + public static readonly ID = 'editor.contrib.inspectTokens'; public static get(editor: ICodeEditor): InspectTokensController { return editor.getContribution(InspectTokensController.ID); @@ -50,10 +50,6 @@ class InspectTokensController extends Disposable implements IEditorContribution this._register(TokenizationRegistry.onDidChange((e) => this.stop())); } - public getId(): string { - return InspectTokensController.ID; - } - public dispose(): void { this.stop(); super.dispose(); @@ -325,7 +321,7 @@ class InspectTokensWidget extends Disposable implements IContentWidget { } } -registerEditorContribution(InspectTokensController); +registerEditorContribution(InspectTokensController.ID, InspectTokensController); registerEditorAction(InspectTokens); registerThemingParticipant((theme, collector) => { @@ -339,4 +335,8 @@ registerThemingParticipant((theme, collector) => { if (background) { collector.addRule(`.monaco-editor .tokens-inspect-widget { background-color: ${background}; }`); } + const foreground = theme.getColor(editorHoverForeground); + if (foreground) { + collector.addRule(`.monaco-editor .tokens-inspect-widget { color: ${foreground}; }`); + } }); diff --git a/src/vs/editor/standalone/browser/quickOpen/editorQuickOpen.ts b/src/vs/editor/standalone/browser/quickOpen/editorQuickOpen.ts index 96bcc2ea3c4..bee2ce31a26 100644 --- a/src/vs/editor/standalone/browser/quickOpen/editorQuickOpen.ts +++ b/src/vs/editor/standalone/browser/quickOpen/editorQuickOpen.ts @@ -24,7 +24,7 @@ export interface IQuickOpenControllerOpts { export class QuickOpenController implements editorCommon.IEditorContribution, IDecorator { - private static readonly ID = 'editor.controller.quickOpenController'; + public static readonly ID = 'editor.controller.quickOpenController'; public static get(editor: ICodeEditor): QuickOpenController { return editor.getContribution(QuickOpenController.ID); @@ -39,10 +39,6 @@ export class QuickOpenController implements editorCommon.IEditorContribution, ID this.editor = editor; } - public getId(): string { - return QuickOpenController.ID; - } - public dispose(): void { // Dispose widget if (this.widget) { @@ -173,4 +169,4 @@ export interface IDecorator { clearDecorations(): void; } -registerEditorContribution(QuickOpenController); +registerEditorContribution(QuickOpenController.ID, QuickOpenController); diff --git a/src/vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts b/src/vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts index e2c2323b450..17fcaf121bf 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget.ts @@ -23,7 +23,7 @@ export class QuickOpenEditorWidget implements IOverlayWidget { private readonly codeEditor: ICodeEditor; private readonly themeService: IThemeService; - private visible: boolean; + private visible: boolean | undefined; private quickOpenWidget: QuickOpenWidget; private domNode: HTMLElement; private styler: IDisposable; @@ -31,11 +31,8 @@ export class QuickOpenEditorWidget implements IOverlayWidget { constructor(codeEditor: ICodeEditor, onOk: () => void, onCancel: () => void, onType: (value: string) => void, configuration: IQuickOpenEditorWidgetOptions, themeService: IThemeService) { this.codeEditor = codeEditor; this.themeService = themeService; + this.visible = false; - this.create(onOk, onCancel, onType, configuration); - } - - private create(onOk: () => void, onCancel: () => void, onType: (value: string) => void, configuration: IQuickOpenEditorWidgetOptions): void { this.domNode = document.createElement('div'); this.quickOpenWidget = new QuickOpenWidget( @@ -58,29 +55,29 @@ export class QuickOpenEditorWidget implements IOverlayWidget { this.codeEditor.addOverlayWidget(this); } - public setInput(model: QuickOpenModel, focus: IAutoFocus): void { + setInput(model: QuickOpenModel, focus: IAutoFocus): void { this.quickOpenWidget.setInput(model, focus); } - public getId(): string { + getId(): string { return QuickOpenEditorWidget.ID; } - public getDomNode(): HTMLElement { + getDomNode(): HTMLElement { return this.domNode; } - public destroy(): void { + destroy(): void { this.codeEditor.removeOverlayWidget(this); this.quickOpenWidget.dispose(); this.styler.dispose(); } - public isVisible(): boolean { - return this.visible; + isVisible(): boolean { + return !!this.visible; } - public show(value: string): void { + show(value: string): void { this.visible = true; const editorLayout = this.codeEditor.getLayoutInfo(); @@ -92,13 +89,13 @@ export class QuickOpenEditorWidget implements IOverlayWidget { this.codeEditor.layoutOverlayWidget(this); } - public hide(): void { + hide(): void { this.visible = false; this.quickOpenWidget.hide(); this.codeEditor.layoutOverlayWidget(this); } - public getPosition(): IOverlayWidgetPosition | null { + getPosition(): IOverlayWidgetPosition | null { if (this.visible) { return { preference: OverlayWidgetPositionPreference.TOP_CENTER @@ -107,4 +104,4 @@ export class QuickOpenEditorWidget implements IOverlayWidget { return null; } -} \ No newline at end of file +} diff --git a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts index eeeaf6f32c8..8bd72a304a2 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts @@ -15,7 +15,7 @@ import { ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editor import { IRange, Range } from 'vs/editor/common/core/range'; import { ScrollType } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { DocumentSymbol, DocumentSymbolProviderRegistry, symbolKindToCssClass } from 'vs/editor/common/modes'; +import { DocumentSymbol, DocumentSymbolProviderRegistry, SymbolKinds } from 'vs/editor/common/modes'; import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen'; import { BaseEditorQuickOpenAction, IDecorator } from 'vs/editor/standalone/browser/quickOpen/editorQuickOpen'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -198,7 +198,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction { } // Add - results.push(this.symbolEntry(label, symbolKindToCssClass(element.kind), description, element.range, highlights, editor, controller)); + results.push(this.symbolEntry(label, SymbolKinds.toCssClassName(element.kind), description, element.range, highlights, editor, controller)); } } diff --git a/src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts b/src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts index 3dcbb43537c..0739802fb78 100644 --- a/src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts +++ b/src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts @@ -37,4 +37,4 @@ export class StandaloneReferencesController extends ReferencesController { } } -registerEditorContribution(StandaloneReferencesController); +registerEditorContribution(ReferencesController.ID, StandaloneReferencesController); diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 372ceb0deab..931335a7077 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -37,7 +37,7 @@ 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, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions, NotificationsFilter } 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'; @@ -233,6 +233,8 @@ export class SimpleNotificationService implements INotificationService { public status(message: string | Error, options?: IStatusMessageOptions): IDisposable { return Disposable.None; } + + public setFilter(filter: NotificationsFilter): void { } } export class StandaloneCommandService implements ICommandService { @@ -515,12 +517,10 @@ export class SimpleResourcePropertiesService implements ITextResourcePropertiesS ) { } - getEOL(resource: URI): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files'); - if (filesConfiguration && filesConfiguration.eol) { - if (filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; - } + getEOL(resource: URI, language?: string): string { + const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource }); + if (eol && eol !== 'auto') { + return eol; } return (isLinux || isMacintosh) ? '\n' : '\r\n'; } @@ -551,7 +551,7 @@ export class SimpleWorkspaceContextService implements IWorkspaceContextService { public _serviceBrand: undefined; - private static SCHEME = 'inmemory'; + private static readonly SCHEME = 'inmemory'; private readonly _onDidChangeWorkspaceName = new Emitter(); public readonly onDidChangeWorkspaceName: Event = this._onDidChangeWorkspaceName.event; @@ -648,7 +648,9 @@ export class SimpleBulkEditService implements IBulkEditService { let totalEdits = 0; let totalFiles = 0; edits.forEach((edits, model) => { - model.applyEdits(edits.map(edit => EditOperation.replaceMove(Range.lift(edit.range), edit.text))); + model.pushStackElement(); + model.pushEditOperations([], edits.map((e) => EditOperation.replaceMove(Range.lift(e.range), e.text)), () => []); + model.pushStackElement(); totalFiles += 1; totalEdits += edits.length; }); diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 47d797f2519..86ce9f07ace 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -10,7 +10,7 @@ import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; -import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IDiffEditorOptions, IEditorOptions, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions'; import { InternalEditorAction } from 'vs/editor/common/editorAction'; import { IModelChangedEvent } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; @@ -30,6 +30,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { StandaloneCodeEditorNLS } from 'vs/editor/common/standaloneStrings'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; /** * Description of an action contribution @@ -79,7 +80,7 @@ export interface IActionDescriptor { /** * The options to create an editor. */ -export interface IEditorConstructionOptions extends IEditorOptions { +export interface IStandaloneEditorConstructionOptions extends IEditorConstructionOptions { /** * The initial model associated with this code editor. */ @@ -158,7 +159,7 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon constructor( domElement: HTMLElement, - options: IEditorConstructionOptions, + options: IStandaloneEditorConstructionOptions, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @ICommandService commandService: ICommandService, @@ -287,7 +288,7 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon constructor( domElement: HTMLElement, - options: IEditorConstructionOptions | undefined, + options: IStandaloneEditorConstructionOptions | undefined, toDispose: IDisposable, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @@ -376,6 +377,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon @INotificationService notificationService: INotificationService, @IConfigurationService configurationService: IConfigurationService, @IContextMenuService contextMenuService: IContextMenuService, + @IEditorProgressService editorProgressService: IEditorProgressService, @optional(IClipboardService) clipboardService: IClipboardService | null, ) { applyConfigurationValues(configurationService, options, true); @@ -384,7 +386,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon options.theme = themeService.setTheme(options.theme); } - super(domElement, options, clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService); + super(domElement, options, clipboardService, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService, contextMenuService, editorProgressService); this._contextViewService = contextViewService; this._configurationService = configurationService; diff --git a/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts index 2f8f7719b0c..c52be42a833 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts @@ -15,19 +15,19 @@ import { IResourceInput } from 'vs/platform/editor/common/editor'; export class StandaloneCodeEditorServiceImpl extends CodeEditorServiceImpl { - public getActiveCodeEditor(): ICodeEditor | undefined { - return undefined; // not supported in the standalone case + public getActiveCodeEditor(): ICodeEditor | null { + return null; // not supported in the standalone case } - public openCodeEditor(input: IResourceInput, source: ICodeEditor | undefined, sideBySide?: boolean): Promise { + public openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise { if (!source) { - return Promise.resolve(undefined); + return Promise.resolve(null); } return Promise.resolve(this.doOpenEditor(source, input)); } - private doOpenEditor(editor: ICodeEditor, input: IResourceInput): ICodeEditor | undefined { + private doOpenEditor(editor: ICodeEditor, input: IResourceInput): ICodeEditor | null { const model = this.findModel(editor, input.resource); if (!model) { if (input.resource) { @@ -39,7 +39,7 @@ export class StandaloneCodeEditorServiceImpl extends CodeEditorServiceImpl { return editor; } } - return undefined; + return null; } const selection = (input.options ? input.options.selection : null); diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index a9457f62a30..14fe6f67a5f 100644 --- a/src/vs/editor/standalone/browser/standaloneEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneEditor.ts @@ -24,7 +24,7 @@ import { IWebWorkerOptions, MonacoWebWorker, createWebWorker as actualCreateWebW import * as standaloneEnums from 'vs/editor/common/standalone/standaloneEnums'; import { Colorizer, IColorizerElementOptions, IColorizerOptions } from 'vs/editor/standalone/browser/colorizer'; import { SimpleEditorModelResolverService } from 'vs/editor/standalone/browser/simpleServices'; -import { IDiffEditorConstructionOptions, IEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor, StandaloneDiffEditor, StandaloneEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor'; +import { IDiffEditorConstructionOptions, IStandaloneEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor, StandaloneDiffEditor, StandaloneEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor'; import { DynamicStandaloneServices, IEditorOverrideServices, StaticServices } from 'vs/editor/standalone/browser/standaloneServices'; import { IStandaloneThemeData, IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -38,6 +38,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { clearAllFontInfos } from 'vs/editor/browser/config/configuration'; +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; type Omit = Pick>; @@ -68,7 +69,7 @@ function withAllStandaloneServices(domElement: H * `domElement` should be empty (not contain other dom nodes). * The editor will read the size of `domElement`. */ -export function create(domElement: HTMLElement, options?: IEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor { +export function create(domElement: HTMLElement, options?: IStandaloneEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor { return withAllStandaloneServices(domElement, override || {}, (services) => { return new StandaloneEditor( domElement, @@ -120,6 +121,7 @@ export function createDiffEditor(domElement: HTMLElement, options?: IDiffEditorC services.get(INotificationService), services.get(IConfigurationService), services.get(IContextMenuService), + services.get(IEditorProgressService), null ); }); diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index 984a1e23856..cabab834266 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -726,6 +726,45 @@ suite('Editor Controller - Cursor', () => { }); }); + test('combining marks', () => { + withTestCodeEditor([ + 'abcabc', + 'ãããããã', + '辻󠄀辻󠄀辻󠄀', + 'பு', + ], {}, (editor, cursor) => { + + cursor.setSelections('test', [new Selection(2, 1, 2, 1)]); + moveRight(cursor); + assertCursor(cursor, new Position(2, 3)); + moveLeft(cursor); + assertCursor(cursor, new Position(2, 1)); + + cursor.setSelections('test', [new Selection(3, 1, 3, 1)]); + moveRight(cursor); + assertCursor(cursor, new Position(3, 4)); + moveLeft(cursor); + assertCursor(cursor, new Position(3, 1)); + + cursor.setSelections('test', [new Selection(4, 1, 4, 1)]); + moveRight(cursor); + assertCursor(cursor, new Position(4, 3)); + moveLeft(cursor); + assertCursor(cursor, new Position(4, 1)); + + cursor.setSelections('test', [new Selection(1, 3, 1, 3)]); + moveDown(cursor); + assertCursor(cursor, new Position(2, 5)); + moveDown(cursor); + assertCursor(cursor, new Position(3, 4)); + moveUp(cursor); + assertCursor(cursor, new Position(2, 5)); + moveUp(cursor); + assertCursor(cursor, new Position(1, 3)); + + }); + }); + test('issue #4905 - column select is biased to the right', () => { const model = createTextModel([ 'var gulp = require("gulp");', @@ -1494,6 +1533,25 @@ suite('Editor Controller - Regression tests', () => { }); }); + test('issue #74722: Pasting whole line does not replace selection', () => { + usingCursor({ + text: [ + 'line1', + 'line sel 2', + 'line3' + ], + }, (model, cursor) => { + cursor.setSelections('test', [new Selection(2, 6, 2, 9)]); + + cursorCommand(cursor, H.Paste, { text: 'line1\n', pasteOnNewLine: true }); + + assert.equal(model.getLineContent(1), 'line1'); + assert.equal(model.getLineContent(2), 'line line1'); + assert.equal(model.getLineContent(3), ' 2'); + assert.equal(model.getLineContent(4), 'line3'); + }); + }); + test('issue #4996: Multiple cursor paste pastes contents of all cursors', () => { usingCursor({ text: [ @@ -2572,7 +2630,37 @@ suite('Editor Controller - Cursor Configuration', () => { '', ' }', ].join('\n')); - assertCursor(cursor, new Position(5, 1)); + assertCursor(cursor, new Position(4, 1)); + }); + + model.dispose(); + }); + + test('issue #40695: maintain cursor position when copying lines using ctrl+c, ctrl+v', () => { + let model = createTextModel( + [ + ' function f() {', + ' // I\'m gonna copy this line', + ' // Another line', + ' return 3;', + ' }', + ].join('\n') + ); + + withTestCodeEditor(null, { model: model }, (editor, cursor) => { + + editor.setSelections([new Selection(4, 10, 4, 10)]); + cursorCommand(cursor, H.Paste, { text: ' // I\'m gonna copy this line\n', pasteOnNewLine: true }); + + assert.equal(model.getValue(), [ + ' function f() {', + ' // I\'m gonna copy this line', + ' // Another line', + ' // I\'m gonna copy this line', + ' return 3;', + ' }', + ].join('\n')); + assertCursor(cursor, new Position(5, 10)); }); model.dispose(); @@ -4822,6 +4910,32 @@ suite('autoClosingPairs', () => { mode.dispose(); }); + test('issue #53357: Over typing ignores characters after backslash', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + 'console.log();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + + cursor.setSelections('test', [new Selection(1, 13, 1, 13)]); + + cursorCommand(cursor, H.Type, { text: '\'' }, 'keyboard'); + assert.equal(model.getValue(), 'console.log(\'\');'); + + cursorCommand(cursor, H.Type, { text: 'it' }, 'keyboard'); + assert.equal(model.getValue(), 'console.log(\'it\');'); + + cursorCommand(cursor, H.Type, { text: '\\' }, 'keyboard'); + assert.equal(model.getValue(), 'console.log(\'it\\\');'); + + cursorCommand(cursor, H.Type, { text: '\'' }, 'keyboard'); + assert.equal(model.getValue(), 'console.log(\'it\\\'\'\');'); + }); + mode.dispose(); + }); + test('issue #2773: Accents (´`¨^, others?) are inserted in the wrong position (Mac)', () => { let mode = new AutoClosingMode(); usingCursor({ @@ -4915,6 +5029,26 @@ suite('autoClosingPairs', () => { mode.dispose(); }); + test('issue #82701: auto close does not execute when IME is canceled via backspace', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '{}' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + cursor.setSelections('test', [new Selection(1, 2, 1, 2)]); + + // Typing a + backspace + cursorCommand(cursor, H.CompositionStart, null, 'keyboard'); + cursorCommand(cursor, H.Type, { text: 'a' }, 'keyboard'); + cursorCommand(cursor, H.ReplacePreviousChar, { replaceCharCnt: 1, text: '' }, 'keyboard'); + cursorCommand(cursor, H.CompositionEnd, null, 'keyboard'); + assert.equal(model.getValue(), '{}'); + }); + mode.dispose(); + }); + test('issue #20891: All cursors should do the same thing', () => { let mode = new AutoClosingMode(); usingCursor({ diff --git a/src/vs/editor/test/browser/controller/imeTester.ts b/src/vs/editor/test/browser/controller/imeTester.ts index 1dd06565c23..d5b19899b7e 100644 --- a/src/vs/editor/test/browser/controller/imeTester.ts +++ b/src/vs/editor/test/browser/controller/imeTester.ts @@ -86,8 +86,14 @@ function doCreateTest(description: string, inputStr: string, expectedStr: string let model = new SingleLineTestModel('some text'); const textAreaInputHost: ITextAreaInputHost = { - getPlainTextToCopy: (): string => '', - getHTMLToCopy: (): string => '', + getDataToCopy: () => { + return { + isFromEmptySelection: false, + multicursorText: null, + text: '', + html: undefined + }; + }, getScreenReaderContent: (currentState: TextAreaState): TextAreaState => { if (browser.isIPad) { diff --git a/src/vs/editor/test/browser/editorTestServices.ts b/src/vs/editor/test/browser/editorTestServices.ts index 5f206b7ea1e..f70b534d96e 100644 --- a/src/vs/editor/test/browser/editorTestServices.ts +++ b/src/vs/editor/test/browser/editorTestServices.ts @@ -14,10 +14,10 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti export class TestCodeEditorService extends AbstractCodeEditorService { public lastInput?: IResourceInput; - public getActiveCodeEditor(): ICodeEditor | undefined { return undefined; } - public openCodeEditor(input: IResourceInput, _source: ICodeEditor | undefined, _sideBySide?: boolean): Promise { + public getActiveCodeEditor(): ICodeEditor | null { return null; } + public openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise { this.lastInput = input; - return Promise.resolve(undefined); + return Promise.resolve(null); } public registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void { } public removeDecorationType(key: string): void { } diff --git a/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts b/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts index 0dd3c563476..962bbe2d677 100644 --- a/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts +++ b/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts @@ -15,12 +15,12 @@ import { TestTheme, TestThemeService } from 'vs/platform/theme/test/common/testT const themeServiceMock = new TestThemeService(); export class TestCodeEditorServiceImpl extends CodeEditorServiceImpl { - getActiveCodeEditor(): ICodeEditor | undefined { - return undefined; + getActiveCodeEditor(): ICodeEditor | null { + return null; } - openCodeEditor(input: IResourceInput, source: ICodeEditor | undefined, sideBySide?: boolean): Promise { - return Promise.resolve(undefined); + openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise { + return Promise.resolve(null); } } diff --git a/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts index 39a84d3acb2..c4eb0282b2c 100644 --- a/src/vs/editor/test/browser/testCodeEditor.ts +++ b/src/vs/editor/test/browser/testCodeEditor.ts @@ -29,7 +29,7 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService export class TestCodeEditor extends CodeEditorWidget implements editorBrowser.ICodeEditor { //#region testing overrides - protected _createConfiguration(options: editorOptions.IEditorOptions): editorCommon.IConfiguration { + protected _createConfiguration(options: editorOptions.IEditorConstructionOptions): editorCommon.IConfiguration { return new TestConfiguration(options); } protected _createView(viewModel: ViewModel, cursor: Cursor): [View, boolean] { @@ -42,9 +42,9 @@ export class TestCodeEditor extends CodeEditorWidget implements editorBrowser.IC public getCursor(): Cursor | undefined { return this._modelData ? this._modelData.cursor : undefined; } - public registerAndInstantiateContribution(ctor: any): T { + public registerAndInstantiateContribution(id: string, ctor: any): T { let r = this._instantiationService.createInstance(ctor, this); - this._contributions[r.getId()] = r; + this._contributions[id] = r; return r; } public dispose() { diff --git a/src/vs/editor/test/common/view/minimapCharRenderer.test.ts b/src/vs/editor/test/browser/view/minimapCharRenderer.test.ts similarity index 70% rename from src/vs/editor/test/common/view/minimapCharRenderer.test.ts rename to src/vs/editor/test/browser/view/minimapCharRenderer.test.ts index f56ebe2bca6..f45f5fa1162 100644 --- a/src/vs/editor/test/common/view/minimapCharRenderer.test.ts +++ b/src/vs/editor/test/browser/view/minimapCharRenderer.test.ts @@ -5,9 +5,8 @@ import * as assert from 'assert'; import { RGBA8 } from 'vs/editor/common/core/rgba'; -import { Constants } from 'vs/editor/common/view/minimapCharRenderer'; -import { getOrCreateMinimapCharRenderer } from 'vs/editor/common/view/runtimeMinimapCharRenderer'; -import { MinimapCharRendererFactory } from 'vs/editor/test/common/view/minimapCharRendererFactory'; +import { Constants } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet'; +import { MinimapCharRendererFactory } from 'vs/editor/browser/viewParts/minimap/minimapCharRendererFactory'; suite('MinimapCharRenderer', () => { @@ -75,11 +74,11 @@ suite('MinimapCharRenderer', () => { test('letter d @ 2x', () => { setSampleData('d'.charCodeAt(0), sampleD); - let renderer = MinimapCharRendererFactory.create(sampleData!); + let renderer = MinimapCharRendererFactory.createFromSampleData(sampleData!, 2); let background = new RGBA8(0, 0, 0, 255); let color = new RGBA8(255, 255, 255, 255); - let imageData = createFakeImageData(Constants.x2_CHAR_WIDTH, Constants.x2_CHAR_HEIGHT); + let imageData = createFakeImageData(Constants.BASE_CHAR_WIDTH * 2, Constants.BASE_CHAR_HEIGHT * 2); // set the background color for (let i = 0, len = imageData.data.length / 4; i < len; i++) { imageData.data[4 * i + 0] = background.r; @@ -87,55 +86,28 @@ suite('MinimapCharRenderer', () => { imageData.data[4 * i + 2] = background.b; imageData.data[4 * i + 3] = 255; } - renderer.x2RenderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false); + renderer.renderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false); let actual: number[] = []; for (let i = 0; i < imageData.data.length; i++) { actual[i] = imageData.data[i]; } + assert.deepEqual(actual, [ - 0x00, 0x00, 0x00, 0xFF, 0x6D, 0x6D, 0x6D, 0xFF, - 0xBB, 0xBB, 0xBB, 0xFF, 0xBE, 0xBE, 0xBE, 0xFF, - 0x94, 0x94, 0x94, 0xFF, 0x7E, 0x7E, 0x7E, 0xFF, - 0xB1, 0xB1, 0xB1, 0xFF, 0xBB, 0xBB, 0xBB, 0xFF, - ]); - }); - - test('letter d @ 2x at runtime', () => { - let renderer = getOrCreateMinimapCharRenderer(); - - let background = new RGBA8(0, 0, 0, 255); - let color = new RGBA8(255, 255, 255, 255); - let imageData = createFakeImageData(Constants.x2_CHAR_WIDTH, Constants.x2_CHAR_HEIGHT); - // set the background color - for (let i = 0, len = imageData.data.length / 4; i < len; i++) { - imageData.data[4 * i + 0] = background.r; - imageData.data[4 * i + 1] = background.g; - imageData.data[4 * i + 2] = background.b; - imageData.data[4 * i + 3] = 255; - } - - renderer.x2RenderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false); - - let actual: number[] = []; - for (let i = 0; i < imageData.data.length; i++) { - actual[i] = imageData.data[i]; - } - assert.deepEqual(actual, [ - 0x00, 0x00, 0x00, 0xFF, 0x6D, 0x6D, 0x6D, 0xFF, - 0xBB, 0xBB, 0xBB, 0xFF, 0xBE, 0xBE, 0xBE, 0xFF, - 0x94, 0x94, 0x94, 0xFF, 0x7E, 0x7E, 0x7E, 0xFF, - 0xB1, 0xB1, 0xB1, 0xFF, 0xBB, 0xBB, 0xBB, 0xFF, + 0x2E, 0x2E, 0x2E, 0xFF, 0xAD, 0xAD, 0xAD, 0xFF, + 0xC6, 0xC6, 0xC6, 0xFF, 0xC8, 0xC8, 0xC8, 0xFF, + 0xC1, 0xC1, 0xC1, 0xFF, 0xCC, 0xCC, 0xCC, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, ]); }); test('letter d @ 1x', () => { setSampleData('d'.charCodeAt(0), sampleD); - let renderer = MinimapCharRendererFactory.create(sampleData!); + let renderer = MinimapCharRendererFactory.createFromSampleData(sampleData!, 1); let background = new RGBA8(0, 0, 0, 255); let color = new RGBA8(255, 255, 255, 255); - let imageData = createFakeImageData(Constants.x1_CHAR_WIDTH, Constants.x1_CHAR_HEIGHT); + let imageData = createFakeImageData(Constants.BASE_CHAR_WIDTH, Constants.BASE_CHAR_HEIGHT); // set the background color for (let i = 0, len = imageData.data.length / 4; i < len; i++) { imageData.data[4 * i + 0] = background.r; @@ -144,42 +116,17 @@ suite('MinimapCharRenderer', () => { imageData.data[4 * i + 3] = 255; } - renderer.x1RenderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false); + renderer.renderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false); let actual: number[] = []; for (let i = 0; i < imageData.data.length; i++) { actual[i] = imageData.data[i]; } + assert.deepEqual(actual, [ - 0x55, 0x55, 0x55, 0xFF, - 0x93, 0x93, 0x93, 0xFF, + 0xCB, 0xCB, 0xCB, 0xFF, + 0x82, 0x82, 0x82, 0xFF, ]); }); - test('letter d @ 1x at runtime', () => { - let renderer = getOrCreateMinimapCharRenderer(); - - let background = new RGBA8(0, 0, 0, 255); - let color = new RGBA8(255, 255, 255, 255); - let imageData = createFakeImageData(Constants.x1_CHAR_WIDTH, Constants.x1_CHAR_HEIGHT); - // set the background color - for (let i = 0, len = imageData.data.length / 4; i < len; i++) { - imageData.data[4 * i + 0] = background.r; - imageData.data[4 * i + 1] = background.g; - imageData.data[4 * i + 2] = background.b; - imageData.data[4 * i + 3] = 255; - } - - renderer.x1RenderChar(imageData, 0, 0, 'd'.charCodeAt(0), color, background, false); - - let actual: number[] = []; - for (let i = 0; i < imageData.data.length; i++) { - actual[i] = imageData.data[i]; - } - assert.deepEqual(actual, [ - 0x55, 0x55, 0x55, 0xFF, - 0x93, 0x93, 0x93, 0xFF, - ]); - }); - -}); \ No newline at end of file +}); diff --git a/src/vs/editor/test/browser/view/minimapFontCreator.ts b/src/vs/editor/test/browser/view/minimapFontCreator.ts index afd9b17e328..b064114f722 100644 --- a/src/vs/editor/test/browser/view/minimapFontCreator.ts +++ b/src/vs/editor/test/browser/view/minimapFontCreator.ts @@ -4,31 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import { RGBA8 } from 'vs/editor/common/core/rgba'; -import { Constants, MinimapCharRenderer } from 'vs/editor/common/view/minimapCharRenderer'; -import { getOrCreateMinimapCharRenderer } from 'vs/editor/common/view/runtimeMinimapCharRenderer'; -import { MinimapCharRendererFactory } from 'vs/editor/test/common/view/minimapCharRendererFactory'; +import { MinimapCharRenderer } from 'vs/editor/browser/viewParts/minimap/minimapCharRenderer'; +import { Constants } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet'; +import { MinimapCharRendererFactory } from 'vs/editor/browser/viewParts/minimap/minimapCharRendererFactory'; -let canvas = document.getElementById('my-canvas'); -let ctx = canvas.getContext('2d')!; - -canvas.style.height = 100 + 'px'; -canvas.height = 100; - -canvas.width = Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH; -canvas.style.width = (Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH) + 'px'; - -ctx.fillStyle = '#ffffff'; -ctx.font = 'bold 16px monospace'; -for (let chCode = Constants.START_CH_CODE; chCode <= Constants.END_CH_CODE; chCode++) { - ctx.fillText(String.fromCharCode(chCode), (chCode - Constants.START_CH_CODE) * Constants.SAMPLED_CHAR_WIDTH, Constants.SAMPLED_CHAR_HEIGHT); -} - -let sampleData = ctx.getImageData(0, 4, Constants.SAMPLED_CHAR_WIDTH * Constants.CHAR_COUNT, Constants.SAMPLED_CHAR_HEIGHT); -let minimapCharRenderer = MinimapCharRendererFactory.create(sampleData.data); +let sampleData = MinimapCharRendererFactory.createSampleData('monospace'); +let minimapCharRenderer1x = MinimapCharRendererFactory.createFromSampleData(sampleData.data, 1); +let minimapCharRenderer2x = MinimapCharRendererFactory.createFromSampleData(sampleData.data, 2); +let minimapCharRenderer4x = MinimapCharRendererFactory.createFromSampleData(sampleData.data, 4); +let minimapCharRenderer6x = MinimapCharRendererFactory.createFromSampleData(sampleData.data, 6); renderImageData(sampleData, 10, 100); -renderMinimapCharRenderer(minimapCharRenderer, 400); -renderMinimapCharRenderer(getOrCreateMinimapCharRenderer(), 600); +renderMinimapCharRenderer(minimapCharRenderer1x, 400, 1); +renderMinimapCharRenderer(minimapCharRenderer2x, 500, 2); +renderMinimapCharRenderer(minimapCharRenderer4x, 600, 4); +renderMinimapCharRenderer(minimapCharRenderer6x, 750, 8); function createFakeImageData(width: number, height: number): ImageData { return { @@ -38,13 +28,15 @@ function createFakeImageData(width: number, height: number): ImageData { }; } -function renderMinimapCharRenderer(minimapCharRenderer: MinimapCharRenderer, y: number): void { - +function renderMinimapCharRenderer(minimapCharRenderer: MinimapCharRenderer, y: number, scale: number): void { let background = new RGBA8(0, 0, 0, 255); let color = new RGBA8(255, 255, 255, 255); { - let x2 = createFakeImageData(Constants.x2_CHAR_WIDTH * Constants.CHAR_COUNT, Constants.x2_CHAR_HEIGHT); + let x2 = createFakeImageData( + Constants.BASE_CHAR_WIDTH * scale * Constants.CHAR_COUNT, + Constants.BASE_CHAR_HEIGHT * scale + ); // set the background color for (let i = 0, len = x2.data.length / 4; i < len; i++) { x2.data[4 * i + 0] = background.r; @@ -54,67 +46,49 @@ function renderMinimapCharRenderer(minimapCharRenderer: MinimapCharRenderer, y: } let dx = 0; for (let chCode = Constants.START_CH_CODE; chCode <= Constants.END_CH_CODE; chCode++) { - minimapCharRenderer.x2RenderChar(x2, dx, 0, chCode, color, background, false); - dx += Constants.x2_CHAR_WIDTH; + minimapCharRenderer.renderChar(x2, dx, 0, chCode, color, background, false); + dx += Constants.BASE_CHAR_WIDTH * scale; } renderImageData(x2, 10, y); } - { - let x1 = createFakeImageData(Constants.x1_CHAR_WIDTH * Constants.CHAR_COUNT, Constants.x1_CHAR_HEIGHT); - // set the background color - for (let i = 0, len = x1.data.length / 4; i < len; i++) { - x1.data[4 * i + 0] = background.r; - x1.data[4 * i + 1] = background.g; - x1.data[4 * i + 2] = background.b; - x1.data[4 * i + 3] = 255; - } - let dx = 0; - for (let chCode = Constants.START_CH_CODE; chCode <= Constants.END_CH_CODE; chCode++) { - minimapCharRenderer.x1RenderChar(x1, dx, 0, chCode, color, background, false); - dx += Constants.x1_CHAR_WIDTH; - } - renderImageData(x1, 10, y + 100); - } } (function () { - let r = 'let x2Data = [', offset = 0; + let r = 'let x2Data = [', + offset = 0; for (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) { let charCode = charIndex + Constants.START_CH_CODE; r += '\n\n// ' + String.fromCharCode(charCode); - for (let i = 0; i < Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH; i++) { + for (let i = 0; i < Constants.BASE_CHAR_HEIGHT * 2; i++) { if (i % 2 === 0) { r += '\n'; } - r += minimapCharRenderer.x2charData[offset] + ','; + r += (minimapCharRenderer2x as any).charDataNormal[offset] + ','; offset++; } - } r += '\n\n]'; console.log(r); })(); (function () { - let r = 'let x1Data = [', offset = 0; + let r = 'let x1Data = [', + offset = 0; for (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) { let charCode = charIndex + Constants.START_CH_CODE; r += '\n\n// ' + String.fromCharCode(charCode); - for (let i = 0; i < Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH; i++) { + for (let i = 0; i < Constants.BASE_CHAR_HEIGHT * Constants.BASE_CHAR_WIDTH; i++) { r += '\n'; - r += minimapCharRenderer.x1charData[offset] + ','; + r += (minimapCharRenderer1x as any).charDataNormal[offset] + ','; offset++; } - } r += '\n\n]'; console.log(r); })(); - - function renderImageData(imageData: ImageData, left: number, top: number): void { let output = ''; let offset = 0; @@ -127,7 +101,8 @@ function renderImageData(imageData: ImageData, left: number, top: number): void let A = imageData.data[offset + 3]; offset += 4; - output += `
`; + output += `
`; } } @@ -135,8 +110,8 @@ function renderImageData(imageData: ImageData, left: number, top: number): void domNode.style.position = 'absolute'; domNode.style.top = top + 'px'; domNode.style.left = left + 'px'; - domNode.style.width = (imageData.width * PX_SIZE) + 'px'; - domNode.style.height = (imageData.height * PX_SIZE) + 'px'; + domNode.style.width = imageData.width * PX_SIZE + 'px'; + domNode.style.height = imageData.height * PX_SIZE + 'px'; domNode.style.border = '1px solid #ccc'; domNode.style.background = '#000000'; domNode.innerHTML = output; diff --git a/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts b/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts index 4f2fe8b9283..e7cd6b4b35e 100644 --- a/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts +++ b/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts @@ -168,9 +168,65 @@ suite('CursorMove', () => { testColumnFromVisibleColumn('baz', 4, 3, 4); testColumnFromVisibleColumn('📚az', 4, 0, 1); - testColumnFromVisibleColumn('📚az', 4, 1, 2); + testColumnFromVisibleColumn('📚az', 4, 1, 1); testColumnFromVisibleColumn('📚az', 4, 2, 3); testColumnFromVisibleColumn('📚az', 4, 3, 4); testColumnFromVisibleColumn('📚az', 4, 4, 5); }); -}); \ No newline at end of file + + test('toStatusbarColumn', () => { + + function t(text: string, tabSize: number, column: number, expected: number): void { + assert.equal(CursorColumns.toStatusbarColumn(text, column, tabSize), expected, `<>`); + } + + t(' spaces', 4, 1, 1); + t(' spaces', 4, 2, 2); + t(' spaces', 4, 3, 3); + t(' spaces', 4, 4, 4); + t(' spaces', 4, 5, 5); + t(' spaces', 4, 6, 6); + t(' spaces', 4, 7, 7); + t(' spaces', 4, 8, 8); + t(' spaces', 4, 9, 9); + t(' spaces', 4, 10, 10); + t(' spaces', 4, 11, 11); + + t('\ttab', 4, 1, 1); + t('\ttab', 4, 2, 5); + t('\ttab', 4, 3, 6); + t('\ttab', 4, 4, 7); + t('\ttab', 4, 5, 8); + + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 1, 1); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 2, 2); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 3, 2); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 4, 3); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 5, 3); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 6, 4); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 7, 4); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 8, 5); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 9, 5); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 10, 6); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 11, 6); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 12, 7); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 13, 7); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 14, 8); + t('𐌀𐌁𐌂𐌃𐌄𐌅𐌆', 4, 15, 8); + + t('🎈🎈🎈🎈', 4, 1, 1); + t('🎈🎈🎈🎈', 4, 2, 2); + t('🎈🎈🎈🎈', 4, 3, 2); + t('🎈🎈🎈🎈', 4, 4, 3); + t('🎈🎈🎈🎈', 4, 5, 3); + t('🎈🎈🎈🎈', 4, 6, 4); + t('🎈🎈🎈🎈', 4, 7, 4); + t('🎈🎈🎈🎈', 4, 8, 5); + t('🎈🎈🎈🎈', 4, 9, 5); + + t('何何何何', 4, 1, 1); + t('何何何何', 4, 2, 2); + t('何何何何', 4, 3, 3); + t('何何何何', 4, 4, 4); + }); +}); diff --git a/src/vs/editor/test/common/core/range.test.ts b/src/vs/editor/test/common/core/range.test.ts index 1d2d627cb32..5420ae45223 100644 --- a/src/vs/editor/test/common/core/range.test.ts +++ b/src/vs/editor/test/common/core/range.test.ts @@ -87,9 +87,9 @@ suite('Editor Core - Range', () => { b = new Range(1, 1, 1, 4); assert.ok(Range.compareRangesUsingEnds(a, b) > 0, 'a.start = b.start, a.end > b.end'); - a = new Range(1, 1, 5, 1); + a = new Range(1, 2, 5, 1); b = new Range(1, 1, 1, 4); - assert.ok(Range.compareRangesUsingEnds(a, b) > 0, 'a.start = b.start, a.end > b.end'); + assert.ok(Range.compareRangesUsingEnds(a, b) > 0, 'a.start > b.start, a.end > b.end'); }); test('containsPosition', () => { diff --git a/src/vs/editor/test/common/diff/diffComputer.test.ts b/src/vs/editor/test/common/diff/diffComputer.test.ts index 24c32a8806d..a4d574c242e 100644 --- a/src/vs/editor/test/common/diff/diffComputer.test.ts +++ b/src/vs/editor/test/common/diff/diffComputer.test.ts @@ -55,9 +55,10 @@ function assertDiff(originalLines: string[], modifiedLines: string[], expectedCh shouldComputeCharChanges, shouldPostProcessCharChanges, shouldIgnoreTrimWhitespace, - shouldMakePrettyDiff: true + shouldMakePrettyDiff: true, + maxComputationTime: 0 }); - let changes = diffComputer.computeDiff(); + let changes = diffComputer.computeDiff().changes; let extracted: IChange[] = []; for (let i = 0; i < changes.length; i++) { diff --git a/src/vs/editor/test/common/mocks/testConfiguration.ts b/src/vs/editor/test/common/mocks/testConfiguration.ts index 5da181c240d..b54f06ffc90 100644 --- a/src/vs/editor/test/common/mocks/testConfiguration.ts +++ b/src/vs/editor/test/common/mocks/testConfiguration.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; @@ -33,6 +33,7 @@ export class TestConfiguration extends CommonEditorConfiguration { fontFamily: 'mockFont', fontWeight: 'normal', fontSize: 14, + fontFeatureSettings: EditorFontLigatures.OFF, lineHeight: 19, letterSpacing: 1.5, isMonospace: true, diff --git a/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts index 0771acc14ae..ac8a659e032 100644 --- a/src/vs/editor/test/common/model/textModel.test.ts +++ b/src/vs/editor/test/common/model/textModel.test.ts @@ -743,6 +743,87 @@ suite('Editor Model - TextModel', () => { assert.deepEqual(m.validatePosition(new Position(2, 1.5)), new Position(2, 1), 'h'); }); + function assertValidatePosition(m: TextModel, lineNumber: number, column: number, expectedColumn: number): void { + const input = new Position(lineNumber, column); + const actual = m.validatePosition(input); + const expected = new Position(lineNumber, expectedColumn); + assert.deepEqual(actual, expected, `validatePosition for ${input}, got ${actual}, expected ${expected}`); + } + + function assertValidateRange(m: TextModel, input: Range, expected: Range): void { + const actual = m.validateRange(input); + assert.deepEqual(actual, expected, `validateRange for ${input}, got ${actual}, expected ${expected}`); + } + + test('combining marks', () => { + const m = TextModel.createFromString([ + 'abcabc', + 'ãããããã', + '辻󠄀辻󠄀辻󠄀', + 'புபுபு', + ].join('\n')); + + assertValidatePosition(m, 2, 1, 1); + assertValidatePosition(m, 2, 2, 1); + assertValidatePosition(m, 2, 3, 3); + assertValidatePosition(m, 2, 4, 3); + assertValidatePosition(m, 2, 5, 5); + assertValidatePosition(m, 2, 6, 5); + assertValidatePosition(m, 2, 7, 7); + assertValidatePosition(m, 2, 8, 7); + assertValidatePosition(m, 2, 9, 9); + assertValidatePosition(m, 2, 10, 9); + assertValidatePosition(m, 2, 11, 11); + assertValidatePosition(m, 2, 12, 11); + assertValidatePosition(m, 2, 13, 13); + assertValidatePosition(m, 2, 14, 13); + + assertValidatePosition(m, 3, 1, 1); + assertValidatePosition(m, 3, 2, 1); + assertValidatePosition(m, 3, 3, 1); + assertValidatePosition(m, 3, 4, 4); + assertValidatePosition(m, 3, 5, 4); + assertValidatePosition(m, 3, 6, 4); + assertValidatePosition(m, 3, 7, 7); + assertValidatePosition(m, 3, 8, 7); + assertValidatePosition(m, 3, 9, 7); + assertValidatePosition(m, 3, 10, 10); + + assertValidatePosition(m, 4, 1, 1); + assertValidatePosition(m, 4, 2, 1); + assertValidatePosition(m, 4, 3, 3); + assertValidatePosition(m, 4, 4, 3); + assertValidatePosition(m, 4, 5, 5); + assertValidatePosition(m, 4, 6, 5); + assertValidatePosition(m, 4, 7, 7); + + assertValidateRange(m, new Range(2, 1, 2, 1), new Range(2, 1, 2, 1)); + assertValidateRange(m, new Range(2, 1, 2, 2), new Range(2, 1, 2, 3)); + assertValidateRange(m, new Range(2, 1, 2, 3), new Range(2, 1, 2, 3)); + assertValidateRange(m, new Range(2, 1, 2, 4), new Range(2, 1, 2, 5)); + assertValidateRange(m, new Range(2, 1, 2, 5), new Range(2, 1, 2, 5)); + assertValidateRange(m, new Range(2, 2, 2, 2), new Range(2, 1, 2, 1)); + assertValidateRange(m, new Range(2, 2, 2, 3), new Range(2, 1, 2, 3)); + assertValidateRange(m, new Range(2, 2, 2, 4), new Range(2, 1, 2, 5)); + assertValidateRange(m, new Range(2, 2, 2, 5), new Range(2, 1, 2, 5)); + + assertValidateRange(m, new Range(3, 1, 3, 1), new Range(3, 1, 3, 1)); + assertValidateRange(m, new Range(3, 1, 3, 2), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 1, 3, 3), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 1, 3, 4), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 1, 3, 5), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 1, 3, 6), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 1, 3, 7), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 2, 3, 2), new Range(3, 1, 3, 1)); + assertValidateRange(m, new Range(3, 2, 3, 3), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 2, 3, 4), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 2, 3, 5), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 2, 3, 6), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 2, 3, 7), new Range(3, 1, 3, 7)); + + m.dispose(); + }); + test('issue #71480: validateRange handle floats', () => { 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 aa90e1c0c3f..2a55d718b50 100644 --- a/src/vs/editor/test/common/model/textModelSearch.test.ts +++ b/src/vs/editor/test/common/model/textModelSearch.test.ts @@ -721,6 +721,20 @@ suite('TextModelSearch', () => { ); }); + test('issue #65281. \w should match line break.', () => { + assertFindMatches( + [ + 'this/is{', + 'a test', + '}', + ].join('\n'), + 'this/\\w*[^}]*', true, false, null, + [ + [1, 1, 3, 1] + ] + ); + }); + test('Simple find using unicode escape sequences', () => { assertFindMatches( regularText.join('\n'), diff --git a/src/vs/editor/test/common/model/textModelWithTokens.test.ts b/src/vs/editor/test/common/model/textModelWithTokens.test.ts index ea2fc18c606..dbbcc3e0661 100644 --- a/src/vs/editor/test/common/model/textModelWithTokens.test.ts +++ b/src/vs/editor/test/common/model/textModelWithTokens.test.ts @@ -25,8 +25,8 @@ suite('TextModelWithTokens', () => { } return { range: a.range.toString(), - open: a.open, - close: a.close, + open: a.open[0], + close: a.close[0], isOpen: a.isOpen }; } @@ -57,8 +57,8 @@ suite('TextModelWithTokens', () => { let ch = lineText.charAt(charIndex); if (charIsBracket[ch]) { expectedBrackets.push({ - open: openForChar[ch], - close: closeForChar[ch], + open: [openForChar[ch]], + close: [closeForChar[ch]], isOpen: charIsOpenBracket[ch], range: new Range(lineIndex + 1, charIndex + 1, lineIndex + 1, charIndex + 2) }); @@ -145,18 +145,18 @@ suite('TextModelWithTokens', () => { }); }); +function assertIsNotBracket(model: TextModel, lineNumber: number, column: number) { + const match = model.matchBracket(new Position(lineNumber, column)); + assert.equal(match, null, 'is not matching brackets at ' + lineNumber + ', ' + column); +} + +function assertIsBracket(model: TextModel, testPosition: Position, expected: [Range, Range]): void { + const actual = model.matchBracket(testPosition); + assert.deepEqual(actual, expected, 'matches brackets at ' + testPosition); +} + suite('TextModelWithTokens - bracket matching', () => { - function isNotABracket(model: TextModel, lineNumber: number, column: number) { - let match = model.matchBracket(new Position(lineNumber, column)); - assert.equal(match, null, 'is not matching brackets at ' + lineNumber + ', ' + column); - } - - function isBracket2(model: TextModel, testPosition: Position, expected: [Range, Range]): void { - let actual = model.matchBracket(testPosition); - assert.deepEqual(actual, expected, 'matches brackets at ' + testPosition); - } - const languageIdentifier = new LanguageIdentifier('bracketMode1', LanguageId.PlainText); let registration: IDisposable; @@ -180,21 +180,21 @@ suite('TextModelWithTokens - bracket matching', () => { ')]}{[('; let model = TextModel.createFromString(text, undefined, languageIdentifier); - isNotABracket(model, 1, 1); - isNotABracket(model, 1, 2); - isNotABracket(model, 1, 3); - isBracket2(model, new Position(1, 4), [new Range(1, 4, 1, 5), new Range(2, 3, 2, 4)]); - isBracket2(model, new Position(1, 5), [new Range(1, 5, 1, 6), new Range(2, 2, 2, 3)]); - isBracket2(model, new Position(1, 6), [new Range(1, 6, 1, 7), new Range(2, 1, 2, 2)]); - isBracket2(model, new Position(1, 7), [new Range(1, 6, 1, 7), new Range(2, 1, 2, 2)]); + assertIsNotBracket(model, 1, 1); + assertIsNotBracket(model, 1, 2); + assertIsNotBracket(model, 1, 3); + assertIsBracket(model, new Position(1, 4), [new Range(1, 4, 1, 5), new Range(2, 3, 2, 4)]); + assertIsBracket(model, new Position(1, 5), [new Range(1, 5, 1, 6), new Range(2, 2, 2, 3)]); + assertIsBracket(model, new Position(1, 6), [new Range(1, 6, 1, 7), new Range(2, 1, 2, 2)]); + assertIsBracket(model, new Position(1, 7), [new Range(1, 6, 1, 7), new Range(2, 1, 2, 2)]); - isBracket2(model, new Position(2, 1), [new Range(2, 1, 2, 2), new Range(1, 6, 1, 7)]); - isBracket2(model, new Position(2, 2), [new Range(2, 2, 2, 3), new Range(1, 5, 1, 6)]); - isBracket2(model, new Position(2, 3), [new Range(2, 3, 2, 4), new Range(1, 4, 1, 5)]); - isBracket2(model, new Position(2, 4), [new Range(2, 3, 2, 4), new Range(1, 4, 1, 5)]); - isNotABracket(model, 2, 5); - isNotABracket(model, 2, 6); - isNotABracket(model, 2, 7); + assertIsBracket(model, new Position(2, 1), [new Range(2, 1, 2, 2), new Range(1, 6, 1, 7)]); + assertIsBracket(model, new Position(2, 2), [new Range(2, 2, 2, 3), new Range(1, 5, 1, 6)]); + assertIsBracket(model, new Position(2, 3), [new Range(2, 3, 2, 4), new Range(1, 4, 1, 5)]); + assertIsBracket(model, new Position(2, 4), [new Range(2, 3, 2, 4), new Range(1, 4, 1, 5)]); + assertIsNotBracket(model, 2, 5); + assertIsNotBracket(model, 2, 6); + assertIsNotBracket(model, 2, 7); model.dispose(); }); @@ -238,7 +238,7 @@ suite('TextModelWithTokens - bracket matching', () => { let isABracket: { [lineNumber: number]: { [col: number]: boolean; }; } = { 1: {}, 2: {}, 3: {}, 4: {}, 5: {} }; for (let i = 0, len = brackets.length; i < len; i++) { let [testPos, b1, b2] = brackets[i]; - isBracket2(model, testPos, [b1, b2]); + assertIsBracket(model, testPos, [b1, b2]); isABracket[testPos.lineNumber][testPos.column] = true; } @@ -246,7 +246,7 @@ suite('TextModelWithTokens - bracket matching', () => { let line = model.getLineContent(i); for (let j = 1, lenJ = line.length + 1; j <= lenJ; j++) { if (!isABracket[i].hasOwnProperty(j)) { - isNotABracket(model, i, j); + assertIsNotBracket(model, i, j); } } } @@ -255,6 +255,88 @@ suite('TextModelWithTokens - bracket matching', () => { }); }); +suite('TextModelWithTokens', () => { + + test('bracket matching 3', () => { + + const languageIdentifier = new LanguageIdentifier('bracketMode2', LanguageId.PlainText); + const registration = LanguageConfigurationRegistry.register(languageIdentifier, { + brackets: [ + ['if', 'end if'], + ['loop', 'end loop'], + ['begin', 'end'] + ], + }); + + const text = [ + 'begin', + ' loop', + ' if then', + ' end if;', + ' end loop;', + 'end;', + '', + 'begin', + ' loop', + ' if then', + ' end ifa;', + ' end loop;', + 'end;', + ].join('\n'); + + const model = TextModel.createFromString(text, undefined, languageIdentifier); + + // ... is not matched + assertIsNotBracket(model, 10, 9); + + // ... is matched + assertIsBracket(model, new Position(3, 9), [new Range(3, 9, 3, 11), new Range(4, 9, 4, 15)]); + assertIsBracket(model, new Position(4, 9), [new Range(4, 9, 4, 15), new Range(3, 9, 3, 11)]); + + // ... is matched + assertIsBracket(model, new Position(2, 5), [new Range(2, 5, 2, 9), new Range(5, 5, 5, 13)]); + assertIsBracket(model, new Position(5, 5), [new Range(5, 5, 5, 13), new Range(2, 5, 2, 9)]); + + // ... is matched + assertIsBracket(model, new Position(1, 1), [new Range(1, 1, 1, 6), new Range(6, 1, 6, 4)]); + assertIsBracket(model, new Position(6, 1), [new Range(6, 1, 6, 4), new Range(1, 1, 1, 6)]); + + model.dispose(); + registration.dispose(); + }); + + test('bracket matching 4', () => { + + const languageIdentifier = new LanguageIdentifier('bracketMode2', LanguageId.PlainText); + const registration = LanguageConfigurationRegistry.register(languageIdentifier, { + brackets: [ + ['recordbegin', 'endrecord'], + ['simplerecordbegin', 'endrecord'], + ], + }); + + const text = [ + 'recordbegin', + ' simplerecordbegin', + ' endrecord', + 'endrecord', + ].join('\n'); + + const model = TextModel.createFromString(text, undefined, languageIdentifier); + + // ... is matched + assertIsBracket(model, new Position(1, 1), [new Range(1, 1, 1, 12), new Range(4, 1, 4, 10)]); + assertIsBracket(model, new Position(4, 1), [new Range(4, 1, 4, 10), new Range(1, 1, 1, 12)]); + + // ... is matched + assertIsBracket(model, new Position(2, 3), [new Range(2, 3, 2, 20), new Range(3, 3, 3, 12)]); + assertIsBracket(model, new Position(3, 3), [new Range(3, 3, 3, 12), new Range(2, 3, 2, 20)]); + + model.dispose(); + registration.dispose(); + }); +}); + suite('TextModelWithTokens regression tests', () => { diff --git a/src/vs/editor/test/common/modes/linkComputer.test.ts b/src/vs/editor/test/common/modes/linkComputer.test.ts index b4f3b76f688..ebb5df027a5 100644 --- a/src/vs/editor/test/common/modes/linkComputer.test.ts +++ b/src/vs/editor/test/common/modes/linkComputer.test.ts @@ -202,4 +202,11 @@ suite('Editor Modes - Link Computer', () => { ' http://[::1]:5000/connect/token ' ); }); + + test('issue #70254: bold links dont open in markdown file using editor mode with ctrl + click', () => { + assertLink( + '2. Navigate to **https://portal.azure.com**', + ' https://portal.azure.com ' + ); + }); }); diff --git a/src/vs/editor/test/common/modes/supports/characterPair.test.ts b/src/vs/editor/test/common/modes/supports/characterPair.test.ts index 3f3f6880450..ed059c8a0cb 100644 --- a/src/vs/editor/test/common/modes/supports/characterPair.test.ts +++ b/src/vs/editor/test/common/modes/supports/characterPair.test.ts @@ -8,6 +8,7 @@ import { StandardTokenType } from 'vs/editor/common/modes'; import { CharacterPairSupport } from 'vs/editor/common/modes/supports/characterPair'; import { TokenText, createFakeScopedLineTokens } from 'vs/editor/test/common/modesTestUtils'; import { StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration'; +import { find } from 'vs/base/common/arrays'; suite('CharacterPairSupport', () => { @@ -53,13 +54,8 @@ suite('CharacterPairSupport', () => { assert.deepEqual(characaterPairSupport.getSurroundingPairs(), []); }); - function findAutoClosingPair(characterPairSupport: CharacterPairSupport, character: string): StandardAutoClosingPairConditional | null { - for (const autoClosingPair of characterPairSupport.getAutoClosingPairs()) { - if (autoClosingPair.open === character) { - return autoClosingPair; - } - } - return null; + function findAutoClosingPair(characterPairSupport: CharacterPairSupport, character: string): StandardAutoClosingPairConditional | undefined { + return find(characterPairSupport.getAutoClosingPairs(), autoClosingPair => autoClosingPair.open === character); } function testShouldAutoClose(characterPairSupport: CharacterPairSupport, line: TokenText[], character: string, column: number): boolean { diff --git a/src/vs/editor/test/common/modes/supports/richEditBrackets.test.ts b/src/vs/editor/test/common/modes/supports/richEditBrackets.test.ts index 3e16436412a..40ae7e628b0 100644 --- a/src/vs/editor/test/common/modes/supports/richEditBrackets.test.ts +++ b/src/vs/editor/test/common/modes/supports/richEditBrackets.test.ts @@ -9,71 +9,71 @@ import { BracketsUtils } from 'vs/editor/common/modes/supports/richEditBrackets' suite('richEditBrackets', () => { - function findPrevBracketInToken(reversedBracketRegex: RegExp, lineText: string, currentTokenStart: number, currentTokenEnd: number): Range | null { - return BracketsUtils.findPrevBracketInToken(reversedBracketRegex, 1, lineText, currentTokenStart, currentTokenEnd); + function findPrevBracketInRange(reversedBracketRegex: RegExp, lineText: string, currentTokenStart: number, currentTokenEnd: number): Range | null { + return BracketsUtils.findPrevBracketInRange(reversedBracketRegex, 1, lineText, currentTokenStart, currentTokenEnd); } - function findNextBracketInToken(forwardBracketRegex: RegExp, lineText: string, currentTokenStart: number, currentTokenEnd: number): Range | null { - return BracketsUtils.findNextBracketInToken(forwardBracketRegex, 1, lineText, currentTokenStart, currentTokenEnd); + function findNextBracketInRange(forwardBracketRegex: RegExp, lineText: string, currentTokenStart: number, currentTokenEnd: number): Range | null { + return BracketsUtils.findNextBracketInRange(forwardBracketRegex, 1, lineText, currentTokenStart, currentTokenEnd); } test('findPrevBracketInToken one char 1', () => { - let result = findPrevBracketInToken(/(\{)|(\})/i, '{', 0, 1); + let result = findPrevBracketInRange(/(\{)|(\})/i, '{', 0, 1); assert.equal(result!.startColumn, 1); assert.equal(result!.endColumn, 2); }); test('findPrevBracketInToken one char 2', () => { - let result = findPrevBracketInToken(/(\{)|(\})/i, '{{', 0, 1); + let result = findPrevBracketInRange(/(\{)|(\})/i, '{{', 0, 1); assert.equal(result!.startColumn, 1); assert.equal(result!.endColumn, 2); }); test('findPrevBracketInToken one char 3', () => { - let result = findPrevBracketInToken(/(\{)|(\})/i, '{hello world!', 0, 13); + let result = findPrevBracketInRange(/(\{)|(\})/i, '{hello world!', 0, 13); assert.equal(result!.startColumn, 1); assert.equal(result!.endColumn, 2); }); test('findPrevBracketInToken more chars 1', () => { - let result = findPrevBracketInToken(/(olleh)/i, 'hello world!', 0, 12); + let result = findPrevBracketInRange(/(olleh)/i, 'hello world!', 0, 12); assert.equal(result!.startColumn, 1); assert.equal(result!.endColumn, 6); }); test('findPrevBracketInToken more chars 2', () => { - let result = findPrevBracketInToken(/(olleh)/i, 'hello world!', 0, 5); + let result = findPrevBracketInRange(/(olleh)/i, 'hello world!', 0, 5); assert.equal(result!.startColumn, 1); assert.equal(result!.endColumn, 6); }); test('findPrevBracketInToken more chars 3', () => { - let result = findPrevBracketInToken(/(olleh)/i, ' hello world!', 0, 6); + let result = findPrevBracketInRange(/(olleh)/i, ' hello world!', 0, 6); assert.equal(result!.startColumn, 2); assert.equal(result!.endColumn, 7); }); test('findNextBracketInToken one char', () => { - let result = findNextBracketInToken(/(\{)|(\})/i, '{', 0, 1); + let result = findNextBracketInRange(/(\{)|(\})/i, '{', 0, 1); assert.equal(result!.startColumn, 1); assert.equal(result!.endColumn, 2); }); test('findNextBracketInToken more chars', () => { - let result = findNextBracketInToken(/(world)/i, 'hello world!', 0, 12); + let result = findNextBracketInRange(/(world)/i, 'hello world!', 0, 12); assert.equal(result!.startColumn, 7); assert.equal(result!.endColumn, 12); }); test('findNextBracketInToken with emoty result', () => { - let result = findNextBracketInToken(/(\{)|(\})/i, '', 0, 0); + let result = findNextBracketInRange(/(\{)|(\})/i, '', 0, 0); assert.equal(result, null); }); test('issue #3894: [Handlebars] Curly braces edit issues', () => { - let result = findPrevBracketInToken(/(\-\-!<)|(>\-\-)|(\{\{)|(\}\})/i, '{{asd}}', 0, 2); + let result = findPrevBracketInRange(/(\-\-!<)|(>\-\-)|(\{\{)|(\}\})/i, '{{asd}}', 0, 2); assert.equal(result!.startColumn, 1); assert.equal(result!.endColumn, 3); }); -}); \ No newline at end of file +}); diff --git a/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts b/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts index a8c5071cb9e..77f96fc20af 100644 --- a/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts +++ b/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts @@ -105,7 +105,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { const colorMap = [null!, '#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff']; assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 0, 17, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 0, 17, 4, true), [ '
', 'Ciao', @@ -118,7 +118,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 0, 12, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 0, 12, 4, true), [ '
', 'Ciao', @@ -131,7 +131,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 0, 11, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 0, 11, 4, true), [ '
', 'Ciao', @@ -143,7 +143,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 1, 11, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 1, 11, 4, true), [ '
', 'iao', @@ -155,7 +155,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 4, 11, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 4, 11, 4, true), [ '
', ' ', @@ -166,7 +166,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 5, 11, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 5, 11, 4, true), [ '
', 'hello', @@ -176,7 +176,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 5, 10, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 5, 10, 4, true), [ '
', 'hello', @@ -185,7 +185,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 6, 9, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 6, 9, 4, true), [ '
', 'ell', @@ -238,7 +238,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { const colorMap = [null!, '#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff']; assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 0, 21, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 0, 21, 4, true), [ '
', '  ', @@ -252,7 +252,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 0, 17, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 0, 17, 4, true), [ '
', '  ', @@ -266,7 +266,7 @@ suite('Editor Modes - textToHtmlTokenizer', () => { ); assert.equal( - tokenizeLineToHTML(text, lineTokens, colorMap, 0, 3, 4), + tokenizeLineToHTML(text, lineTokens, colorMap, 0, 3, 4, true), [ '
', '  ', diff --git a/src/vs/editor/test/common/services/editorSimpleWorker.test.ts b/src/vs/editor/test/common/services/editorSimpleWorker.test.ts index 8ea09048b02..d2aa3675d36 100644 --- a/src/vs/editor/test/common/services/editorSimpleWorker.test.ts +++ b/src/vs/editor/test/common/services/editorSimpleWorker.test.ts @@ -167,9 +167,8 @@ suite('EditorSimpleWorker', () => { assert.ok(false); return; } - const { suggestions } = result; - assert.equal(suggestions.length, 1); - assert.equal(suggestions[0].label, 'foobar'); + assert.equal(result.length, 1); + assert.equal(result, 'foobar'); }); }); diff --git a/src/vs/editor/test/common/services/modelService.test.ts b/src/vs/editor/test/common/services/modelService.test.ts index 20d3b7d3312..0a28a285b38 100644 --- a/src/vs/editor/test/common/services/modelService.test.ts +++ b/src/vs/editor/test/common/services/modelService.test.ts @@ -365,7 +365,7 @@ assertComputeEdits(file1, file2); } } -class TestTextResourcePropertiesService implements ITextResourcePropertiesService { +export class TestTextResourcePropertiesService implements ITextResourcePropertiesService { _serviceBrand: undefined; @@ -375,11 +375,9 @@ class TestTextResourcePropertiesService implements ITextResourcePropertiesServic } getEOL(resource: URI, language?: string): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files', { overrideIdentifier: language, resource }); - if (filesConfiguration && filesConfiguration.eol) { - if (filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; - } + const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource }); + if (eol && eol !== 'auto') { + return eol; } return (platform.isLinux || platform.isMacintosh) ? '\n' : '\r\n'; } diff --git a/src/vs/editor/test/common/view/minimapCharRendererFactory.ts b/src/vs/editor/test/common/view/minimapCharRendererFactory.ts deleted file mode 100644 index 43989a1e1fa..00000000000 --- a/src/vs/editor/test/common/view/minimapCharRendererFactory.ts +++ /dev/null @@ -1,172 +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 { Constants, MinimapCharRenderer } from 'vs/editor/common/view/minimapCharRenderer'; - -const enum InternalConstants { - CA_CHANNELS_CNT = 2, -} - -export class MinimapCharRendererFactory { - - public static create(source: Uint8ClampedArray): MinimapCharRenderer { - const expectedLength = (Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT); - if (source.length !== expectedLength) { - throw new Error('Unexpected source in MinimapCharRenderer'); - } - - let x2CharData = this.toGrayscale(MinimapCharRendererFactory._downsample2x(source)); - let x1CharData = this.toGrayscale(MinimapCharRendererFactory._downsample1x(source)); - return new MinimapCharRenderer(x2CharData, x1CharData); - } - - private static toGrayscale(charData: Uint8ClampedArray): Uint8ClampedArray { - let newLength = charData.length / 2; - let result = new Uint8ClampedArray(newLength); - let sourceOffset = 0; - for (let i = 0; i < newLength; i++) { - let color = charData[sourceOffset]; - let alpha = charData[sourceOffset + 1]; - let newColor = Math.round((color * alpha) / 255); - result[i] = newColor; - sourceOffset += 2; - } - return result; - } - - private static _extractSampledChar(source: Uint8ClampedArray, charIndex: number, dest: Uint8ClampedArray) { - let destOffset = 0; - for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) { - let sourceOffset = ( - Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT * i - + Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * charIndex - ); - for (let j = 0; j < Constants.SAMPLED_CHAR_WIDTH; j++) { - for (let c = 0; c < Constants.RGBA_CHANNELS_CNT; c++) { - dest[destOffset] = source[sourceOffset]; - sourceOffset++; - destOffset++; - } - } - } - } - - private static _downsample2xChar(source: Uint8ClampedArray, dest: Uint8ClampedArray): void { - // chars are 2 x 4px (width x height) - const resultLen = Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT; - const result = new Uint16Array(resultLen); - for (let i = 0; i < resultLen; i++) { - result[i] = 0; - } - - let inputOffset = 0, globalOutputOffset = 0; - for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) { - - let outputOffset = globalOutputOffset; - - let color = 0; - let alpha = 0; - for (let j = 0; j < Constants.SAMPLED_HALF_CHAR_WIDTH; j++) { - color += source[inputOffset]; // R - alpha += source[inputOffset + 3]; // A - inputOffset += Constants.RGBA_CHANNELS_CNT; - } - result[outputOffset] += color; - result[outputOffset + 1] += alpha; - outputOffset += InternalConstants.CA_CHANNELS_CNT; - - color = 0; - alpha = 0; - for (let j = 0; j < Constants.SAMPLED_HALF_CHAR_WIDTH; j++) { - color += source[inputOffset]; // R - alpha += source[inputOffset + 3]; // A - inputOffset += Constants.RGBA_CHANNELS_CNT; - } - result[outputOffset] += color; - result[outputOffset + 1] += alpha; - outputOffset += InternalConstants.CA_CHANNELS_CNT; - - if (i === 2 || i === 5 || i === 8) { - globalOutputOffset = outputOffset; - } - } - - for (let i = 0; i < resultLen; i++) { - dest[i] = result[i] / 12; // 15 it should be - } - } - - private static _downsample2x(data: Uint8ClampedArray): Uint8ClampedArray { - const resultLen = Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT * Constants.CHAR_COUNT; - const result = new Uint8ClampedArray(resultLen); - - const sampledChar = new Uint8ClampedArray(Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT); - const downsampledChar = new Uint8ClampedArray(Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT); - - for (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) { - this._extractSampledChar(data, charIndex, sampledChar); - this._downsample2xChar(sampledChar, downsampledChar); - let resultOffset = (Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT * charIndex); - for (let i = 0; i < downsampledChar.length; i++) { - result[resultOffset + i] = downsampledChar[i]; - } - } - - return result; - } - - private static _downsample1xChar(source: Uint8ClampedArray, dest: Uint8ClampedArray): void { - // chars are 1 x 2px (width x height) - const resultLen = Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT; - const result = new Uint16Array(resultLen); - for (let i = 0; i < resultLen; i++) { - result[i] = 0; - } - - let inputOffset = 0, globalOutputOffset = 0; - for (let i = 0; i < Constants.SAMPLED_CHAR_HEIGHT; i++) { - - let outputOffset = globalOutputOffset; - - let color = 0; - let alpha = 0; - for (let j = 0; j < Constants.SAMPLED_CHAR_WIDTH; j++) { - color += source[inputOffset]; // R - alpha += source[inputOffset + 3]; // A - inputOffset += Constants.RGBA_CHANNELS_CNT; - } - result[outputOffset] += color; - result[outputOffset + 1] += alpha; - outputOffset += InternalConstants.CA_CHANNELS_CNT; - - if (i === 5) { - globalOutputOffset = outputOffset; - } - } - - for (let i = 0; i < resultLen; i++) { - dest[i] = result[i] / 50; // 60 it should be - } - } - - private static _downsample1x(data: Uint8ClampedArray): Uint8ClampedArray { - const resultLen = Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT * Constants.CHAR_COUNT; - const result = new Uint8ClampedArray(resultLen); - - const sampledChar = new Uint8ClampedArray(Constants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT); - const downsampledChar = new Uint8ClampedArray(Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT); - - for (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) { - this._extractSampledChar(data, charIndex, sampledChar); - this._downsample1xChar(sampledChar, downsampledChar); - let resultOffset = (Constants.x1_CHAR_HEIGHT * Constants.x1_CHAR_WIDTH * InternalConstants.CA_CHANNELS_CNT * charIndex); - for (let i = 0; i < downsampledChar.length; i++) { - result[resultOffset + i] = downsampledChar[i]; - } - } - - return result; - } -} diff --git a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts index 793ab31cf7f..4d6e0a4fe71 100644 --- a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts +++ b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts @@ -48,7 +48,8 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { side: input.minimapSide, renderCharacters: input.minimapRenderCharacters, maxColumn: input.minimapMaxColumn, - showSlider: 'mouseover' + showSlider: 'mouseover', + scale: 1, }; options._write(EditorOption.minimap, minimapOptions); const scrollbarOptions: InternalEditorScrollbarOptions = { @@ -704,7 +705,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentWidth: 901, contentHeight: 800, - renderMinimap: RenderMinimap.Small, + renderMinimap: RenderMinimap.Text, minimapLeft: 911, minimapWidth: 89, viewportColumn: 89, @@ -762,7 +763,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentWidth: 901, contentHeight: 800, - renderMinimap: RenderMinimap.Large, + renderMinimap: RenderMinimap.Text, minimapLeft: 911, minimapWidth: 89, viewportColumn: 89, @@ -820,7 +821,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentWidth: 943, contentHeight: 800, - renderMinimap: RenderMinimap.Large, + renderMinimap: RenderMinimap.Text, minimapLeft: 953, minimapWidth: 47, viewportColumn: 94, @@ -878,7 +879,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentWidth: 943, contentHeight: 800, - renderMinimap: RenderMinimap.Large, + renderMinimap: RenderMinimap.Text, minimapLeft: 0, minimapWidth: 47, viewportColumn: 94, @@ -936,7 +937,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { contentWidth: 1026, contentHeight: 422, - renderMinimap: RenderMinimap.Large, + renderMinimap: RenderMinimap.Text, minimapLeft: 1104, minimapWidth: 83, viewportColumn: 83, diff --git a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts index e3e6ad4c22b..040629e325b 100644 --- a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts +++ b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts @@ -189,8 +189,8 @@ suite('viewLineRenderer.renderLine', () => { createPart(48, 12), ]); let expectedOutput = [ - '\u2192\u00a0\u00a0\u00a0', - '\u00b7\u00b7\u00b7\u00b7', + '\u2192\u00a0\u00a0\u00a0', + '\u00b7\u00b7\u00b7\u00b7', 'export', '\u00a0', 'class', @@ -201,8 +201,8 @@ suite('viewLineRenderer.renderLine', () => { '\u00a0', '//\u00a0', 'http://test.com', - '\u00b7\u00b7', - '\u00b7\u00b7\u00b7' + '\u00b7\u00b7', + '\u00b7\u00b7\u00b7' ].join(''); let expectedOffsetsArr = [ [0], @@ -867,10 +867,10 @@ suite('viewLineRenderer.renderLine 2', () => { null, [ '', - '\u00b7\u00b7\u00b7\u00b7', + '\u00b7\u00b7\u00b7\u00b7', 'He', 'llo\u00a0world!', - '\u00b7\u00b7\u00b7\u00b7', + '\u00b7\u00b7\u00b7\u00b7', '', ].join('') ); @@ -889,12 +889,12 @@ suite('viewLineRenderer.renderLine 2', () => { null, [ '', - '\u00b7\u00b7\u00b7\u00b7', - '\u00b7\u00b7\u00b7\u00b7', + '\u00b7\u00b7\u00b7\u00b7', + '\u00b7\u00b7\u00b7\u00b7', 'He', 'llo\u00a0world!', - '\u00b7\u00b7\u00b7\u00b7', - '\u00b7\u00b7\u00b7\u00b7', + '\u00b7\u00b7\u00b7\u00b7', + '\u00b7\u00b7\u00b7\u00b7', '', ].join('') ); @@ -913,11 +913,11 @@ suite('viewLineRenderer.renderLine 2', () => { null, [ '', - '\u2192\u00a0\u00a0\u00a0', - '\u2192\u00a0\u00a0\u00a0', + '\u2192\u00a0\u00a0\u00a0', + '\u2192\u00a0\u00a0\u00a0', 'He', 'llo\u00a0world!', - '\u2192\u00a0\u00a0\u00a0', + '\u2192\u00a0\u00a0\u00a0', '', ].join('') ); @@ -936,15 +936,15 @@ suite('viewLineRenderer.renderLine 2', () => { null, [ '', - '\u00b7\u00b7\u2192\u00a0', - '\u2192\u00a0\u00a0\u00a0', - '\u00b7\u00b7', + '\u00b7\u00b7\u2192\u00a0', + '\u2192\u00a0\u00a0\u00a0', + '\u00b7\u00b7', 'He', 'llo\u00a0world!', - '\u00b7\uffeb', - '\u00b7\u00b7\u2192\u00a0', - '\u00b7\u00b7\u00b7\uffeb', - '\u00b7\u00b7\u00b7\u00b7', + '\u00b7\uffeb', + '\u00b7\u00b7\u2192\u00a0', + '\u00b7\u00b7\u00b7\uffeb', + '\u00b7\u00b7\u00b7\u00b7', '', ].join('') ); @@ -965,13 +965,13 @@ suite('viewLineRenderer.renderLine 2', () => { [ '', '\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0', - '\u00b7\u00b7', + '\u00b7\u00b7', 'He', 'llo\u00a0world!', - '\u00b7\uffeb', - '\u00b7\u00b7\u2192\u00a0', - '\u00b7\u00b7\u00b7\uffeb', - '\u00b7\u00b7\u00b7\u00b7', + '\u00b7\uffeb', + '\u00b7\u00b7\u2192\u00a0', + '\u00b7\u00b7\u00b7\uffeb', + '\u00b7\u00b7\u00b7\u00b7', '', ].join('') ); @@ -1016,11 +1016,11 @@ suite('viewLineRenderer.renderLine 2', () => { [ '', 'it', - '\u00b7\u00b7', + '\u00b7\u00b7', 'it', '\u00a0', 'it', - '\u00b7\u00b7', + '\u00b7\u00b7', 'it', '', ].join('') @@ -1041,12 +1041,12 @@ suite('viewLineRenderer.renderLine 2', () => { null, [ '', - '\u00b7', + '\u00b7', 'Hel', 'lo', - '\u00b7', + '\u00b7', 'world!', - '\u2192\u00a0\u00a0', + '\u2192\u00a0\u00a0', '', ].join('') ); @@ -1088,12 +1088,12 @@ suite('viewLineRenderer.renderLine 2', () => { [new LineRange(0, 14)], [ '', - '\u00b7', + '\u00b7', 'Hel', 'lo', - '\u00b7', + '\u00b7', 'world!', - '\u2192\u00a0\u00a0', + '\u2192\u00a0\u00a0', '', ].join('') ); @@ -1113,7 +1113,7 @@ suite('viewLineRenderer.renderLine 2', () => { [new LineRange(0, 5)], [ '', - '\u00b7', + '\u00b7', 'Hel', 'lo', '\u00a0world!\u00a0\u00a0\u00a0', @@ -1137,11 +1137,11 @@ suite('viewLineRenderer.renderLine 2', () => { [new LineRange(0, 5), new LineRange(9, 14)], [ '', - '\u00b7', + '\u00b7', 'Hel', 'lo', '\u00a0world!', - '\u2192\u00a0\u00a0', + '\u2192\u00a0\u00a0', '', ].join('') ); @@ -1162,11 +1162,11 @@ suite('viewLineRenderer.renderLine 2', () => { [new LineRange(9, 14), new LineRange(0, 5)], [ '', - '\u00b7', + '\u00b7', 'Hel', 'lo', '\u00a0world!', - '\u2192\u00a0\u00a0', + '\u2192\u00a0\u00a0', '', ].join('') ); @@ -1184,9 +1184,9 @@ suite('viewLineRenderer.renderLine 2', () => { [new LineRange(0, 1), new LineRange(1, 2), new LineRange(2, 3)], [ '', - '\u00b7', + '\u00b7', '*', - '\u00b7', + '\u00b7', 'S', '', ].join('') @@ -1293,7 +1293,7 @@ suite('viewLineRenderer.renderLine 2', () => { let expected = [ '', - '\u2192\u00a0\u00a0\u00a0', + '\u2192\u00a0\u00a0\u00a0', 'b', 'la', '' diff --git a/src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts b/src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts index 11cc42efb8d..313c672b101 100644 --- a/src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts +++ b/src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { toUint32Array } from 'vs/editor/common/core/uint'; +import { toUint32Array } from 'vs/base/common/uint'; import { PrefixSumComputer, PrefixSumIndexOfResult } from 'vs/editor/common/viewModel/prefixSumComputer'; suite('Editor ViewModel - PrefixSumComputer', () => { diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index d57bcaecded..a8b64c4da7a 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -9,7 +9,7 @@ import { IViewLineTokens } from 'vs/editor/common/core/lineTokens'; import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; -import { toUint32Array } from 'vs/editor/common/core/uint'; +import { toUint32Array } from 'vs/base/common/uint'; import { EndOfLinePreference } from 'vs/editor/common/model'; import { TextModel } from 'vs/editor/common/model/textModel'; import * as modes from 'vs/editor/common/modes'; diff --git a/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts b/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts index 9aab952c372..099e4d4e915 100644 --- a/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts +++ b/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts @@ -103,16 +103,6 @@ suite('ViewModelDecorations', () => { // view line 2: (1,14 -> 1,24) assert.deepEqual(inlineDecorations1, [ - { - range: new Range(1, 2, 2, 1), - inlineClassName: 'i-dec2', - type: InlineDecorationType.Regular - }, - { - range: new Range(2, 1, 2, 1), - inlineClassName: 'a-dec2', - type: InlineDecorationType.After - }, { range: new Range(1, 2, 2, 2), inlineClassName: 'i-dec3', @@ -124,7 +114,7 @@ suite('ViewModelDecorations', () => { type: InlineDecorationType.After }, { - range: new Range(1, 2, 4, 1), + range: new Range(1, 2, 3, 13), inlineClassName: 'i-dec4', type: InlineDecorationType.Regular }, @@ -164,7 +154,7 @@ suite('ViewModelDecorations', () => { type: InlineDecorationType.After }, { - range: new Range(2, 1, 4, 1), + range: new Range(2, 1, 3, 13), inlineClassName: 'i-dec8', type: InlineDecorationType.Regular }, @@ -199,7 +189,7 @@ suite('ViewModelDecorations', () => { type: InlineDecorationType.After }, { - range: new Range(2, 3, 4, 1), + range: new Range(2, 3, 3, 13), inlineClassName: 'i-dec11', type: InlineDecorationType.Regular }, @@ -228,30 +218,45 @@ suite('ViewModelDecorations', () => { // view line 3 (24 -> 36) assert.deepEqual(inlineDecorations2, [ { - range: new Range(1, 2, 4, 1), + range: new Range(1, 2, 3, 13), inlineClassName: 'i-dec4', type: InlineDecorationType.Regular }, + { + range: new Range(3, 13, 3, 13), + inlineClassName: 'a-dec4', + type: InlineDecorationType.After + }, { range: new Range(1, 2, 5, 8), inlineClassName: 'i-dec5', type: InlineDecorationType.Regular }, { - range: new Range(2, 1, 4, 1), + range: new Range(2, 1, 3, 13), inlineClassName: 'i-dec8', type: InlineDecorationType.Regular }, + { + range: new Range(3, 13, 3, 13), + inlineClassName: 'a-dec8', + type: InlineDecorationType.After + }, { range: new Range(2, 1, 5, 8), inlineClassName: 'i-dec9', type: InlineDecorationType.Regular }, { - range: new Range(2, 3, 4, 1), + range: new Range(2, 3, 3, 13), inlineClassName: 'i-dec11', type: InlineDecorationType.Regular }, + { + range: new Range(3, 13, 3, 13), + inlineClassName: 'a-dec11', + type: InlineDecorationType.After + }, { range: new Range(2, 3, 5, 8), inlineClassName: 'i-dec12', diff --git a/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts b/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts index 141afb3c455..dd012520e9f 100644 --- a/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts +++ b/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts @@ -210,7 +210,7 @@ suite('ViewModel', () => { new Range(3, 2, 3, 2), ], true, - 'ine2' + ['ine2', 'line3'] ); }); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 08b3cdbadd3..72bd32cf0da 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -42,9 +42,9 @@ declare namespace monaco { export class CancellationTokenSource { constructor(parent?: CancellationToken); - readonly token: CancellationToken; + get token(): CancellationToken; cancel(): void; - dispose(): void; + dispose(cancel?: boolean): void; } export interface CancellationToken { @@ -55,7 +55,6 @@ declare namespace monaco { */ readonly onCancellationRequested: IEvent; } - /** * Uniform Resource Identifier (Uri) http://tools.ietf.org/html/rfc3986. * This class is a simple parser which creates the basic component parts @@ -118,7 +117,7 @@ declare namespace monaco { * namely the server name, would be missing. Therefore `Uri#fsPath` exists - it's sugar to ease working * with URIs that represent files on disk (`file` scheme). */ - readonly fsPath: string; + get fsPath(): string; with(change: { scheme?: string; authority?: string | null; @@ -379,8 +378,8 @@ declare namespace monaco { } export interface IMarkdownString { - value: string; - isTrusted?: boolean; + readonly value: string; + readonly isTrusted?: boolean; uris?: { [href: string]: UriComponents; }; @@ -727,10 +726,6 @@ declare namespace monaco { */ readonly positionColumn: number; constructor(selectionStartLineNumber: number, selectionStartColumn: number, positionLineNumber: number, positionColumn: number); - /** - * Clone this selection. - */ - clone(): Selection; /** * Transform to a human-readable representation. */ @@ -813,7 +808,7 @@ declare namespace monaco.editor { * `domElement` should be empty (not contain other dom nodes). * The editor will read the size of `domElement`. */ - export function create(domElement: HTMLElement, options?: IEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor; + export function create(domElement: HTMLElement, options?: IStandaloneEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor; /** * Emitted when an editor is created. @@ -1051,7 +1046,7 @@ declare namespace monaco.editor { /** * The options to create an editor. */ - export interface IEditorConstructionOptions extends IEditorOptions { + export interface IStandaloneEditorConstructionOptions extends IEditorConstructionOptions { /** * The initial model associated with this code editor. */ @@ -1556,6 +1551,11 @@ declare namespace monaco.editor { * @return The text length. */ getValueLengthInRange(range: IRange): number; + /** + * Get the character count of text in a certain range. + * @param range The range describing what text length to get. + */ + getCharacterCountInRange(range: IRange): number; /** * Get the number of lines in the model. */ @@ -2061,6 +2061,8 @@ declare namespace monaco.editor { /** * Instructs the editor to remeasure its container. This method should * be called when the container of the editor gets resized. + * + * If a dimension is passed in, the passed in value will be used. */ layout(dimension?: IDimension): void; /** @@ -2207,10 +2209,6 @@ declare namespace monaco.editor { * An editor contribution that gets created every time a new editor gets created and gets disposed when the editor gets disposed. */ export interface IEditorContribution { - /** - * Get a unique identifier for this contribution. - */ - getId(): string; /** * Dispose this contribution. */ @@ -2398,6 +2396,18 @@ declare namespace monaco.editor { * The secondary selections. */ readonly secondarySelections: Selection[]; + /** + * The model version id. + */ + readonly modelVersionId: number; + /** + * The old selections. + */ + readonly oldSelections: Selection[] | null; + /** + * The model version id the that `oldSelections` refer to. + */ + readonly oldModelVersionId: number; /** * Source of the call that caused the event. */ @@ -2472,6 +2482,12 @@ declare namespace monaco.editor { * Defaults to 0. */ cursorSurroundingLines?: number; + /** + * Controls when `cursorSurroundingLines` should be enforced + * Defaults to `default`, `cursorSurroundingLines` is not enforced when cursor position is changed + * by mouse. + */ + cursorSurroundingLinesStyle?: 'default' | 'all'; /** * Render last line number when the file ends with a newline. * Defaults to true. @@ -2538,7 +2554,7 @@ declare namespace monaco.editor { fixedOverflowWidgets?: boolean; /** * The number of vertical lanes the overview ruler should render. - * Defaults to 2. + * Defaults to 3. */ overviewRulerLanes?: number; /** @@ -2579,7 +2595,7 @@ declare namespace monaco.editor { * Enable font ligatures. * Defaults to false. */ - fontLigatures?: boolean; + fontLigatures?: boolean | string; /** * Disable the use of `will-change` for the editor margin and lines layers. * The usage of `will-change` acts as a hint for browsers to create an extra layer. @@ -2918,6 +2934,13 @@ declare namespace monaco.editor { showUnused?: boolean; } + export interface IEditorConstructionOptions extends IEditorOptions { + /** + * The initial editor dimension (to avoid measuring the container). + */ + dimension?: IDimension; + } + /** * Configuration options for the diff editor. */ @@ -2932,6 +2955,11 @@ declare namespace monaco.editor { * Defaults to true. */ renderSideBySide?: boolean; + /** + * Timeout in milliseconds after which diff computation is cancelled. + * Defaults to 5000. + */ + maxComputationTime?: number; /** * Compute the diff by ignoring leading/trailing whitespace * Defaults to true. @@ -3024,9 +3052,9 @@ declare namespace monaco.editor { */ seedSearchStringFromSelection?: boolean; /** - * Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor. + * Controls if Find in Selection flag is turned on in the editor. */ - autoFindInSelection?: boolean; + autoFindInSelection?: 'never' | 'always' | 'multiline'; addExtraSpaceOnTop?: boolean; } @@ -3091,10 +3119,8 @@ declare namespace monaco.editor { export enum RenderMinimap { None = 0, - Small = 1, - Large = 2, - SmallBlocks = 3, - LargeBlocks = 4 + Text = 1, + Blocks = 2 } /** @@ -3229,6 +3255,10 @@ declare namespace monaco.editor { * Defaults to 120. */ maxColumn?: number; + /** + * Relative size of the font in the minimap. Defaults to 1. + */ + scale?: number; } export type EditorMinimapOptions = Readonly>; @@ -3356,6 +3386,10 @@ declare namespace monaco.editor { * Configuration options for editor suggest widget */ export interface ISuggestOptions { + /** + * Overwrite word ends on accept. Default to false. + */ + overwriteOnAccept?: boolean; /** * Enable graceful matching. Defaults to true. */ @@ -3381,9 +3415,105 @@ declare namespace monaco.editor { */ maxVisibleSuggestions?: number; /** - * Names of suggestion types to filter. + * Show method-suggestions. */ - filteredTypes?: Record; + showMethods?: boolean; + /** + * Show function-suggestions. + */ + showFunctions?: boolean; + /** + * Show constructor-suggestions. + */ + showConstructors?: boolean; + /** + * Show field-suggestions. + */ + showFields?: boolean; + /** + * Show variable-suggestions. + */ + showVariables?: boolean; + /** + * Show class-suggestions. + */ + showClasses?: boolean; + /** + * Show struct-suggestions. + */ + showStructs?: boolean; + /** + * Show interface-suggestions. + */ + showInterfaces?: boolean; + /** + * Show module-suggestions. + */ + showModules?: boolean; + /** + * Show property-suggestions. + */ + showProperties?: boolean; + /** + * Show event-suggestions. + */ + showEvents?: boolean; + /** + * Show operator-suggestions. + */ + showOperators?: boolean; + /** + * Show unit-suggestions. + */ + showUnits?: boolean; + /** + * Show value-suggestions. + */ + showValues?: boolean; + /** + * Show constant-suggestions. + */ + showConstants?: boolean; + /** + * Show enum-suggestions. + */ + showEnums?: boolean; + /** + * Show enumMember-suggestions. + */ + showEnumMembers?: boolean; + /** + * Show keyword-suggestions. + */ + showKeywords?: boolean; + /** + * Show text-suggestions. + */ + showWords?: boolean; + /** + * Show color-suggestions. + */ + showColors?: boolean; + /** + * Show file-suggestions. + */ + showFiles?: boolean; + /** + * Show reference-suggestions. + */ + showReferences?: boolean; + /** + * Show folder-suggestions. + */ + showFolders?: boolean; + /** + * Show typeParameter-suggestions. + */ + showTypeParameters?: boolean; + /** + * Show snippet-suggestions. + */ + showSnippets?: boolean; } export type InternalSuggestOptions = Readonly>; @@ -4115,6 +4245,7 @@ declare namespace monaco.editor { readonly fontFamily: string; readonly fontWeight: string; readonly fontSize: number; + readonly fontFeatureSettings: string; readonly lineHeight: number; readonly letterSpacing: number; } @@ -4748,7 +4879,10 @@ declare namespace monaco.languages { * *Note:* The range must be a [single line](#Range.isSingleLine) and it must * [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems). */ - range: IRange; + range: IRange | { + insert: IRange; + replace: IRange; + }; /** * An optional set of characters that when pressed while this completion is active will accept it first and * then type that character. *Note* that all commit characters should have `length=1` and that superfluous @@ -5127,7 +5261,7 @@ declare namespace monaco.languages { /** * The document symbol provider interface defines the contract between extensions and - * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_goto-symbol)-feature. + * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature. */ export interface DocumentSymbolProvider { displayName?: string; diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts index 01d88e2ece8..17dfd5efde6 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts @@ -205,19 +205,20 @@ export class MenuEntryActionViewItem extends ActionViewItem { } updateLabel(): void { - if (this.options.label) { + if (this.options.label && this.label) { this.label.textContent = this._commandAction.label; } } updateTooltip(): void { - const element = this.label; - const keybinding = this._keybindingService.lookupKeybinding(this._commandAction.id); - const keybindingLabel = keybinding && keybinding.getLabel(); + if (this.label) { + const keybinding = this._keybindingService.lookupKeybinding(this._commandAction.id); + const keybindingLabel = keybinding && keybinding.getLabel(); - element.title = keybindingLabel - ? localize('titleAndKb', "{0} ({1})", this._commandAction.label, keybindingLabel) - : this._commandAction.label; + this.label.title = keybindingLabel + ? localize('titleAndKb', "{0} ({1})", this._commandAction.label, keybindingLabel) + : this._commandAction.label; + } } updateClass(): void { @@ -249,8 +250,14 @@ export class MenuEntryActionViewItem extends ActionViewItem { MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass); } - addClasses(this.label, 'icon', iconClass); - this._itemClassDispose.value = toDisposable(() => removeClasses(this.label, 'icon', iconClass)); + if (this.label) { + addClasses(this.label, 'icon', iconClass); + this._itemClassDispose.value = toDisposable(() => { + if (this.label) { + removeClasses(this.label, 'icon', iconClass); + } + }); + } } } } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index a88f4f6968e..a583f7a34f5 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -287,13 +287,13 @@ export class MenuItemAction extends ExecuteCommandAction { export class SyncActionDescriptor { - private _descriptor: SyncDescriptor0; + private readonly _descriptor: SyncDescriptor0; - private _id: string; - private _label?: string; - private _keybindings: IKeybindings | undefined; - private _keybindingContext: ContextKeyExpr | undefined; - private _keybindingWeight: number | undefined; + private readonly _id: string; + private readonly _label?: string; + private readonly _keybindings: IKeybindings | undefined; + private readonly _keybindingContext: ContextKeyExpr | undefined; + private readonly _keybindingWeight: number | undefined; constructor(ctor: IConstructorSignature2, id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number diff --git a/src/vs/platform/auth/common/auth.ts b/src/vs/platform/auth/common/auth.ts new file mode 100644 index 00000000000..7b2961d30b0 --- /dev/null +++ b/src/vs/platform/auth/common/auth.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 { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Event } from 'vs/base/common/event'; + +export const enum AuthTokenStatus { + Disabled = 'Disabled', + Inactive = 'Inactive', + Active = 'Active' +} + +export const IAuthTokenService = createDecorator('IAuthTokenService'); + +export interface IAuthTokenService { + _serviceBrand: undefined; + + readonly status: AuthTokenStatus; + readonly onDidChangeStatus: Event; + + getToken(): Promise; + updateToken(token: string): Promise; + refreshToken(): Promise; + deleteToken(): Promise; + +} + diff --git a/src/vs/platform/auth/common/authTokenIpc.ts b/src/vs/platform/auth/common/authTokenIpc.ts new file mode 100644 index 00000000000..a5c78c4a8dd --- /dev/null +++ b/src/vs/platform/auth/common/authTokenIpc.ts @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Event } from 'vs/base/common/event'; +import { IAuthTokenService } from 'vs/platform/auth/common/auth'; + +export class AuthTokenChannel implements IServerChannel { + + constructor(private readonly service: IAuthTokenService) { } + + listen(_: unknown, event: string): Event { + switch (event) { + case 'onDidChangeStatus': return this.service.onDidChangeStatus; + } + throw new Error(`Event not found: ${event}`); + } + + call(context: any, command: string, args?: any): Promise { + switch (command) { + case '_getInitialStatus': return Promise.resolve(this.service.status); + case 'getToken': return this.service.getToken(); + case 'updateToken': return this.service.updateToken(args[0]); + case 'refreshToken': return this.service.refreshToken(); + case 'deleteToken': return this.service.deleteToken(); + } + throw new Error('Invalid call'); + } +} diff --git a/src/vs/platform/auth/common/authTokenService.ts b/src/vs/platform/auth/common/authTokenService.ts new file mode 100644 index 00000000000..322ecfb2b09 --- /dev/null +++ b/src/vs/platform/auth/common/authTokenService.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event, Emitter } from 'vs/base/common/event'; +import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +const SERVICE_NAME = 'VS Code'; +const ACCOUNT = 'MyAccount'; + +export class AuthTokenService extends Disposable implements IAuthTokenService { + _serviceBrand: undefined; + + private _status: AuthTokenStatus = AuthTokenStatus.Disabled; + get status(): AuthTokenStatus { return this._status; } + private _onDidChangeStatus: Emitter = this._register(new Emitter()); + readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + + constructor( + @ICredentialsService private readonly credentialsService: ICredentialsService, + @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService, + ) { + super(); + if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) { + this._status = AuthTokenStatus.Inactive; + this.getToken().then(token => { + if (token) { + this.setStatus(AuthTokenStatus.Active); + } + }); + } + } + + getToken(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + return this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT); + } + + async updateToken(token: string): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + await this.credentialsService.setPassword(SERVICE_NAME, ACCOUNT, token); + this.setStatus(AuthTokenStatus.Active); + } + + async refreshToken(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + await this.deleteToken(); + } + + async deleteToken(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + await this.credentialsService.deletePassword(SERVICE_NAME, ACCOUNT); + this.setStatus(AuthTokenStatus.Inactive); + } + + private setStatus(status: AuthTokenStatus): void { + if (this._status !== status) { + this._status = status; + this._onDidChangeStatus.fire(status); + } + } + +} + diff --git a/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts index ab24a78884b..910457adf19 100644 --- a/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -28,9 +28,9 @@ export class BackupMainService implements IBackupMainService { protected backupHome: string; protected workspacesJsonPath: string; - private rootWorkspaces: IWorkspaceBackupInfo[]; - private folderWorkspaces: URI[]; - private emptyWorkspaces: IEmptyWindowBackupInfo[]; + private rootWorkspaces: IWorkspaceBackupInfo[] = []; + private folderWorkspaces: URI[] = []; + private emptyWorkspaces: IEmptyWindowBackupInfo[] = []; constructor( @IEnvironmentService environmentService: IEnvironmentService, @@ -55,8 +55,6 @@ export class BackupMainService implements IBackupMainService { } else if (Array.isArray(backups.emptyWorkspaces)) { // read legacy entries this.emptyWorkspaces = await this.validateEmptyWorkspaces(backups.emptyWorkspaces.map(backupFolder => ({ backupFolder }))); - } else { - this.emptyWorkspaces = []; } // read workspace backups @@ -70,6 +68,7 @@ export class BackupMainService implements IBackupMainService { } catch (e) { // ignore URI parsing exceptions } + this.rootWorkspaces = await this.validateWorkspaces(rootWorkspaces); // read folder backups @@ -131,7 +130,7 @@ export class BackupMainService implements IBackupMainService { private getHotExitConfig(): string { const config = this.configurationService.getValue(); - return (config && config.files && config.files.hotExit) || HotExitConfiguration.ON_EXIT; + return config?.files?.hotExit || HotExitConfiguration.ON_EXIT; } getEmptyWindowBackupPaths(): IEmptyWindowBackupInfo[] { @@ -213,14 +212,11 @@ export class BackupMainService implements IBackupMainService { } } - registerEmptyWindowBackupSync(backupFolder?: string, remoteAuthority?: string): string { + registerEmptyWindowBackupSync(backupFolderCandidate?: string, remoteAuthority?: string): string { // Generate a new folder if this is a new empty workspace - if (!backupFolder) { - backupFolder = this.getRandomEmptyWindowId(); - } - - if (!this.emptyWorkspaces.some(window => !!window.backupFolder && isEqual(window.backupFolder, backupFolder!, !platform.isLinux))) { + const backupFolder = backupFolderCandidate || this.getRandomEmptyWindowId(); + if (!this.emptyWorkspaces.some(window => !!window.backupFolder && isEqual(window.backupFolder, backupFolder, !platform.isLinux))) { this.emptyWorkspaces.push({ backupFolder, remoteAuthority }); this.saveSync(); } diff --git a/src/vs/platform/commands/common/commands.ts b/src/vs/platform/commands/common/commands.ts index 96523ce0450..2110663021f 100644 --- a/src/vs/platform/commands/common/commands.ts +++ b/src/vs/platform/commands/common/commands.ts @@ -99,7 +99,7 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR let ret = toDisposable(() => { removeFn(); const command = this._commands.get(id); - if (command && command.isEmpty()) { + if (command?.isEmpty()) { this._commands.delete(id); } }); diff --git a/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts index c4749186815..533ce1a7c4d 100644 --- a/src/vs/platform/configuration/common/configurationModels.ts +++ b/src/vs/platform/configuration/common/configurationModels.ts @@ -518,14 +518,14 @@ export class Configuration { return folderConsolidatedConfiguration; } - private getFolderConfigurationModelForResource(resource: URI | null | undefined, workspace: Workspace | undefined): ConfigurationModel | null { + private getFolderConfigurationModelForResource(resource: URI | null | undefined, workspace: Workspace | undefined): ConfigurationModel | undefined { if (workspace && resource) { const root = workspace.getFolder(resource); if (root) { - return types.withUndefinedAsNull(this._folderConfigurations.get(root.uri)); + return this._folderConfigurations.get(root.uri); } } - return null; + return undefined; } toData(): IConfigurationData { @@ -605,6 +605,7 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i private _changedConfiguration: ConfigurationModel = new ConfigurationModel(), private _changedConfigurationByResource: ResourceMap = new ResourceMap()) { super(); + this._source = ConfigurationTarget.DEFAULT; } get changedConfiguration(): IConfigurationModel { @@ -663,13 +664,7 @@ export class ConfigurationChangeEvent extends AbstractConfigurationChangeEvent i configurationModelsToSearch.push(...this._changedConfigurationByResource.values()); } - for (const configuration of configurationModelsToSearch) { - if (this.doesConfigurationContains(configuration, config)) { - return true; - } - } - - return false; + return configurationModelsToSearch.some(configuration => this.doesConfigurationContains(configuration, config)); } private changeWithKeys(keys: string[], resource?: URI): void { diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index 32d66562f55..8a346c09ca4 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -173,7 +173,7 @@ class ConfigurationRegistry implements IConfigurationRegistry { this.editorConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting', allowTrailingCommas: true, allowComments: true }; this.configurationProperties = {}; this.excludedConfigurationProperties = {}; - this.computeOverridePropertyPattern(); + this.overridePropertyPattern = this.computeOverridePropertyPattern(); contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema); } @@ -413,7 +413,7 @@ class ConfigurationRegistry implements IConfigurationRegistry { delete windowSettings.patternProperties[this.overridePropertyPattern]; delete resourceSettings.patternProperties[this.overridePropertyPattern]; - this.computeOverridePropertyPattern(); + this.overridePropertyPattern = this.computeOverridePropertyPattern(); allSettings.patternProperties[this.overridePropertyPattern] = patternProperties; applicationSettings.patternProperties[this.overridePropertyPattern] = patternProperties; @@ -440,8 +440,8 @@ class ConfigurationRegistry implements IConfigurationRegistry { } } - private computeOverridePropertyPattern(): void { - this.overridePropertyPattern = this.overrideIdentifiers.length ? OVERRIDE_PATTERN_WITH_SUBSTITUTION.replace('${0}', this.overrideIdentifiers.map(identifier => strings.createRegExp(identifier, false).source).join('|')) : OVERRIDE_PROPERTY; + private computeOverridePropertyPattern(): string { + return this.overrideIdentifiers.length ? OVERRIDE_PATTERN_WITH_SUBSTITUTION.replace('${0}', this.overrideIdentifiers.map(identifier => strings.createRegExp(identifier, false).source).join('|')) : OVERRIDE_PROPERTY; } } diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index 8efe90bd137..6e033c32c6a 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -87,7 +87,7 @@ class NullContext extends Context { class ConfigAwareContextValuesContainer extends Context { - private static _keyPrefix = 'config.'; + private static readonly _keyPrefix = 'config.'; private readonly _values = new Map(); private readonly _listener: IDisposable; diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 16e79df476f..d0654bc1caf 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -613,7 +613,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { if (e instanceof ContextKeyOrExpr) { // Not allowed, because we don't have parens! - throw new Error(`It is not allowed to have an or expression here due to lack of parens!`); + throw new Error(`It is not allowed to have an or expression here due to lack of parens! For example "a && (b||c)" is not supported, use "(a&&b) || (a&&c)" instead.`); } expr.push(e); diff --git a/src/vs/platform/credentials/node/credentialsService.ts b/src/vs/platform/credentials/node/credentialsService.ts new file mode 100644 index 00000000000..bc8d8d75914 --- /dev/null +++ b/src/vs/platform/credentials/node/credentialsService.ts @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; +import { IdleValue } from 'vs/base/common/async'; + +type KeytarModule = typeof import('keytar'); +export class KeytarCredentialsService implements ICredentialsService { + + _serviceBrand: undefined; + + private readonly _keytar = new IdleValue>(() => import('keytar')); + + async getPassword(service: string, account: string): Promise { + const keytar = await this._keytar.getValue(); + return keytar.getPassword(service, account); + } + + async setPassword(service: string, account: string, password: string): Promise { + const keytar = await this._keytar.getValue(); + return keytar.setPassword(service, account, password); + } + + async deletePassword(service: string, account: string): Promise { + const keytar = await this._keytar.getValue(); + return keytar.deletePassword(service, account); + } + + async findPassword(service: string): Promise { + const keytar = await this._keytar.getValue(); + return keytar.findPassword(service); + } + + async findCredentials(service: string): Promise> { + const keytar = await this._keytar.getValue(); + return keytar.findCredentials(service); + } +} diff --git a/src/vs/platform/debug/common/extensionHostDebug.ts b/src/vs/platform/debug/common/extensionHostDebug.ts index 3ccb12051b7..57a604c2350 100644 --- a/src/vs/platform/debug/common/extensionHostDebug.ts +++ b/src/vs/platform/debug/common/extensionHostDebug.ts @@ -6,7 +6,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { IRemoteConsoleLog } from 'vs/base/common/console'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { IProcessEnvironment } from 'vs/base/common/platform'; export const IExtensionHostDebugService = createDecorator('extensionHostDebugService'); @@ -53,5 +52,5 @@ export interface IExtensionHostDebugService { terminateSession(sessionId: string, subId?: string): void; readonly onTerminateSession: Event; - openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise; + openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment): Promise; } diff --git a/src/vs/platform/debug/common/extensionHostDebugIpc.ts b/src/vs/platform/debug/common/extensionHostDebugIpc.ts index e342490136d..72aa7fcc2ea 100644 --- a/src/vs/platform/debug/common/extensionHostDebugIpc.ts +++ b/src/vs/platform/debug/common/extensionHostDebugIpc.ts @@ -8,7 +8,6 @@ import { IReloadSessionEvent, ICloseSessionEvent, IAttachSessionEvent, ILogToSes import { Event, Emitter } from 'vs/base/common/event'; import { IRemoteConsoleLog } from 'vs/base/common/console'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { IProcessEnvironment } from 'vs/base/common/platform'; export class ExtensionHostDebugBroadcastChannel implements IServerChannel { @@ -102,9 +101,7 @@ export class ExtensionHostDebugChannelClient extends Disposable implements IExte return this.channel.listen('terminate'); } - openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { - // TODO@Isidor - //return this.channel.call('openExtensionDevelopmentHostWindow', [args, env]); - return Promise.resolve(); + openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment): Promise { + return this.channel.call('openExtensionDevelopmentHostWindow', [args, env]); } } diff --git a/src/vs/platform/diagnostics/common/diagnostics.ts b/src/vs/platform/diagnostics/common/diagnostics.ts index 9adfc578f64..31a4ee17474 100644 --- a/src/vs/platform/diagnostics/common/diagnostics.ts +++ b/src/vs/platform/diagnostics/common/diagnostics.ts @@ -63,6 +63,7 @@ export interface PerformanceInfo { export interface IWorkspaceInformation extends IWorkspace { telemetryId: string | undefined; + rendererSessionId: string; } export function isRemoteDiagnosticError(x: any): x is IRemoteDiagnosticError { diff --git a/src/vs/platform/diagnostics/node/diagnosticsService.ts b/src/vs/platform/diagnostics/node/diagnosticsService.ts index 43dd25b6a5f..b423cbae2eb 100644 --- a/src/vs/platform/diagnostics/node/diagnosticsService.ts +++ b/src/vs/platform/diagnostics/node/diagnosticsService.ts @@ -7,7 +7,7 @@ import { virtualMachineHint } from 'vs/base/node/id'; import { IMachineInfo, WorkspaceStats, WorkspaceStatItem, PerformanceInfo, SystemInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError, isRemoteDiagnosticError, IWorkspaceInformation } from 'vs/platform/diagnostics/common/diagnostics'; import { readdir, stat, exists, readFile } from 'fs'; import { join, basename } from 'vs/base/common/path'; -import { parse, ParseError } from 'vs/base/common/json'; +import { parse, ParseError, getNodeType } from 'vs/base/common/json'; import { listProcesses } from 'vs/base/node/ps'; import product from 'vs/platform/product/common/product'; import { repeat, pad } from 'vs/base/common/strings'; @@ -223,7 +223,7 @@ export function collectLaunchConfigs(folder: string): Promise { type WorkspaceStatsClassification = { 'workspace.id': { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - fileTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - configTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - launchConfigs: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + rendererSessionId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; }; type WorkspaceStatsEvent = { 'workspace.id': string | undefined; - fileTypes: WorkspaceStatItem[]; - configTypes: WorkspaceStatItem[]; - launchConfigs: WorkspaceStatItem[]; + rendererSessionId: string; }; this.telemetryService.publicLog2('workspace.stats', { 'workspace.id': workspace.telemetryId, - fileTypes: stats.fileTypes, - configTypes: stats.configFiles, - launchConfigs: stats.launchConfigFiles + rendererSessionId: workspace.rendererSessionId + }); + type WorkspaceStatsFileClassification = { + rendererSessionId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + type: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + count: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type WorkspaceStatsFileEvent = { + rendererSessionId: string; + type: string; + count: number; + }; + stats.fileTypes.forEach(e => { + this.telemetryService.publicLog2('workspace.stats.file', { + rendererSessionId: workspace.rendererSessionId, + type: e.name, + count: e.count + }); + }); + stats.launchConfigFiles.forEach(e => { + this.telemetryService.publicLog2('workspace.stats.launchConfigFile', { + rendererSessionId: workspace.rendererSessionId, + type: e.name, + count: e.count + }); + }); + stats.configFiles.forEach(e => { + this.telemetryService.publicLog2('workspace.stats.configFiles', { + rendererSessionId: workspace.rendererSessionId, + type: e.name, + count: e.count + }); }); }).catch(_ => { // Report nothing if collecting metadata fails. diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index 9a504f151ab..a01a721267f 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -94,7 +94,7 @@ export interface ISaveDialogOptions { * Specifies a list of schemas for the file systems the user can save to. If not specified, uses the schema of the defaultURI or, if also not specified, * the schema of the current window. */ - availableFileSystems?: string[]; + availableFileSystems?: readonly string[]; } export interface IOpenDialogOptions { @@ -138,7 +138,7 @@ export interface IOpenDialogOptions { * Specifies a list of schemas for the file systems the user can load from. If not specified, uses the schema of the defaultURI or, if also not available, * the schema of the current window. */ - availableFileSystems?: string[]; + availableFileSystems?: readonly string[]; } diff --git a/src/vs/platform/dialogs/electron-main/dialogs.ts b/src/vs/platform/dialogs/electron-main/dialogs.ts new file mode 100644 index 00000000000..7b49ca50c2e --- /dev/null +++ b/src/vs/platform/dialogs/electron-main/dialogs.ts @@ -0,0 +1,207 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { MessageBoxOptions, MessageBoxReturnValue, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, dialog, FileFilter, BrowserWindow } from 'electron'; +import { Queue } from 'vs/base/common/async'; +import { IStateService } from 'vs/platform/state/node/state'; +import { isMacintosh } from 'vs/base/common/platform'; +import { dirname } from 'vs/base/common/path'; +import { normalizeNFC } from 'vs/base/common/normalization'; +import { exists } from 'vs/base/node/pfs'; +import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { localize } from 'vs/nls'; +import { WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces'; +import { mnemonicButtonLabel } from 'vs/base/common/labels'; + +export const IDialogMainService = createDecorator('dialogMainService'); + +export interface IDialogMainService { + + _serviceBrand: undefined; + + pickFileFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise; + pickFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise; + pickFile(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise; + pickWorkspace(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise; + + showMessageBox(options: MessageBoxOptions, window?: BrowserWindow): Promise; + showSaveDialog(options: SaveDialogOptions, window?: BrowserWindow): Promise; + showOpenDialog(options: OpenDialogOptions, window?: BrowserWindow): Promise; +} + +interface IInternalNativeOpenDialogOptions extends INativeOpenDialogOptions { + pickFolders?: boolean; + pickFiles?: boolean; + + title: string; + buttonLabel?: string; + filters?: FileFilter[]; +} + +export class DialogMainService implements IDialogMainService { + + _serviceBrand: undefined; + + private static readonly workingDirPickerStorageKey = 'pickerWorkingDir'; + + private readonly mapWindowToDialogQueue: Map>; + private readonly noWindowDialogQueue: Queue; + + constructor( + @IStateService private readonly stateService: IStateService + ) { + this.mapWindowToDialogQueue = new Map>(); + this.noWindowDialogQueue = new Queue(); + } + + pickFileFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise { + return this.doPick({ ...options, pickFolders: true, pickFiles: true, title: localize('open', "Open") }, window); + } + + pickFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise { + return this.doPick({ ...options, pickFolders: true, title: localize('openFolder', "Open Folder") }, window); + } + + pickFile(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise { + return this.doPick({ ...options, pickFiles: true, title: localize('openFile', "Open File") }, window); + } + + pickWorkspace(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise { + const title = localize('openWorkspaceTitle', "Open Workspace"); + const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open")); + const filters = WORKSPACE_FILTER; + + return this.doPick({ ...options, pickFiles: true, title, filters, buttonLabel }, window); + } + + private async doPick(options: IInternalNativeOpenDialogOptions, window?: BrowserWindow): Promise { + + // Ensure dialog options + const dialogOptions: OpenDialogOptions = { + title: options.title, + buttonLabel: options.buttonLabel, + filters: options.filters + }; + + // Ensure defaultPath + dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem(DialogMainService.workingDirPickerStorageKey); + + + // Ensure properties + if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') { + dialogOptions.properties = undefined; // let it override based on the booleans + + if (options.pickFiles && options.pickFolders) { + dialogOptions.properties = ['multiSelections', 'openDirectory', 'openFile', 'createDirectory']; + } + } + + if (!dialogOptions.properties) { + dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory']; + } + + if (isMacintosh) { + dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files + } + + // Show Dialog + const windowToUse = window || BrowserWindow.getFocusedWindow(); + + const result = await this.showOpenDialog(dialogOptions, withNullAsUndefined(windowToUse)); + if (result && result.filePaths && result.filePaths.length > 0) { + + // Remember path in storage for next time + this.stateService.setItem(DialogMainService.workingDirPickerStorageKey, dirname(result.filePaths[0])); + + return result.filePaths; + } + + return; + } + + private getDialogQueue(window?: BrowserWindow): Queue { + if (!window) { + return this.noWindowDialogQueue; + } + + let windowDialogQueue = this.mapWindowToDialogQueue.get(window.id); + if (!windowDialogQueue) { + windowDialogQueue = new Queue(); + this.mapWindowToDialogQueue.set(window.id, windowDialogQueue); + } + + return windowDialogQueue; + } + + showMessageBox(options: MessageBoxOptions, window?: BrowserWindow): Promise { + return this.getDialogQueue(window).queue(async () => { + if (window) { + return dialog.showMessageBox(window, options); + } + + return dialog.showMessageBox(options); + }); + } + + showSaveDialog(options: SaveDialogOptions, window?: BrowserWindow): Promise { + + function normalizePath(path: string | undefined): string | undefined { + if (path && isMacintosh) { + path = normalizeNFC(path); // normalize paths returned from the OS + } + + return path; + } + + return this.getDialogQueue(window).queue(async () => { + let result: SaveDialogReturnValue; + if (window) { + result = await dialog.showSaveDialog(window, options); + } else { + result = await dialog.showSaveDialog(options); + } + + result.filePath = normalizePath(result.filePath); + + return result; + }); + } + + showOpenDialog(options: OpenDialogOptions, window?: BrowserWindow): Promise { + + function normalizePaths(paths: string[] | undefined): string[] | undefined { + if (paths && paths.length > 0 && isMacintosh) { + paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS + } + + return paths; + } + + return this.getDialogQueue(window).queue(async () => { + + // Ensure the path exists (if provided) + if (options.defaultPath) { + const pathExists = await exists(options.defaultPath); + if (!pathExists) { + options.defaultPath = undefined; + } + } + + // Show dialog + let result: OpenDialogReturnValue; + if (window) { + result = await dialog.showOpenDialog(window, options); + } else { + result = await dialog.showOpenDialog(options); + } + + result.filePaths = normalizePaths(result.filePaths); + + return result; + }); + } +} diff --git a/src/vs/workbench/services/progress/browser/editorProgressService.ts b/src/vs/platform/dialogs/node/dialogs.ts similarity index 60% rename from src/vs/workbench/services/progress/browser/editorProgressService.ts rename to src/vs/platform/dialogs/node/dialogs.ts index b05c6305b84..754693da712 100644 --- a/src/vs/workbench/services/progress/browser/editorProgressService.ts +++ b/src/vs/platform/dialogs/node/dialogs.ts @@ -3,9 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ProgressBarIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; +import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; -export class EditorProgressService extends ProgressBarIndicator { +export interface INativeOpenDialogOptions { + forceNewWindow?: boolean; - _serviceBrand: undefined; + defaultPath?: string; + + telemetryEventName?: string; + telemetryExtraData?: ITelemetryData; } diff --git a/src/vs/platform/download/common/downloadService.ts b/src/vs/platform/download/common/downloadService.ts index 08593aa5d27..7de9b02fc3d 100644 --- a/src/vs/platform/download/common/downloadService.ts +++ b/src/vs/platform/download/common/downloadService.ts @@ -30,7 +30,7 @@ export class DownloadService implements IDownloadService { await this.fileService.writeFile(target, context.stream); } else { const message = await asText(context); - return Promise.reject(new Error(`Expected 200, got back ${context.res.statusCode} instead.\n\n${message}`)); + throw new Error(`Expected 200, got back ${context.res.statusCode} instead.\n\n${message}`); } } } diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index 941c4aa63b5..2594eef1361 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -8,7 +8,6 @@ import { WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platf import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import * as electron from 'electron'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { timeout } from 'vs/base/common/async'; import { BaseWindowDriver } from 'vs/platform/driver/browser/baseDriver'; import { IElectronService } from 'vs/platform/electron/node/electron'; @@ -46,10 +45,9 @@ class WindowDriver extends BaseWindowDriver { } } -export async function registerWindowDriver(accessor: ServicesAccessor): Promise { +export async function registerWindowDriver(accessor: ServicesAccessor, windowId: number): Promise { const instantiationService = accessor.get(IInstantiationService); const mainProcessService = accessor.get(IMainProcessService); - const windowService = accessor.get(IWindowService); const windowDriver = instantiationService.createInstance(WindowDriver); const windowDriverChannel = new WindowDriverChannel(windowDriver); @@ -58,12 +56,12 @@ export async function registerWindowDriver(accessor: ServicesAccessor): Promise< const windowDriverRegistryChannel = mainProcessService.getChannel('windowDriverRegistry'); const windowDriverRegistry = new WindowDriverRegistryChannelClient(windowDriverRegistryChannel); - await windowDriverRegistry.registerWindowDriver(windowService.windowId); + await windowDriverRegistry.registerWindowDriver(windowId); // const options = await windowDriverRegistry.registerWindowDriver(windowId); // if (options.verbose) { // windowDriver.openDevTools(); // } - return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowService.windowId)); + return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowId)); } diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index a0e9f373504..e0beffc55ed 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -19,6 +19,8 @@ import { KeybindingParser } from 'vs/base/common/keybindingParser'; import { timeout } from 'vs/base/common/async'; import { IDriver, IElement, IWindowDriver } from 'vs/platform/driver/common/driver'; import { NativeImage } from 'electron'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; +import { IElectronMainService } from 'vs/platform/electron/electron-main/electronMainService'; function isSilentKeyCode(keyCode: KeyCode) { return keyCode < KeyCode.KEY_0; @@ -35,7 +37,9 @@ export class Driver implements IDriver, IWindowDriverRegistry { constructor( private windowServer: IPCServer, private options: IDriverOptions, - @IWindowsMainService private readonly windowsMainService: IWindowsMainService + @IWindowsMainService private readonly windowsMainService: IWindowsMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, + @IElectronMainService private readonly electronMainService: IElectronMainService ) { } async registerWindowDriver(windowId: number): Promise { @@ -75,11 +79,11 @@ export class Driver implements IDriver, IWindowDriverRegistry { throw new Error('Invalid window'); } this.reloadingWindowIds.add(windowId); - this.windowsMainService.reload(window); + this.lifecycleMainService.reload(window); } async exitApplication(): Promise { - return this.windowsMainService.quit(); + return this.electronMainService.quit(undefined); } async dispatchKeybinding(windowId: number, keybinding: string): Promise { diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 09d22bda225..3185e8c9f96 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -106,6 +106,21 @@ export enum EditorActivation { PRESERVE } +export enum EditorOpenContext { + + /** + * Default: the editor is opening via a programmatic call + * to the editor service API. + */ + API, + + /** + * Indicates that a user action triggered the opening, e.g. + * via mouse or keyboard use. + */ + USER +} + export interface IEditorOptions { /** @@ -179,6 +194,18 @@ export interface IEditorOptions { * Does not use editor overrides while opening the editor */ readonly ignoreOverrides?: boolean; + + /** + * A optional hint to signal in which context the editor opens. + * + * If configured to be `EditorOpenContext.USER`, this hint can be + * used in various places to control the experience. For example, + * if the editor to open fails with an error, a notification could + * inform about this in a modal dialog. If the editor opened through + * some background task, the notification would show in the background, + * not as a modal dialog. + */ + readonly context?: EditorOpenContext; } export interface ITextEditorSelection { diff --git a/src/vs/platform/electron/electron-main/electronMainService.ts b/src/vs/platform/electron/electron-main/electronMainService.ts index 48ba9ca7f34..7c2a6840f9e 100644 --- a/src/vs/platform/electron/electron-main/electronMainService.ts +++ b/src/vs/platform/electron/electron-main/electronMainService.ts @@ -3,27 +3,56 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; -import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, CrashReporterStartOptions, crashReporter, Menu } from 'electron'; +import { Event } from 'vs/base/common/event'; +import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; +import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, CrashReporterStartOptions, crashReporter, Menu, BrowserWindow, app } from 'electron'; +import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; -import { OpenContext, INativeOpenDialogOptions, IWindowOpenable, IOpenInWindowOptions, IOpenedWindow, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IOpenedWindow, OpenContext, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; import { isMacintosh } from 'vs/base/common/platform'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; -import { AddContextToFunctions } from 'vs/platform/ipc/node/simpleIpcProxy'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { AddFirstParameterToFunctions } from 'vs/base/common/types'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { dirExists } from 'vs/base/node/pfs'; +import { URI } from 'vs/base/common/uri'; +import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -export class ElectronMainService implements AddContextToFunctions { +export interface IElectronMainService extends AddFirstParameterToFunctions /* only methods, not events */, number | undefined /* window ID */> { } + +export const IElectronMainService = createDecorator('electronMainService'); + +export class ElectronMainService implements IElectronMainService { _serviceBrand: undefined; constructor( @IWindowsMainService private readonly windowsMainService: IWindowsMainService, + @IDialogMainService private readonly dialogMainService: IDialogMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, - @IEnvironmentService private readonly environmentService: IEnvironmentService + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @ITelemetryService private readonly telemetryService: ITelemetryService ) { } + //#region Events + + readonly onWindowOpen: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-created', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)); + + readonly onWindowMaximize: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-maximize', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)); + readonly onWindowUnmaximize: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-unmaximize', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)); + + readonly onWindowBlur: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-blur', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)); + readonly onWindowFocus: Event = Event.any( + Event.map(Event.filter(Event.map(this.windowsMainService.onWindowsCountChanged, () => this.windowsMainService.getLastActiveWindow()), window => !!window), window => window!.id), + Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (_, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)) + ); + + //#endregion + //#region Window async getWindows(): Promise { @@ -38,15 +67,30 @@ export class ElectronMainService implements AddContextToFunctions { + async getWindowCount(windowId: number | undefined): Promise { return this.windowsMainService.getWindowCount(); } - async openEmptyWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise { - this.windowsMainService.openEmptyWindow(OpenContext.API, options); + async getActiveWindowId(windowId: number | undefined): Promise { + const activeWindow = BrowserWindow.getFocusedWindow() || this.windowsMainService.getLastActiveWindow(); + if (activeWindow) { + return activeWindow.id; + } + + return undefined; } - async openInWindow(windowId: number, toOpen: IWindowOpenable[], options: IOpenInWindowOptions = Object.create(null)): Promise { + openWindow(windowId: number | undefined, options?: IOpenEmptyWindowOptions): Promise; + openWindow(windowId: number | undefined, toOpen: IWindowOpenable[], options?: INativeOpenWindowOptions): Promise; + openWindow(windowId: number | undefined, arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: INativeOpenWindowOptions): Promise { + if (Array.isArray(arg1)) { + return this.doOpenWindow(windowId, arg1, arg2); + } + + return this.doOpenEmptyWindow(windowId, arg1); + } + + private async doOpenWindow(windowId: number | undefined, toOpen: IWindowOpenable[], options: INativeOpenWindowOptions = Object.create(null)): Promise { if (toOpen.length > 0) { this.windowsMainService.open({ context: OpenContext.API, @@ -64,22 +108,26 @@ export class ElectronMainService implements AddContextToFunctions { - const window = this.windowsMainService.getWindowById(windowId); + private async doOpenEmptyWindow(windowId: number | undefined, options?: IOpenEmptyWindowOptions): Promise { + this.windowsMainService.openEmptyWindow(OpenContext.API, options); + } + + async toggleFullScreen(windowId: number | undefined): Promise { + const window = this.windowById(windowId); if (window) { window.toggleFullScreen(); } } - async handleTitleDoubleClick(windowId: number): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async handleTitleDoubleClick(windowId: number | undefined): Promise { + const window = this.windowById(windowId); if (window) { window.handleTitleDoubleClick(); } } - async isMaximized(windowId: number): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async isMaximized(windowId: number | undefined): Promise { + const window = this.windowById(windowId); if (window) { return window.win.isMaximized(); } @@ -87,33 +135,42 @@ export class ElectronMainService implements AddContextToFunctions { - const window = this.windowsMainService.getWindowById(windowId); + async maximizeWindow(windowId: number | undefined): Promise { + const window = this.windowById(windowId); if (window) { window.win.maximize(); } } - async unmaximizeWindow(windowId: number): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async unmaximizeWindow(windowId: number | undefined): Promise { + const window = this.windowById(windowId); if (window) { window.win.unmaximize(); } } - async minimizeWindow(windowId: number): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async minimizeWindow(windowId: number | undefined): Promise { + const window = this.windowById(windowId); if (window) { window.win.minimize(); } } - async focusWindow(windowId: number, options?: { windowId?: number; }): Promise { + async isWindowFocused(windowId: number | undefined): Promise { + const window = this.windowById(windowId); + if (window) { + return window.win.isFocused(); + } + + return false; + } + + async focusWindow(windowId: number | undefined, options?: { windowId?: number; }): Promise { if (options && typeof options.windowId === 'number') { windowId = options.windowId; } - const window = this.windowsMainService.getWindowById(windowId); + const window = this.windowById(windowId); if (window) { if (isMacintosh) { window.win.show(); @@ -127,62 +184,111 @@ export class ElectronMainService implements AddContextToFunctions { - return this.windowsMainService.showMessageBox(options, this.windowsMainService.getWindowById(windowId)); + async showMessageBox(windowId: number | undefined, options: MessageBoxOptions): Promise { + return this.dialogMainService.showMessageBox(options, this.toBrowserWindow(windowId)); } - async showSaveDialog(windowId: number, options: SaveDialogOptions): Promise { - return this.windowsMainService.showSaveDialog(options, this.windowsMainService.getWindowById(windowId)); + async showSaveDialog(windowId: number | undefined, options: SaveDialogOptions): Promise { + return this.dialogMainService.showSaveDialog(options, this.toBrowserWindow(windowId)); } - async showOpenDialog(windowId: number, options: OpenDialogOptions): Promise { - return this.windowsMainService.showOpenDialog(options, this.windowsMainService.getWindowById(windowId)); + async showOpenDialog(windowId: number | undefined, options: OpenDialogOptions): Promise { + return this.dialogMainService.showOpenDialog(options, this.toBrowserWindow(windowId)); } - async pickFileFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { - return this.windowsMainService.pickFileFolderAndOpen(options, this.windowsMainService.getWindowById(windowId)); + private toBrowserWindow(windowId: number | undefined): BrowserWindow | undefined { + const window = this.windowById(windowId); + if (window) { + return window.win; + } + + return undefined; } - async pickFileAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { - return this.windowsMainService.pickFileAndOpen(options, this.windowsMainService.getWindowById(windowId)); + async pickFileFolderAndOpen(windowId: number | undefined, options: INativeOpenDialogOptions): Promise { + const paths = await this.dialogMainService.pickFileFolder(options); + if (paths) { + this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFileFolder', options.telemetryExtraData); + this.doOpenPicked(await Promise.all(paths.map(async path => (await dirExists(path)) ? { folderUri: URI.file(path) } : { fileUri: URI.file(path) })), options, windowId); + } } - async pickFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { - return this.windowsMainService.pickFolderAndOpen(options, this.windowsMainService.getWindowById(windowId)); + async pickFolderAndOpen(windowId: number | undefined, options: INativeOpenDialogOptions): Promise { + const paths = await this.dialogMainService.pickFolder(options); + if (paths) { + this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFolder', options.telemetryExtraData); + this.doOpenPicked(paths.map(path => ({ folderUri: URI.file(path) })), options, windowId); + } } - async pickWorkspaceAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { - return this.windowsMainService.pickWorkspaceAndOpen(options, this.windowsMainService.getWindowById(windowId)); + async pickFileAndOpen(windowId: number | undefined, options: INativeOpenDialogOptions): Promise { + const paths = await this.dialogMainService.pickFile(options); + if (paths) { + this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFile', options.telemetryExtraData); + this.doOpenPicked(paths.map(path => ({ fileUri: URI.file(path) })), options, windowId); + } + } + + async pickWorkspaceAndOpen(windowId: number | undefined, options: INativeOpenDialogOptions): Promise { + const paths = await this.dialogMainService.pickWorkspace(options); + if (paths) { + this.sendPickerTelemetry(paths, options.telemetryEventName || 'openWorkspace', options.telemetryExtraData); + this.doOpenPicked(paths.map(path => ({ workspaceUri: URI.file(path) })), options, windowId); + } + } + + private doOpenPicked(openable: IWindowOpenable[], options: INativeOpenDialogOptions, windowId: number | undefined): void { + this.windowsMainService.open({ + context: OpenContext.DIALOG, + contextWindowId: windowId, + cli: this.environmentService.args, + urisToOpen: openable, + forceNewWindow: options.forceNewWindow + }); + } + + private sendPickerTelemetry(paths: string[], telemetryEventName: string, telemetryExtraData?: ITelemetryData) { + const numberOfPaths = paths ? paths.length : 0; + + // Telemetry + // __GDPR__TODO__ Dynamic event names and dynamic properties. Can not be registered statically. + this.telemetryService.publicLog(telemetryEventName, { + ...telemetryExtraData, + outcome: numberOfPaths ? 'success' : 'canceled', + numberOfPaths + }); } //#endregion //#region OS - async showItemInFolder(windowId: number, path: string): Promise { + async showItemInFolder(windowId: number | undefined, path: string): Promise { shell.showItemInFolder(path); } - async setRepresentedFilename(windowId: number, path: string): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async setRepresentedFilename(windowId: number | undefined, path: string): Promise { + const window = this.windowById(windowId); if (window) { window.setRepresentedFilename(path); } } - async setDocumentEdited(windowId: number, edited: boolean): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async setDocumentEdited(windowId: number | undefined, edited: boolean): Promise { + const window = this.windowById(windowId); if (window) { window.win.setDocumentEdited(edited); } } - async openExternal(windowId: number, url: string): Promise { - return this.windowsMainService.openExternal(url); + async openExternal(windowId: number | undefined, url: string): Promise { + shell.openExternal(url); + + return true; } - async updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async updateTouchBar(windowId: number | undefined, items: ISerializableCommandAction[][]): Promise { + const window = this.windowById(windowId); if (window) { window.updateTouchBar(items); } @@ -193,7 +299,7 @@ export class ElectronMainService implements AddContextToFunctions { - this.windowsMainService.openNewTabbedWindow(OpenContext.API); + this.windowsMainService.open({ context: OpenContext.API, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true }); } async showPreviousWindowTab(): Promise { @@ -220,44 +326,51 @@ export class ElectronMainService implements AddContextToFunctions { + async relaunch(windowId: number | undefined, options?: { addArgs?: string[], removeArgs?: string[] }): Promise { return this.lifecycleMainService.relaunch(options); } - async reload(windowId: number): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async reload(windowId: number | undefined, options?: { disableExtensions?: boolean }): Promise { + const window = this.windowById(windowId); if (window) { - return this.windowsMainService.reload(window); + return this.lifecycleMainService.reload(window, options?.disableExtensions ? { _: [], 'disable-extensions': true } : undefined); } } - async closeWorkpsace(windowId: number): Promise { - const window = this.windowsMainService.getWindowById(windowId); - if (window) { - return this.windowsMainService.closeWorkspace(window); - } - } - - async closeWindow(windowId: number): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async closeWindow(windowId: number | undefined): Promise { + const window = this.windowById(windowId); if (window) { return window.win.close(); } } - async quit(windowId: number): Promise { - return this.windowsMainService.quit(); + async quit(windowId: number | undefined): Promise { + + // If the user selected to exit from an extension development host window, do not quit, but just + // close the window unless this is the last window that is opened. + const window = this.windowsMainService.getLastActiveWindow(); + if (window?.isExtensionDevelopmentHost && this.windowsMainService.getWindowCount() > 1) { + window.win.close(); + } + + // Otherwise: normal quit + else { + setTimeout(() => { + this.lifecycleMainService.quit(); + }, 10 /* delay to unwind callback stack (IPC) */); + } } //#endregion //#region Connectivity - async resolveProxy(windowId: number, url: string): Promise { + async resolveProxy(windowId: number | undefined, url: string): Promise { return new Promise(resolve => { - const window = this.windowsMainService.getWindowById(windowId); - if (window && window.win && window.win.webContents && window.win.webContents.session) { - window.win.webContents.session.resolveProxy(url, proxy => resolve(proxy)); + const window = this.windowById(windowId); + const session = window?.win?.webContents?.session; + if (session) { + session.resolveProxy(url, proxy => resolve(proxy)); } else { resolve(); } @@ -268,18 +381,18 @@ export class ElectronMainService implements AddContextToFunctions { - const window = this.windowsMainService.getWindowById(windowId); + async openDevTools(windowId: number | undefined, options?: OpenDevToolsOptions): Promise { + const window = this.windowById(windowId); if (window) { window.win.webContents.openDevTools(options); } } - async toggleDevTools(windowId: number): Promise { - const window = this.windowsMainService.getWindowById(windowId); + async toggleDevTools(windowId: number | undefined): Promise { + const window = this.windowById(windowId); if (window) { const contents = window.win.webContents; - if (isMacintosh && window.hasHiddenTitleBarStyle() && !window.isFullScreen() && !contents.isDevToolsOpened()) { + if (isMacintosh && window.hasHiddenTitleBarStyle && !window.isFullScreen && !contents.isDevToolsOpened()) { contents.openDevTools({ mode: 'undocked' }); // due to https://github.com/electron/electron/issues/3647 } else { contents.toggleDevTools(); @@ -287,9 +400,17 @@ export class ElectronMainService implements AddContextToFunctions { + async startCrashReporter(windowId: number | undefined, options: CrashReporterStartOptions): Promise { crashReporter.start(options); } //#endregion + + private windowById(windowId: number | undefined): ICodeWindow | undefined { + if (typeof windowId !== 'number') { + return undefined; + } + + return this.windowsMainService.getWindowById(windowId); + } } diff --git a/src/vs/platform/electron/node/electron.ts b/src/vs/platform/electron/node/electron.ts index d7c33695d6d..294db26343a 100644 --- a/src/vs/platform/electron/node/electron.ts +++ b/src/vs/platform/electron/node/electron.ts @@ -3,10 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Event } from 'vs/base/common/event'; import { MessageBoxOptions, MessageBoxReturnValue, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, OpenDialogReturnValue, SaveDialogReturnValue, CrashReporterStartOptions } from 'electron'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { INativeOpenDialogOptions, IWindowOpenable, IOpenInWindowOptions, IOpenedWindow, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable, IOpenEmptyWindowOptions, IOpenedWindow } from 'vs/platform/windows/common/windows'; +import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; +import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window'; export const IElectronService = createDecorator('electronService'); @@ -14,12 +17,22 @@ export interface IElectronService { _serviceBrand: undefined; + // Events + readonly onWindowOpen: Event; + + readonly onWindowMaximize: Event; + readonly onWindowUnmaximize: Event; + + readonly onWindowFocus: Event; + readonly onWindowBlur: Event; + // Window getWindows(): Promise; getWindowCount(): Promise; + getActiveWindowId(): Promise; - openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise; - openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise; + openWindow(options?: IOpenEmptyWindowOptions): Promise; + openWindow(toOpen: IWindowOpenable[], options?: INativeOpenWindowOptions): Promise; toggleFullScreen(): Promise; @@ -30,6 +43,7 @@ export interface IElectronService { unmaximizeWindow(): Promise; minimizeWindow(): Promise; + isWindowFocused(): Promise; focusWindow(options?: { windowId?: number }): Promise; // Dialogs @@ -59,8 +73,7 @@ export interface IElectronService { // Lifecycle relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise; - reload(): Promise; - closeWorkpsace(): Promise; + reload(options?: { disableExtensions?: boolean }): Promise; closeWindow(): Promise; quit(): Promise; diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index fdd4e9997a0..eaa3bc1bae1 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -71,11 +71,16 @@ export interface ParsedArgs { 'driver-verbose'?: boolean; remote?: string; 'disable-user-env-probe'?: boolean; - 'disable-inspect'?: boolean; 'force'?: boolean; 'force-user-env'?: boolean; - // node flags + // chromium command line args: https://electronjs.org/docs/all#supported-chrome-command-line-switches + 'no-proxy-server'?: boolean; + 'proxy-server'?: string; + 'proxy-bypass-list'?: string; + 'proxy-pac-url'?: string; + 'inspect'?: string; + 'inspect-brk'?: string; 'js-flags'?: string; 'disable-gpu'?: boolean; 'nolazy'?: boolean; @@ -107,17 +112,18 @@ export interface IEnvironmentService { userHome: string; userDataPath: string; - appNameLong: string; - appQuality?: string; appSettingsHome: URI; // user roaming data userRoamingDataHome: URI; settingsResource: URI; - settingsSyncPreviewResource: URI; keybindingsResource: URI; keyboardLayoutResource: URI; - localeResource: URI; + argvResource: URI; + + // sync resources + userDataSyncLogResource: URI; + settingsSyncPreviewResource: URI; machineSettingsHome: URI; machineSettingsResource: URI; @@ -136,6 +142,7 @@ export interface IEnvironmentService { extensionsPath?: string; extensionDevelopmentLocationURI?: URI[]; extensionTestsLocationURI?: URI; + logExtensionHostCommunication?: boolean; debugExtensionHost: IExtensionHostDebugParams; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index e61113171d0..8176898aa76 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -7,13 +7,10 @@ import * as minimist from 'vscode-minimist'; import * as os from 'os'; import { localize } from 'vs/nls'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; -import { join } from 'vs/base/common/path'; -import { writeFileSync } from 'vs/base/node/pfs'; /** * This code is also used by standalone cli's. Avoid adding any other dependencies. */ - const helpCategories = { o: localize('optionsUpperCase', "Options"), e: localize('extensionsManagement', "Extensions Management"), @@ -109,10 +106,16 @@ export const OPTIONS: OptionDescriptions> = { 'trace': { type: 'boolean' }, 'trace-category-filter': { type: 'string' }, 'trace-options': { type: 'string' }, - 'disable-inspect': { type: 'boolean' }, 'force-user-env': { type: 'boolean' }, + // chromium flags + 'no-proxy-server': { type: 'boolean' }, + 'proxy-server': { type: 'string' }, + 'proxy-bypass-list': { type: 'string' }, + 'proxy-pac-url': { type: 'string' }, 'js-flags': { type: 'string' }, // chrome js flags + 'inspect': { type: 'string' }, + 'inspect-brk': { type: 'string' }, 'nolazy': { type: 'boolean' }, // node inspect '_urls': { type: 'string[]' }, @@ -155,7 +158,7 @@ export function parseArgs(args: string[], options: OptionDescriptions, err } } } - // remote aliases to avoid confusion + // remove aliases to avoid confusion const parsedArgs = minimist(args, { string, boolean, alias }); const cleanedArgs: any = {}; @@ -178,7 +181,7 @@ export function parseArgs(args: string[], options: OptionDescriptions, err delete parsedArgs[o.deprecates]; } - if (val) { + if (typeof val !== 'undefined') { if (o.type === 'string[]') { if (val && !Array.isArray(val)) { val = [val]; @@ -304,34 +307,3 @@ export function buildVersionMessage(version: string | undefined, commit: string return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`; } - -export function addArg(argv: string[], ...args: string[]): string[] { - const endOfArgsMarkerIndex = argv.indexOf('--'); - if (endOfArgsMarkerIndex === -1) { - argv.push(...args); - } else { - // if the we have an argument "--" (end of argument marker) - // we cannot add arguments at the end. rather, we add - // arguments before the "--" marker. - argv.splice(endOfArgsMarkerIndex, 0, ...args); - } - - return argv; -} - -export function createWaitMarkerFile(verbose?: boolean): string | undefined { - const randomWaitMarkerPath = join(os.tmpdir(), Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10)); - - try { - writeFileSync(randomWaitMarkerPath, ''); - if (verbose) { - console.log(`Marker file for --wait created: ${randomWaitMarkerPath}`); - } - return randomWaitMarkerPath; - } catch (err) { - if (verbose) { - console.error(`Failed to create marker file for --wait: ${err}`); - } - return undefined; - } -} diff --git a/src/vs/platform/environment/node/argvHelper.ts b/src/vs/platform/environment/node/argvHelper.ts index 1dd2f688934..2aef6dff05c 100644 --- a/src/vs/platform/environment/node/argvHelper.ts +++ b/src/vs/platform/environment/node/argvHelper.ts @@ -69,3 +69,17 @@ export function parseCLIProcessArgv(processArgv: string[]): ParsedArgs { return parseAndValidate(args, true); } + +export function addArg(argv: string[], ...args: string[]): string[] { + const endOfArgsMarkerIndex = argv.indexOf('--'); + if (endOfArgsMarkerIndex === -1) { + argv.push(...args); + } else { + // if the we have an argument "--" (end of argument marker) + // we cannot add arguments at the end. rather, we add + // arguments before the "--" marker. + argv.splice(endOfArgsMarkerIndex, 0, ...args); + } + + return argv; +} diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 0df72e178ad..cd86c866c06 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -95,7 +95,6 @@ export class EnvironmentService implements IEnvironmentService { @memoize get userDataPath(): string { const vscodePortable = process.env['VSCODE_PORTABLE']; - if (vscodePortable) { return path.join(vscodePortable, 'user-data'); } @@ -103,10 +102,6 @@ export class EnvironmentService implements IEnvironmentService { return parseUserDataDir(this._args, process); } - get appNameLong(): string { return product.nameLong; } - - get appQuality(): string | undefined { return product.quality; } - @memoize get appSettingsHome(): URI { return URI.file(path.join(this.userDataPath, 'User')); } @@ -119,6 +114,9 @@ export class EnvironmentService implements IEnvironmentService { @memoize get settingsSyncPreviewResource(): URI { return resources.joinPath(this.userRoamingDataHome, '.settings.json'); } + @memoize + get userDataSyncLogResource(): URI { return URI.file(path.join(this.logsPath, 'userDataSync.log')); } + @memoize get machineSettingsHome(): URI { return URI.file(path.join(this.userDataPath, 'Machine')); } @@ -138,7 +136,14 @@ export class EnvironmentService implements IEnvironmentService { get keyboardLayoutResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); } @memoize - get localeResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'locale.json'); } + get argvResource(): URI { + const vscodePortable = process.env['VSCODE_PORTABLE']; + if (vscodePortable) { + return URI.file(path.join(vscodePortable, 'argv.json')); + } + + return URI.file(path.join(this.userHome, product.dataFolderName, 'argv.json')); + } @memoize get isExtensionDevelopment(): boolean { return !!this._args.extensionDevelopmentPath; } @@ -179,7 +184,6 @@ export class EnvironmentService implements IEnvironmentService { } const vscodePortable = process.env['VSCODE_PORTABLE']; - if (vscodePortable) { return path.join(vscodePortable, 'extensions'); } @@ -231,6 +235,8 @@ export class EnvironmentService implements IEnvironmentService { @memoize get debugExtensionHost(): IExtensionHostDebugParams { return parseExtensionHostPort(this._args, this.isBuilt); } + @memoize + get logExtensionHostCommunication(): boolean { return !!this.args.logExtensionHostCommunication; } get isBuilt(): boolean { return !process.env['VSCODE_DEV']; } get verbose(): boolean { return !!this._args.verbose; } diff --git a/src/vs/platform/environment/node/waitMarkerFile.ts b/src/vs/platform/environment/node/waitMarkerFile.ts new file mode 100644 index 00000000000..8916ef40732 --- /dev/null +++ b/src/vs/platform/environment/node/waitMarkerFile.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. + *--------------------------------------------------------------------------------------------*/ + +/** + * This code is also used by standalone cli's. Avoid adding dependencies to keep the size of the cli small. + */ +import * as path from 'vs/base/common/path'; +import * as os from 'os'; +import * as fs from 'fs'; + +export function createWaitMarkerFile(verbose?: boolean): string | undefined { + const randomWaitMarkerPath = path.join(os.tmpdir(), Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10)); + + try { + fs.writeFileSync(randomWaitMarkerPath, ''); // use built-in fs to avoid dragging in more dependencies + if (verbose) { + console.log(`Marker file for --wait created: ${randomWaitMarkerPath}`); + } + return randomWaitMarkerPath; + } catch (err) { + if (verbose) { + console.error(`Failed to create marker file for --wait: ${err}`); + } + return undefined; + } +} diff --git a/src/vs/platform/extensionManagement/node/extensionLifecycle.ts b/src/vs/platform/extensionManagement/node/extensionLifecycle.ts index d252d404a60..25a4468ad4b 100644 --- a/src/vs/platform/extensionManagement/node/extensionLifecycle.ts +++ b/src/vs/platform/extensionManagement/node/extensionLifecycle.ts @@ -98,11 +98,11 @@ export class ExtensionsLifecycle extends Disposable { // Catch all output coming from the process type Output = { data: string, format: string[] }; - extensionUninstallProcess.stdout.setEncoding('utf8'); - extensionUninstallProcess.stderr.setEncoding('utf8'); + extensionUninstallProcess.stdout!.setEncoding('utf8'); + extensionUninstallProcess.stderr!.setEncoding('utf8'); - const onStdout = Event.fromNodeEventEmitter(extensionUninstallProcess.stdout, 'data'); - const onStderr = Event.fromNodeEventEmitter(extensionUninstallProcess.stderr, 'data'); + const onStdout = Event.fromNodeEventEmitter(extensionUninstallProcess.stdout!, 'data'); + const onStderr = Event.fromNodeEventEmitter(extensionUninstallProcess.stderr!, 'data'); // Log output onStdout(data => this.logService.info(extension.identifier.id, extension.manifest.version, `post-${lifecycleType}`, data)); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index f0eaa74a593..a36425204f7 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -153,7 +153,7 @@ export class ExtensionManagementService extends Disposable implements IExtension this.logService.trace('ExtensionManagementService#zip', extension.identifier.id); return this.collectFiles(extension) .then(files => zip(path.join(tmpdir(), generateUuid()), files)) - .then(path => URI.file(path)); + .then(path => URI.file(path)); } unzip(zipLocation: URI, type: ExtensionType): Promise { @@ -373,7 +373,7 @@ export class ExtensionManagementService extends Disposable implements IExtension return this.setUninstalled(extension) .then(() => this.removeUninstalledExtension(extension) .then( - () => this.installFromGallery(galleryExtension), + () => this.installFromGallery(galleryExtension).then(), e => Promise.reject(new Error(nls.localize('removeError', "Error while removing the extension: {0}. Please Quit and Start VS Code before trying again.", toErrorMessage(e)))))); } return Promise.reject(new Error(nls.localize('Not a Marketplace extension', "Only Marketplace Extensions can be reinstalled"))); @@ -524,10 +524,10 @@ export class ExtensionManagementService extends Disposable implements IExtension .then(galleryResult => { const extensionsToInstall = galleryResult.firstPage; return Promise.all(extensionsToInstall.map(e => this.installFromGallery(e))) - .then(() => null, errors => this.rollback(extensionsToInstall).then(() => Promise.reject(errors), () => Promise.reject(errors))); + .then(undefined, errors => this.rollback(extensionsToInstall).then(() => Promise.reject(errors), () => Promise.reject(errors))); }); } - return null; + return; }); } } @@ -548,7 +548,7 @@ export class ExtensionManagementService extends Disposable implements IExtension .then(installed => { const extensionToUninstall = installed.filter(e => areSameExtensions(e.identifier, extension.identifier))[0]; if (extensionToUninstall) { - return this.checkForDependenciesAndUninstall(extensionToUninstall, installed).then(() => null, error => Promise.reject(this.joinErrors(error))); + return this.checkForDependenciesAndUninstall(extensionToUninstall, installed).then(undefined, error => Promise.reject(this.joinErrors(error))); } else { return Promise.reject(new Error(nls.localize('notInstalled', "Extension '{0}' is not installed.", extension.manifest.displayName || extension.manifest.name))); } diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index a043fdfcaa3..99a37eaa9f2 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -88,6 +88,14 @@ export interface IColor { defaults: { light: string, dark: string, highContrast: string }; } +export interface IWebviewEditor { + readonly viewType: string; + readonly priority: string; + readonly selector: readonly { + readonly filenamePattern?: string; + }[]; +} + export interface IExtensionContributions { commands?: ICommand[]; configuration?: IConfiguration | IConfiguration[]; @@ -104,6 +112,7 @@ export interface IExtensionContributions { views?: { [location: string]: IView[] }; colors?: IColor[]; localizations?: ILocalization[]; + readonly webviewEditors?: readonly IWebviewEditor[]; } export type ExtensionKind = 'ui' | 'workspace' | 'web'; @@ -134,7 +143,7 @@ export interface IExtensionManifest { readonly activationEvents?: string[]; readonly extensionDependencies?: string[]; readonly extensionPack?: string[]; - readonly extensionKind?: ExtensionKind; + readonly extensionKind?: ExtensionKind | ExtensionKind[]; readonly contributes?: IExtensionContributions; readonly repository?: { url: string; }; readonly bugs?: { url: string; }; diff --git a/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts index 8efc34437f0..b789748febe 100644 --- a/src/vs/platform/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, IDisposable, toDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; -import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED } from 'vs/platform/files/common/files'; +import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED, hasFileReadStreamCapability, IFileSystemProviderWithFileReadStreamCapability, ensureFileSystemProviderError } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { isAbsolutePath, dirname, basename, joinPath, isEqual, isEqualOrParent } from 'vs/base/common/resources'; @@ -13,10 +13,13 @@ import { TernarySearchTree } from 'vs/base/common/map'; import { isNonEmptyArray, coalesce } from 'vs/base/common/arrays'; import { getBaseLabel } from 'vs/base/common/labels'; import { ILogService } from 'vs/platform/log/common/log'; -import { VSBuffer, VSBufferReadable, readableToBuffer, bufferToReadable, streamToBuffer, bufferToStream, VSBufferReadableStream, writeableBufferStream, VSBufferWriteableStream, isVSBufferReadableStream } from 'vs/base/common/buffer'; +import { VSBuffer, VSBufferReadable, readableToBuffer, bufferToReadable, streamToBuffer, bufferToStream, VSBufferReadableStream } from 'vs/base/common/buffer'; +import { isReadableStream, transform, ReadableStreamEvents, consumeReadableWithLimit, consumeStreamWithLimit } from 'vs/base/common/stream'; import { Queue } from 'vs/base/common/async'; import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; import { Schemas } from 'vs/base/common/network'; +import { assign } from 'vs/base/common/objects'; +import { createReadStream } from 'vs/platform/files/common/io'; export class FileService extends Disposable implements IFileService { @@ -118,14 +121,24 @@ export class FileService extends Disposable implements IFileService { return provider; } - private async withReadWriteProvider(resource: URI): Promise { + private async withReadProvider(resource: URI): Promise { + const provider = await this.withProvider(resource); + + if (hasOpenReadWriteCloseCapability(provider) || hasReadWriteCapability(provider) || hasFileReadStreamCapability(provider)) { + return provider; + } + + throw new Error('Provider neither has FileReadWrite, FileReadStream nor FileOpenReadWriteClose capability which is needed for the read operation.'); + } + + private async withWriteProvider(resource: URI): Promise { const provider = await this.withProvider(resource); if (hasOpenReadWriteCloseCapability(provider) || hasReadWriteCapability(provider)) { return provider; } - throw new Error('Provider neither has FileReadWrite nor FileOpenReadWriteClose capability which is needed for the operation.'); + throw new Error('Provider neither has FileReadWrite nor FileOpenReadWriteClose capability which is needed for the write operation.'); } //#endregion @@ -154,7 +167,7 @@ export class FileService extends Disposable implements IFileService { } // Bubble up any other error as is - throw this.ensureError(error); + throw ensureFileSystemProviderError(error); } } @@ -163,15 +176,15 @@ export class FileService extends Disposable implements IFileService { private async doResolveFile(resource: URI, options?: IResolveFileOptions): Promise { const provider = await this.withProvider(resource); - const resolveTo = options && options.resolveTo; - const resolveSingleChildDescendants = !!(options && options.resolveSingleChildDescendants); - const resolveMetadata = !!(options && options.resolveMetadata); + const resolveTo = options?.resolveTo; + const resolveSingleChildDescendants = options?.resolveSingleChildDescendants; + const resolveMetadata = options?.resolveMetadata; const stat = await provider.stat(resource); let trie: TernarySearchTree | undefined; - return this.toFileStat(provider, resource, stat, undefined, resolveMetadata, (stat, siblings) => { + return this.toFileStat(provider, resource, stat, undefined, !!resolveMetadata, (stat, siblings) => { // lazy trie to check for recursive resolving if (!trie) { @@ -274,8 +287,7 @@ export class FileService extends Disposable implements IFileService { async createFile(resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream = VSBuffer.fromString(''), options?: ICreateFileOptions): Promise { // validate overwrite - const overwrite = !!(options && options.overwrite); - if (!overwrite && await this.exists(resource)) { + if (!options?.overwrite && await this.exists(resource)) { throw new FileOperationError(localize('fileExists', "File to create already exists ({0})", this.resourceForError(resource)), FileOperationResult.FILE_MODIFIED_SINCE, options); } @@ -289,7 +301,7 @@ export class FileService extends Disposable implements IFileService { } async writeFile(resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: IWriteFileOptions): Promise { - const provider = this.throwIfFileSystemIsReadonly(await this.withReadWriteProvider(resource)); + const provider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(resource)); try { @@ -301,17 +313,29 @@ export class FileService extends Disposable implements IFileService { await this.mkdirp(provider, dirname(resource)); } - // write file: buffered - if (hasOpenReadWriteCloseCapability(provider)) { - await this.doWriteBuffered(provider, resource, bufferOrReadableOrStream instanceof VSBuffer ? bufferToReadable(bufferOrReadableOrStream) : bufferOrReadableOrStream); + // optimization: if the provider has unbuffered write capability and the data + // to write is a Readable, we consume up to 3 chunks and try to write the data + // unbuffered to reduce the overhead. If the Readable has more data to provide + // we continue to write buffered. + if (hasReadWriteCapability(provider) && !(bufferOrReadableOrStream instanceof VSBuffer)) { + if (isReadableStream(bufferOrReadableOrStream)) { + bufferOrReadableOrStream = await consumeStreamWithLimit(bufferOrReadableOrStream, data => VSBuffer.concat(data), 3); + } else { + bufferOrReadableOrStream = consumeReadableWithLimit(bufferOrReadableOrStream, data => VSBuffer.concat(data), 3); + } } - // write file: unbuffered - else { + // write file: unbuffered (only if data to write is a buffer, or the provider has no buffered write capability) + if (!hasOpenReadWriteCloseCapability(provider) || (hasReadWriteCapability(provider) && bufferOrReadableOrStream instanceof VSBuffer)) { await this.doWriteUnbuffered(provider, resource, bufferOrReadableOrStream); } + + // write file: buffered + else { + await this.doWriteBuffered(provider, resource, bufferOrReadableOrStream instanceof VSBuffer ? bufferToReadable(bufferOrReadableOrStream) : bufferOrReadableOrStream); + } } catch (error) { - throw new FileOperationError(localize('err.write', "Unable to write file ({0})", this.ensureError(error).toString()), toFileOperationResult(error), options); + throw new FileOperationError(localize('err.write', "Unable to write file ({0})", ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), options); } return this.resolve(resource, { resolveMetadata: true }); @@ -354,7 +378,16 @@ export class FileService extends Disposable implements IFileService { } async readFile(resource: URI, options?: IReadFileOptions): Promise { - const stream = await this.readFileStream(resource, options); + const provider = await this.withReadProvider(resource); + + const stream = await this.doReadAsFileStream(provider, resource, assign({ + // optimization: since we know that the caller does not + // care about buffering, we indicate this to the reader. + // this reduces all the overhead the buffered reading + // has (open, read, close) if the provider supports + // unbuffered reading. + preferUnbuffered: true + }, options || Object.create(null))); return { ...stream, @@ -363,7 +396,12 @@ export class FileService extends Disposable implements IFileService { } async readFileStream(resource: URI, options?: IReadFileOptions): Promise { - const provider = await this.withReadWriteProvider(resource); + const provider = await this.withReadProvider(resource); + + return this.doReadAsFileStream(provider, resource, options); + } + + private async doReadAsFileStream(provider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability | IFileSystemProviderWithFileReadStreamCapability, resource: URI, options?: IReadFileOptions & { preferUnbuffered?: boolean }): Promise { // install a cancellation token that gets cancelled // when any error occurs. this allows us to resolve @@ -390,14 +428,19 @@ export class FileService extends Disposable implements IFileService { let fileStreamPromise: Promise; - // read buffered - if (hasOpenReadWriteCloseCapability(provider)) { - fileStreamPromise = Promise.resolve(this.readFileBuffered(provider, resource, cancellableSource.token, options)); + // read unbuffered (only if either preferred, or the provider has no buffered read capability) + if (!(hasOpenReadWriteCloseCapability(provider) || hasFileReadStreamCapability(provider)) || (hasReadWriteCapability(provider) && options?.preferUnbuffered)) { + fileStreamPromise = this.readFileUnbuffered(provider, resource, options); } - // read unbuffered + // read streamed (always prefer over primitive buffered read) + else if (hasFileReadStreamCapability(provider)) { + fileStreamPromise = Promise.resolve(this.readFileStreamed(provider, resource, cancellableSource.token, options)); + } + + // read buffered else { - fileStreamPromise = this.readFileUnbuffered(provider, resource, options); + fileStreamPromise = Promise.resolve(this.readFileBuffered(provider, resource, cancellableSource.token, options)); } const [fileStat, fileStream] = await Promise.all([statPromise, fileStreamPromise]); @@ -407,74 +450,30 @@ export class FileService extends Disposable implements IFileService { value: fileStream }; } catch (error) { - throw new FileOperationError(localize('err.read', "Unable to read file ({0})", this.ensureError(error).toString()), toFileOperationResult(error), options); + throw new FileOperationError(localize('err.read', "Unable to read file ({0})", ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), options); } } - private readFileBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, token: CancellationToken, options?: IReadFileOptions): VSBufferReadableStream { - const stream = writeableBufferStream(); + private readFileStreamed(provider: IFileSystemProviderWithFileReadStreamCapability, resource: URI, token: CancellationToken, options: IReadFileOptions = Object.create(null)): VSBufferReadableStream { + const fileStream = provider.readFileStream(resource, options, token); - // do not await reading but simply return - // the stream directly since it operates - // via events. finally end the stream and - // send through the possible error - let error: Error | undefined = undefined; - this.doReadFileBuffered(provider, resource, stream, token, options).then(undefined, err => error = err).finally(() => stream.end(error)); - - return stream; + return this.transformFileReadStream(fileStream, options); } - private async doReadFileBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, stream: VSBufferWriteableStream, token: CancellationToken, options?: IReadFileOptions): Promise { + private readFileBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, token: CancellationToken, options: IReadFileOptions = Object.create(null)): VSBufferReadableStream { + const fileStream = createReadStream(provider, resource, { + ...options, + bufferSize: this.BUFFER_SIZE + }, token); - // open handle through provider - const handle = await provider.open(resource, { create: false }); + return this.transformFileReadStream(fileStream, options); + } - try { - let totalBytesRead = 0; - let bytesRead = 0; - let allowedRemainingBytes = (options && typeof options.length === 'number') ? options.length : undefined; - - let buffer = VSBuffer.alloc(Math.min(this.BUFFER_SIZE, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : this.BUFFER_SIZE)); - - let posInFile = options && typeof options.position === 'number' ? options.position : 0; - let posInBuffer = 0; - do { - // read from source (handle) at current position (pos) into buffer (buffer) at - // buffer position (posInBuffer) up to the size of the buffer (buffer.byteLength). - bytesRead = await provider.read(handle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer); - - posInFile += bytesRead; - posInBuffer += bytesRead; - totalBytesRead += bytesRead; - - if (typeof allowedRemainingBytes === 'number') { - allowedRemainingBytes -= bytesRead; - } - - // when buffer full, create a new one and emit it through stream - if (posInBuffer === buffer.byteLength) { - stream.write(buffer); - - buffer = VSBuffer.alloc(Math.min(this.BUFFER_SIZE, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : this.BUFFER_SIZE)); - - posInBuffer = 0; - } - } while (bytesRead > 0 && (typeof allowedRemainingBytes !== 'number' || allowedRemainingBytes > 0) && this.throwIfCancelled(token) && this.throwIfTooLarge(totalBytesRead, options)); - - // wrap up with last buffer (also respect maxBytes if provided) - if (posInBuffer > 0) { - let lastChunkLength = posInBuffer; - if (typeof allowedRemainingBytes === 'number') { - lastChunkLength = Math.min(posInBuffer, allowedRemainingBytes); - } - - stream.write(buffer.slice(0, lastChunkLength)); - } - } catch (error) { - throw this.ensureError(error); - } finally { - await provider.close(handle); - } + private transformFileReadStream(stream: ReadableStreamEvents, options: IReadFileOptions): VSBufferReadableStream { + return transform(stream, { + data: data => data instanceof VSBuffer ? data : VSBuffer.wrap(data), + error: error => new FileOperationError(localize('err.read', "Unable to read file ({0})", ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), options) + }, data => VSBuffer.concat(data)); } private async readFileUnbuffered(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, options?: IReadFileOptions): Promise { @@ -490,46 +489,59 @@ export class FileService extends Disposable implements IFileService { buffer = buffer.slice(0, options.length); } + // Throw if file is too large to load + this.validateReadFileLimits(buffer.byteLength, options); + return bufferToStream(VSBuffer.wrap(buffer)); } private async validateReadFile(resource: URI, options?: IReadFileOptions): Promise { const stat = await this.resolve(resource, { resolveMetadata: true }); - // Return early if resource is a directory + // Throw if resource is a directory if (stat.isDirectory) { throw new FileOperationError(localize('fileIsDirectoryError', "Expected file {0} is actually a directory", this.resourceForError(resource)), FileOperationResult.FILE_IS_DIRECTORY, options); } - // Return early if file not modified since (unless disabled) + // Throw if file not modified since (unless disabled) if (options && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED && options.etag === stat.etag) { throw new FileOperationError(localize('fileNotModifiedError', "File not modified since"), FileOperationResult.FILE_NOT_MODIFIED_SINCE, options); } - // Return early if file is too large to load - if (options && options.limits) { - if (typeof options.limits.memory === 'number' && stat.size > options.limits.memory) { - throw new FileOperationError(localize('fileTooLargeForHeapError', "To open a file of this size, you need to restart and allow it to use more memory"), FileOperationResult.FILE_EXCEED_MEMORY_LIMIT); - } - - if (typeof options.limits.size === 'number' && stat.size > options.limits.size) { - throw new FileOperationError(localize('fileTooLargeError', "File is too large to open"), FileOperationResult.FILE_TOO_LARGE); - } - } + // Throw if file is too large to load + this.validateReadFileLimits(stat.size, options); return stat; } + private validateReadFileLimits(size: number, options?: IReadFileOptions): void { + if (options?.limits) { + let tooLargeErrorResult: FileOperationResult | undefined = undefined; + + if (typeof options.limits.memory === 'number' && size > options.limits.memory) { + tooLargeErrorResult = FileOperationResult.FILE_EXCEEDS_MEMORY_LIMIT; + } + + if (typeof options.limits.size === 'number' && size > options.limits.size) { + tooLargeErrorResult = FileOperationResult.FILE_TOO_LARGE; + } + + if (typeof tooLargeErrorResult === 'number') { + throw new FileOperationError(localize('fileTooLargeError', "File is too large to open"), tooLargeErrorResult); + } + } + } + //#endregion //#region Move/Copy/Delete/Create Folder async move(source: URI, target: URI, overwrite?: boolean): Promise { - const sourceProvider = this.throwIfFileSystemIsReadonly(await this.withReadWriteProvider(source)); - const targetProvider = this.throwIfFileSystemIsReadonly(await this.withReadWriteProvider(target)); + const sourceProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(source)); + const targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target)); // move - const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'move', overwrite); + const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'move', !!overwrite); // resolve and send events const fileStat = await this.resolve(target, { resolveMetadata: true }); @@ -539,11 +551,11 @@ export class FileService extends Disposable implements IFileService { } async copy(source: URI, target: URI, overwrite?: boolean): Promise { - const sourceProvider = await this.withReadWriteProvider(source); - const targetProvider = this.throwIfFileSystemIsReadonly(await this.withReadWriteProvider(target)); + const sourceProvider = await this.withReadProvider(source); + const targetProvider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(target)); // copy - const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'copy', overwrite); + const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'copy', !!overwrite); // resolve and send events const fileStat = await this.resolve(target, { resolveMetadata: true }); @@ -552,7 +564,7 @@ export class FileService extends Disposable implements IFileService { return fileStat; } - private async doMoveCopy(sourceProvider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI, mode: 'move' | 'copy', overwrite?: boolean): Promise<'move' | 'copy'> { + private async doMoveCopy(sourceProvider: IFileSystemProvider, source: URI, targetProvider: IFileSystemProvider, target: URI, mode: 'move' | 'copy', overwrite: boolean): Promise<'move' | 'copy'> { if (source.toString() === target.toString()) { return mode; // simulate node.js behaviour here and do a no-op if paths match } @@ -573,7 +585,7 @@ export class FileService extends Disposable implements IFileService { // same provider with fast copy: leverage copy() functionality if (sourceProvider === targetProvider && hasFileFolderCopyCapability(sourceProvider)) { - await sourceProvider.copy(source, target, { overwrite: !!overwrite }); + await sourceProvider.copy(source, target, { overwrite }); } // when copying via buffer/unbuffered, we have to manually @@ -595,7 +607,7 @@ export class FileService extends Disposable implements IFileService { // same provider: leverage rename() functionality if (sourceProvider === targetProvider) { - await sourceProvider.rename(source, target, { overwrite: !!overwrite }); + await sourceProvider.rename(source, target, { overwrite }); return mode; } @@ -744,13 +756,13 @@ export class FileService extends Disposable implements IFileService { const provider = this.throwIfFileSystemIsReadonly(await this.withProvider(resource)); // Validate trash support - const useTrash = !!(options && options.useTrash); + const useTrash = !!options?.useTrash; if (useTrash && !(provider.capabilities & FileSystemProviderCapabilities.Trash)) { throw new Error(localize('err.trash', "Provider does not support trash.")); } // Validate recursive - const recursive = !!(options && options.recursive); + const recursive = !!options?.recursive; if (!recursive && await this.exists(resource)) { const stat = await this.resolve(resource); if (stat.isDirectory && Array.isArray(stat.children) && stat.children.length > 0) { @@ -872,13 +884,13 @@ export class FileService extends Disposable implements IFileService { // write into handle until all bytes from buffer have been written try { - if (isVSBufferReadableStream(readableOrStream)) { + if (isReadableStream(readableOrStream)) { await this.doWriteStreamBufferedQueued(provider, handle, readableOrStream); } else { await this.doWriteReadableBufferedQueued(provider, handle, readableOrStream); } } catch (error) { - throw this.ensureError(error); + throw ensureFileSystemProviderError(error); } finally { // close handle always @@ -920,7 +932,7 @@ export class FileService extends Disposable implements IFileService { let posInFile = 0; let chunk: VSBuffer | null; - while (chunk = readable.read()) { + while ((chunk = readable.read()) !== null) { await this.doWriteBuffer(provider, handle, chunk, chunk.byteLength, posInFile, 0); posInFile += chunk.byteLength; @@ -943,7 +955,7 @@ export class FileService extends Disposable implements IFileService { let buffer: VSBuffer; if (bufferOrReadableOrStream instanceof VSBuffer) { buffer = bufferOrReadableOrStream; - } else if (isVSBufferReadableStream(bufferOrReadableOrStream)) { + } else if (isReadableStream(bufferOrReadableOrStream)) { buffer = await streamToBuffer(bufferOrReadableOrStream); } else { buffer = readableToBuffer(bufferOrReadableOrStream); @@ -989,7 +1001,7 @@ export class FileService extends Disposable implements IFileService { } } while (bytesRead > 0); } catch (error) { - throw this.ensureError(error); + throw ensureFileSystemProviderError(error); } finally { await Promise.all([ typeof sourceHandle === 'number' ? sourceProvider.close(sourceHandle) : Promise.resolve(), @@ -1020,7 +1032,7 @@ export class FileService extends Disposable implements IFileService { const buffer = await sourceProvider.readFile(source); await this.doWriteBuffer(targetProvider, targetHandle, VSBuffer.wrap(buffer), buffer.byteLength, 0, 0); } catch (error) { - throw this.ensureError(error); + throw ensureFileSystemProviderError(error); } finally { await targetProvider.close(targetHandle); } @@ -1043,38 +1055,6 @@ export class FileService extends Disposable implements IFileService { return provider; } - private throwIfCancelled(token: CancellationToken): boolean { - if (token.isCancellationRequested) { - throw new Error('cancelled'); - } - - return true; - } - - private ensureError(error?: Error): Error { - if (!error) { - return new Error(localize('unknownError', "Unknown Error")); // https://github.com/Microsoft/vscode/issues/72798 - } - - return error; - } - - private throwIfTooLarge(totalBytesRead: number, options?: IReadFileOptions): boolean { - - // Return early if file is too large to load - if (options && options.limits) { - if (typeof options.limits.memory === 'number' && totalBytesRead > options.limits.memory) { - throw new FileOperationError(localize('fileTooLargeForHeapError', "To open a file of this size, you need to restart and allow it to use more memory"), FileOperationResult.FILE_EXCEED_MEMORY_LIMIT); - } - - if (typeof options.limits.size === 'number' && totalBytesRead > options.limits.size) { - throw new FileOperationError(localize('fileTooLargeError', "File is too large to open"), FileOperationResult.FILE_TOO_LARGE); - } - } - - return true; - } - private resourceForError(resource: URI): string { if (resource.scheme === Schemas.file) { return resource.fsPath; diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 04788f62ec1..0356e8dfdd3 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { localize } from 'vs/nls'; import { sep } from 'vs/base/common/path'; import { URI } from 'vs/base/common/uri'; import * as glob from 'vs/base/common/glob'; @@ -13,6 +14,8 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { isEqualOrParent, isEqual } from 'vs/base/common/resources'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer'; +import { ReadableStreamEvents } from 'vs/base/common/stream'; +import { CancellationToken } from 'vs/base/common/cancellation'; export const IFileService = createDecorator('fileService'); @@ -158,6 +161,29 @@ export interface FileOverwriteOptions { overwrite: boolean; } +export interface FileReadStreamOptions { + + /** + * Is an integer specifying where to begin reading from in the file. If position is undefined, + * data will be read from the current file position. + */ + readonly position?: number; + + /** + * Is an integer specifying how many bytes to read from the file. By default, all bytes + * will be read. + */ + readonly length?: number; + + /** + * If provided, the size of the file will be checked against the limits. + */ + limits?: { + readonly size?: number; + readonly memory?: number; + }; +} + export interface FileWriteOptions { overwrite: boolean; create: boolean; @@ -194,6 +220,8 @@ export interface IWatchOptions { export const enum FileSystemProviderCapabilities { FileReadWrite = 1 << 1, FileOpenReadWriteClose = 1 << 2, + FileReadStream = 1 << 4, + FileFolderCopy = 1 << 3, PathCaseSensitive = 1 << 10, @@ -209,7 +237,7 @@ export interface IFileSystemProvider { readonly onDidErrorOccur?: Event; // TODO@ben remove once file watchers are solid - readonly onDidChangeFile: Event; + readonly onDidChangeFile: Event; watch(resource: URI, opts: IWatchOptions): IDisposable; stat(resource: URI): Promise; @@ -223,6 +251,8 @@ export interface IFileSystemProvider { readFile?(resource: URI): Promise; writeFile?(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise; + readFileStream?(resource: URI, opts: FileReadStreamOptions, token?: CancellationToken): ReadableStreamEvents; + open?(resource: URI, opts: FileOpenOptions): Promise; close?(fd: number): Promise; read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise; @@ -257,11 +287,21 @@ export function hasOpenReadWriteCloseCapability(provider: IFileSystemProvider): return !!(provider.capabilities & FileSystemProviderCapabilities.FileOpenReadWriteClose); } +export interface IFileSystemProviderWithFileReadStreamCapability extends IFileSystemProvider { + readFileStream(resource: URI, opts: FileReadStreamOptions, token?: CancellationToken): ReadableStreamEvents; +} + +export function hasFileReadStreamCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileReadStreamCapability { + return !!(provider.capabilities & FileSystemProviderCapabilities.FileReadStream); +} + export enum FileSystemProviderErrorCode { FileExists = 'EntryExists', FileNotFound = 'EntryNotFound', FileNotADirectory = 'EntryNotADirectory', FileIsADirectory = 'EntryIsADirectory', + FileExceedsMemoryLimit = 'EntryExceedsMemoryLimit', + FileTooLarge = 'EntryTooLarge', NoPermissions = 'NoPermissions', Unavailable = 'Unavailable', Unknown = 'Unknown' @@ -274,13 +314,21 @@ export class FileSystemProviderError extends Error { } } -export function createFileSystemProviderError(error: Error, code: FileSystemProviderErrorCode): FileSystemProviderError { +export function createFileSystemProviderError(error: Error | string, code: FileSystemProviderErrorCode): FileSystemProviderError { const providerError = new FileSystemProviderError(error.toString(), code); markAsFileSystemProviderError(providerError, code); return providerError; } +export function ensureFileSystemProviderError(error?: Error): Error { + if (!error) { + return createFileSystemProviderError(localize('unknownError', "Unknown Error"), FileSystemProviderErrorCode.Unknown); // https://github.com/Microsoft/vscode/issues/72798 + } + + return error; +} + export function markAsFileSystemProviderError(error: Error, code: FileSystemProviderErrorCode): Error { error.name = code ? `${code} (FileSystemError)` : `FileSystemError`; @@ -311,6 +359,8 @@ export function toFileSystemProviderErrorCode(error: Error | undefined | null): case FileSystemProviderErrorCode.FileIsADirectory: return FileSystemProviderErrorCode.FileIsADirectory; case FileSystemProviderErrorCode.FileNotADirectory: return FileSystemProviderErrorCode.FileNotADirectory; case FileSystemProviderErrorCode.FileNotFound: return FileSystemProviderErrorCode.FileNotFound; + case FileSystemProviderErrorCode.FileExceedsMemoryLimit: return FileSystemProviderErrorCode.FileExceedsMemoryLimit; + case FileSystemProviderErrorCode.FileTooLarge: return FileSystemProviderErrorCode.FileTooLarge; case FileSystemProviderErrorCode.NoPermissions: return FileSystemProviderErrorCode.NoPermissions; case FileSystemProviderErrorCode.Unavailable: return FileSystemProviderErrorCode.Unavailable; } @@ -335,7 +385,10 @@ export function toFileOperationResult(error: Error): FileOperationResult { return FileOperationResult.FILE_PERMISSION_DENIED; case FileSystemProviderErrorCode.FileExists: return FileOperationResult.FILE_MOVE_CONFLICT; - case FileSystemProviderErrorCode.FileNotADirectory: + case FileSystemProviderErrorCode.FileExceedsMemoryLimit: + return FileOperationResult.FILE_EXCEEDS_MEMORY_LIMIT; + case FileSystemProviderErrorCode.FileTooLarge: + return FileOperationResult.FILE_TOO_LARGE; default: return FileOperationResult.FILE_OTHER_ERROR; } @@ -389,19 +442,19 @@ export interface IFileChange { /** * The type of change that occurred to the file. */ - type: FileChangeType; + readonly type: FileChangeType; /** * The unified resource identifier of the file that changed. */ - resource: URI; + readonly resource: URI; } export class FileChangesEvent { - private _changes: IFileChange[]; + private readonly _changes: readonly IFileChange[]; - constructor(changes: IFileChange[]) { + constructor(changes: readonly IFileChange[]) { this._changes = changes; } @@ -612,7 +665,7 @@ export interface IFileStreamContent extends IBaseStatWithMetadata { value: VSBufferReadableStream; } -export interface IReadFileOptions { +export interface IReadFileOptions extends FileReadStreamOptions { /** * The optional etag parameter allows to return early from resolving the resource if @@ -621,26 +674,6 @@ export interface IReadFileOptions { * It is the task of the caller to makes sure to handle this error case from the promise. */ readonly etag?: string; - - /** - * Is an integer specifying where to begin reading from in the file. If position is null, - * data will be read from the current file position. - */ - readonly position?: number; - - /** - * Is an integer specifying how many bytes to read from the file. By default, all bytes - * will be read. - */ - readonly length?: number; - - /** - * If provided, the size of the file will be checked against the limits. - */ - limits?: { - readonly size?: number; - readonly memory?: number; - }; } export interface IWriteFileOptions { @@ -709,7 +742,7 @@ export const enum FileOperationResult { FILE_PERMISSION_DENIED, FILE_TOO_LARGE, FILE_INVALID_PATH, - FILE_EXCEED_MEMORY_LIMIT, + FILE_EXCEEDS_MEMORY_LIMIT, FILE_OTHER_ERROR } diff --git a/src/vs/platform/files/common/io.ts b/src/vs/platform/files/common/io.ts new file mode 100644 index 00000000000..1fb8ff0b285 --- /dev/null +++ b/src/vs/platform/files/common/io.ts @@ -0,0 +1,114 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { VSBuffer, VSBufferWriteableStream, newWriteableBufferStream, VSBufferReadableStream } from 'vs/base/common/buffer'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IFileSystemProviderWithOpenReadWriteCloseCapability, FileReadStreamOptions, createFileSystemProviderError, FileSystemProviderErrorCode, ensureFileSystemProviderError } from 'vs/platform/files/common/files'; +import { canceled } from 'vs/base/common/errors'; + +export interface ICreateReadStreamOptions extends FileReadStreamOptions { + + /** + * The size of the buffer to use before sending to the stream. + */ + bufferSize: number; +} + +export function createReadStream(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, options: ICreateReadStreamOptions, token?: CancellationToken): VSBufferReadableStream { + const stream = newWriteableBufferStream(); + + // do not await reading but simply return the stream directly since it operates + // via events. finally end the stream and send through the possible error + let error: Error | undefined = undefined; + + doReadFileIntoStream(provider, resource, stream, options, token).then(undefined, err => error = err).finally(() => stream.end(error)); + + return stream; +} + +async function doReadFileIntoStream(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, stream: VSBufferWriteableStream, options: ICreateReadStreamOptions, token?: CancellationToken): Promise { + + // Check for cancellation + throwIfCancelled(token); + + // open handle through provider + const handle = await provider.open(resource, { create: false }); + + // Check for cancellation + throwIfCancelled(token); + + try { + let totalBytesRead = 0; + let bytesRead = 0; + let allowedRemainingBytes = (options && typeof options.length === 'number') ? options.length : undefined; + + let buffer = VSBuffer.alloc(Math.min(options.bufferSize, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : options.bufferSize)); + + let posInFile = options && typeof options.position === 'number' ? options.position : 0; + let posInBuffer = 0; + do { + // read from source (handle) at current position (pos) into buffer (buffer) at + // buffer position (posInBuffer) up to the size of the buffer (buffer.byteLength). + bytesRead = await provider.read(handle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer); + + posInFile += bytesRead; + posInBuffer += bytesRead; + totalBytesRead += bytesRead; + + if (typeof allowedRemainingBytes === 'number') { + allowedRemainingBytes -= bytesRead; + } + + // when buffer full, create a new one and emit it through stream + if (posInBuffer === buffer.byteLength) { + stream.write(buffer); + + buffer = VSBuffer.alloc(Math.min(options.bufferSize, typeof allowedRemainingBytes === 'number' ? allowedRemainingBytes : options.bufferSize)); + + posInBuffer = 0; + } + } while (bytesRead > 0 && (typeof allowedRemainingBytes !== 'number' || allowedRemainingBytes > 0) && throwIfCancelled(token) && throwIfTooLarge(totalBytesRead, options)); + + // wrap up with last buffer (also respect maxBytes if provided) + if (posInBuffer > 0) { + let lastChunkLength = posInBuffer; + if (typeof allowedRemainingBytes === 'number') { + lastChunkLength = Math.min(posInBuffer, allowedRemainingBytes); + } + + stream.write(buffer.slice(0, lastChunkLength)); + } + } catch (error) { + throw ensureFileSystemProviderError(error); + } finally { + await provider.close(handle); + } +} + +function throwIfCancelled(token?: CancellationToken): boolean { + if (token && token.isCancellationRequested) { + throw canceled(); + } + + return true; +} + +function throwIfTooLarge(totalBytesRead: number, options: ICreateReadStreamOptions): boolean { + + // Return early if file is too large to load and we have configured limits + if (options?.limits) { + if (typeof options.limits.memory === 'number' && totalBytesRead > options.limits.memory) { + throw createFileSystemProviderError(localize('fileTooLargeForHeapError', "To open a file of this size, you need to restart and allow it to use more memory"), FileSystemProviderErrorCode.FileExceedsMemoryLimit); + } + + if (typeof options.limits.size === 'number' && totalBytesRead > options.limits.size) { + throw createFileSystemProviderError(localize('fileTooLargeError', "File is too large to open"), FileSystemProviderErrorCode.FileTooLarge); + } + } + + return true; +} diff --git a/src/vs/platform/files/node/diskFileSystemProvider.ts b/src/vs/platform/files/node/diskFileSystemProvider.ts index d66ef03839c..7c7e255d80e 100644 --- a/src/vs/platform/files/node/diskFileSystemProvider.ts +++ b/src/vs/platform/files/node/diskFileSystemProvider.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { mkdir, open, close, read, write, fdatasync } from 'fs'; +import { mkdir, open, close, read, write, fdatasync, Dirent, Stats } from 'fs'; import { promisify } from 'util'; import { IDisposable, Disposable, toDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; -import { IFileSystemProvider, FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, FileSystemProviderErrorCode, createFileSystemProviderError, FileSystemProviderError } from 'vs/platform/files/common/files'; +import { FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, FileSystemProviderErrorCode, createFileSystemProviderError, FileSystemProviderError, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, FileReadStreamOptions, IFileSystemProviderWithFileFolderCopyCapability } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { isLinux, isWindows } from 'vs/base/common/platform'; -import { statLink, readdir, unlink, move, copy, readFile, truncate, rimraf, RimRafMode, exists } from 'vs/base/node/pfs'; +import { statLink, unlink, move, copy, readFile, truncate, rimraf, RimRafMode, exists, readdirWithFileTypes } from 'vs/base/node/pfs'; import { normalize, basename, dirname } from 'vs/base/common/path'; import { joinPath } from 'vs/base/common/resources'; import { isEqual } from 'vs/base/common/extpath'; @@ -22,15 +22,30 @@ import { FileWatcher as UnixWatcherService } from 'vs/platform/files/node/watche import { FileWatcher as WindowsWatcherService } from 'vs/platform/files/node/watcher/win32/watcherService'; import { FileWatcher as NsfwWatcherService } from 'vs/platform/files/node/watcher/nsfw/watcherService'; import { FileWatcher as NodeJSWatcherService } from 'vs/platform/files/node/watcher/nodejs/watcherService'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { ReadableStreamEvents, transform } from 'vs/base/common/stream'; +import { createReadStream } from 'vs/platform/files/common/io'; export interface IWatcherOptions { pollingInterval?: number; usePolling: boolean; } -export class DiskFileSystemProvider extends Disposable implements IFileSystemProvider { +export interface IDiskFileSystemProviderOptions { + bufferSize?: number; + watcher?: IWatcherOptions; +} - constructor(private logService: ILogService, private watcherOptions?: IWatcherOptions) { +export class DiskFileSystemProvider extends Disposable implements + IFileSystemProviderWithFileReadWriteCapability, + IFileSystemProviderWithOpenReadWriteCloseCapability, + IFileSystemProviderWithFileReadStreamCapability, + IFileSystemProviderWithFileFolderCopyCapability { + + private readonly BUFFER_SIZE = this.options?.bufferSize || 64 * 1024; + + constructor(private logService: ILogService, private options?: IDiskFileSystemProviderOptions) { super(); } @@ -44,6 +59,7 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro this._capabilities = FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.FileOpenReadWriteClose | + FileSystemProviderCapabilities.FileReadStream | FileSystemProviderCapabilities.FileFolderCopy; if (isLinux) { @@ -62,15 +78,8 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro try { const { stat, isSymbolicLink } = await statLink(this.toFilePath(resource)); // cannot use fs.stat() here to support links properly - let type: number; - if (isSymbolicLink) { - type = FileType.SymbolicLink | (stat.isDirectory() ? FileType.Directory : FileType.File); - } else { - type = stat.isFile() ? FileType.File : stat.isDirectory() ? FileType.Directory : FileType.Unknown; - } - return { - type, + type: this.toType(stat, isSymbolicLink), ctime: stat.ctime.getTime(), mtime: stat.mtime.getTime(), size: stat.size @@ -82,13 +91,19 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro async readdir(resource: URI): Promise<[string, FileType][]> { try { - const children = await readdir(this.toFilePath(resource)); + const children = await readdirWithFileTypes(this.toFilePath(resource)); const result: [string, FileType][] = []; await Promise.all(children.map(async child => { try { - const stat = await this.stat(joinPath(resource, child)); - result.push([child, stat.type]); + let type: FileType; + if (child.isSymbolicLink()) { + type = (await this.stat(joinPath(resource, child.name))).type; // always resolve target the link points to if any + } else { + type = this.toType(child); + } + + result.push([child.name, type]); } catch (error) { this.logService.trace(error); // ignore errors for individual entries that can arise from permission denied } @@ -100,6 +115,14 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro } } + private toType(entry: Stats | Dirent, isSymbolicLink = entry.isSymbolicLink()): FileType { + if (isSymbolicLink) { + return FileType.SymbolicLink | (entry.isDirectory() ? FileType.Directory : FileType.File); + } + + return entry.isFile() ? FileType.File : entry.isDirectory() ? FileType.Directory : FileType.Unknown; + } + //#endregion //#region File Reading/Writing @@ -114,17 +137,32 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro } } + readFileStream(resource: URI, opts: FileReadStreamOptions, token?: CancellationToken): ReadableStreamEvents { + const fileStream = createReadStream(this, resource, { + ...opts, + bufferSize: this.BUFFER_SIZE + }, token); + + return transform(fileStream, { data: data => data.buffer }, data => VSBuffer.concat(data.map(data => VSBuffer.wrap(data))).buffer); + } + 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); + // Validate target unless { create: true, overwrite: true } + if (!opts.create || !opts.overwrite) { + const fileExists = await exists(filePath); + if (fileExists) { + if (!opts.overwrite) { + throw createFileSystemProviderError(localize('fileExists', "File already exists"), FileSystemProviderErrorCode.FileExists); + } + } else { + if (!opts.create) { + throw createFileSystemProviderError(localize('fileNotExists', "File does not exist"), FileSystemProviderErrorCode.FileNotFound); + } + } } // Open @@ -373,7 +411,7 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro try { // Ensure target does not exist - await this.validateTargetDeleted(from, to, 'move', opts && opts.overwrite); + await this.validateTargetDeleted(from, to, 'move', opts.overwrite); // Move await move(fromFilePath, toFilePath); @@ -400,7 +438,7 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro try { // Ensure target does not exist - await this.validateTargetDeleted(from, to, 'copy', opts && opts.overwrite); + await this.validateTargetDeleted(from, to, 'copy', opts.overwrite); // Copy await copy(fromFilePath, toFilePath); @@ -428,13 +466,13 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro } if (isSameResourceWithDifferentPathCase && mode === 'copy') { - throw createFileSystemProviderError(new Error('File cannot be copied to same path with different path case'), FileSystemProviderErrorCode.FileExists); + throw createFileSystemProviderError(localize('fileCopyErrorPathCase', "'File cannot be copied to same path with different path case"), FileSystemProviderErrorCode.FileExists); } // handle existing target (unless this is a case change) if (!isSameResourceWithDifferentPathCase && await exists(toFilePath)) { if (!overwrite) { - throw createFileSystemProviderError(new Error('File at target already exists'), FileSystemProviderErrorCode.FileExists); + throw createFileSystemProviderError(localize('fileCopyErrorExists', "File at target already exists"), FileSystemProviderErrorCode.FileExists); } // Delete target @@ -449,8 +487,8 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro private _onDidWatchErrorOccur: Emitter = this._register(new Emitter()); readonly onDidErrorOccur: Event = this._onDidWatchErrorOccur.event; - private _onDidChangeFile: Emitter = this._register(new Emitter()); - get onDidChangeFile(): Event { return this._onDidChangeFile.event; } + private _onDidChangeFile = this._register(new Emitter()); + get onDidChangeFile(): Event { return this._onDidChangeFile.event; } private recursiveWatcher: WindowsWatcherService | UnixWatcherService | NsfwWatcherService | undefined; private recursiveFoldersToWatch: { path: string, excludes: string[] }[] = []; @@ -525,9 +563,9 @@ export class DiskFileSystemProvider extends Disposable implements IFileSystemPro let watcherOptions: IWatcherOptions | undefined = undefined; // requires a polling watcher - if (this.watcherOptions && this.watcherOptions.usePolling) { + if (this.options?.watcher?.usePolling) { watcherImpl = UnixWatcherService; - watcherOptions = this.watcherOptions; + watcherOptions = this.options?.watcher; } // Single Folder Watcher diff --git a/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts index 582d0bc8754..4c21c4dd045 100644 --- a/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts +++ b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts @@ -244,14 +244,14 @@ export class NsfwWatcherService implements IWatcherService { } private log(message: string) { - this._onLogMessage.fire({ type: 'trace', message: `[File Watcher (nswf)] ` + message }); + this._onLogMessage.fire({ type: 'trace', message: `[File Watcher (nsfw)] ` + message }); } private warn(message: string) { - this._onLogMessage.fire({ type: 'warn', message: `[File Watcher (nswf)] ` + message }); + this._onLogMessage.fire({ type: 'warn', message: `[File Watcher (nsfw)] ` + message }); } private error(message: string) { - this._onLogMessage.fire({ type: 'error', message: `[File Watcher (nswf)] ` + message }); + this._onLogMessage.fire({ type: 'error', message: `[File Watcher (nsfw)] ` + message }); } } diff --git a/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts index f12dfef68bc..c91a6a829c9 100644 --- a/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts +++ b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts @@ -17,6 +17,9 @@ import { isMacintosh, isLinux } from 'vs/base/common/platform'; import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/platform/files/node/watcher/watcher'; import { IWatcherRequest, IWatcherService, IWatcherOptions } from 'vs/platform/files/node/watcher/unix/watcher'; import { Emitter, Event } from 'vs/base/common/event'; +import { equals } from 'vs/base/common/arrays'; + +process.noAsar = true; // disable ASAR support in watcher process interface IWatcher { requests: ExtendedWatcherRequest[]; @@ -32,8 +35,8 @@ export class ChokidarWatcherService implements IWatcherService { private static readonly FS_EVENT_DELAY = 50; // aggregate and only emit events when changes have stopped for this duration (in ms) private static readonly EVENT_SPAM_WARNING_THRESHOLD = 60 * 1000; // warn after certain time span of event spam - private _watchers: { [watchPath: string]: IWatcher }; - private _watcherCount: number; + private _watchers: { [watchPath: string]: IWatcher } = Object.create(null); + private _watcherCount = 0; private _pollingInterval?: number; private _usePolling?: boolean; @@ -49,29 +52,30 @@ export class ChokidarWatcherService implements IWatcherService { private readonly _onLogMessage = new Emitter(); readonly onLogMessage: Event = this._onLogMessage.event; - public watch(options: IWatcherOptions): Event { + watch(options: IWatcherOptions): Event { this._pollingInterval = options.pollingInterval; this._usePolling = options.usePolling; this._watchers = Object.create(null); this._watcherCount = 0; + return this.onWatchEvent; } - public setVerboseLogging(enabled: boolean): Promise { + setVerboseLogging(enabled: boolean): Promise { this._verboseLogging = enabled; return Promise.resolve(); } - public setRoots(requests: IWatcherRequest[]): Promise { + setRoots(requests: IWatcherRequest[]): Promise { const watchers = Object.create(null); const newRequests: string[] = []; const requestsByBasePath = normalizeRoots(requests); // evaluate new & remaining watchers - for (let basePath in requestsByBasePath) { - let watcher = this._watchers[basePath]; + for (const basePath in requestsByBasePath) { + const watcher = this._watchers[basePath]; if (watcher && isEqualRequests(watcher.requests, requestsByBasePath[basePath])) { watchers[basePath] = watcher; delete this._watchers[basePath]; @@ -79,13 +83,15 @@ export class ChokidarWatcherService implements IWatcherService { newRequests.push(basePath); } } + // stop all old watchers - for (let path in this._watchers) { + for (const path in this._watchers) { this._watchers[path].stop(); } + // start all new watchers - for (let basePath of newRequests) { - let requests = requestsByBasePath[basePath]; + for (const basePath of newRequests) { + const requests = requestsByBasePath[basePath]; watchers[basePath] = this._watch(basePath, requests); } @@ -94,7 +100,7 @@ export class ChokidarWatcherService implements IWatcherService { } // for test purposes - public get wacherCount() { + get wacherCount() { return this._watcherCount; } @@ -120,9 +126,10 @@ export class ChokidarWatcherService implements IWatcherService { }; const excludes: string[] = []; - // if there's only one request, use the built-in ignore-filterering + const isSingleFolder = requests.length === 1; if (isSingleFolder) { + // if there's only one request, use the built-in ignore-filterering excludes.push(...requests[0].excludes); } @@ -132,6 +139,9 @@ export class ChokidarWatcherService implements IWatcherService { excludes.push('/proc/**', '/sys/**'); } } + + excludes.push('**/*.asar'); // Ensure we never recurse into ASAR archives + watcherOpts.ignored = excludes; // Chokidar fails when the basePath does not match case-identical to the path on disk @@ -219,7 +229,7 @@ export class ChokidarWatcherService implements IWatcherService { } } - let event = { type: eventType, path }; + const event = { type: eventType, path }; // Logging if (this._verboseLogging) { @@ -283,12 +293,14 @@ export class ChokidarWatcherService implements IWatcherService { return watcher; } - public stop(): Promise { - for (let path in this._watchers) { - let watcher = this._watchers[path]; + stop(): Promise { + for (const path in this._watchers) { + const watcher = this._watchers[path]; watcher.stop(); } + this._watchers = Object.create(null); + return Promise.resolve(); } @@ -306,25 +318,28 @@ export class ChokidarWatcherService implements IWatcherService { } function isIgnored(path: string, requests: ExtendedWatcherRequest[]): boolean { - for (let request of requests) { + for (const request of requests) { if (request.path === path) { return false; } + if (extpath.isEqualOrParent(path, request.path)) { if (!request.parsedPattern) { if (request.excludes && request.excludes.length > 0) { - let pattern = `{${request.excludes.join(',')}}`; + const pattern = `{${request.excludes.join(',')}}`; request.parsedPattern = glob.parse(pattern); } else { request.parsedPattern = () => false; } } + const relPath = path.substr(request.path.length + 1); if (!request.parsedPattern(relPath)) { return false; } } } + return true; } @@ -334,11 +349,12 @@ function isIgnored(path: string, requests: ExtendedWatcherRequest[]): boolean { */ export function normalizeRoots(requests: IWatcherRequest[]): { [basePath: string]: IWatcherRequest[] } { requests = requests.sort((r1, r2) => r1.path.localeCompare(r2.path)); + let prevRequest: IWatcherRequest | null = null; - let result: { [basePath: string]: IWatcherRequest[] } = Object.create(null); - for (let request of requests) { - let basePath = request.path; - let ignored = (request.excludes || []).sort(); + const result: { [basePath: string]: IWatcherRequest[] } = Object.create(null); + for (const request of requests) { + const basePath = request.path; + const ignored = (request.excludes || []).sort(); if (prevRequest && (extpath.isEqualOrParent(basePath, prevRequest.path))) { if (!isEqualIgnore(ignored, prevRequest.excludes)) { result[prevRequest.path].push({ path: basePath, excludes: ignored }); @@ -348,29 +364,14 @@ export function normalizeRoots(requests: IWatcherRequest[]): { [basePath: string result[basePath] = [prevRequest]; } } + return result; } -function isEqualRequests(r1: IWatcherRequest[], r2: IWatcherRequest[]) { - if (r1.length !== r2.length) { - return false; - } - for (let k = 0; k < r1.length; k++) { - if (r1[k].path !== r2[k].path || !isEqualIgnore(r1[k].excludes, r2[k].excludes)) { - return false; - } - } - return true; +function isEqualRequests(r1: readonly IWatcherRequest[], r2: readonly IWatcherRequest[]) { + return equals(r1, r2, (a, b) => a.path === b.path && isEqualIgnore(a.excludes, b.excludes)); } -function isEqualIgnore(i1: string[], i2: string[]) { - if (i1.length !== i2.length) { - return false; - } - for (let k = 0; k < i1.length; k++) { - if (i1[k] !== i2[k]) { - return false; - } - } - return true; +function isEqualIgnore(i1: readonly string[], i2: readonly string[]) { + return equals(i1, i2); } diff --git a/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts b/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts index 1948481a857..0b4ea4ca211 100644 --- a/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts +++ b/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts @@ -55,7 +55,7 @@ export class OutOfProcessWin32FolderWatcher { const stdoutLineDecoder = new decoder.LineDecoder(); // Events over stdout - this.handle.stdout.on('data', (data: Buffer) => { + this.handle.stdout!.on('data', (data: Buffer) => { // Collect raw events from output const rawEvents: IDiskFileChange[] = []; @@ -99,7 +99,7 @@ export class OutOfProcessWin32FolderWatcher { // Errors this.handle.on('error', (error: Error) => this.onError(error)); - this.handle.stderr.on('data', (data: Buffer) => this.onError(data)); + this.handle.stderr!.on('data', (data: Buffer) => this.onError(data)); // Exit this.handle.on('exit', (code: number, signal: string) => this.onExit(code, signal)); diff --git a/src/vs/platform/files/test/common/nullFileSystemProvider.ts b/src/vs/platform/files/test/common/nullFileSystemProvider.ts index b4b1c3af6fe..59ba8e873cd 100644 --- a/src/vs/platform/files/test/common/nullFileSystemProvider.ts +++ b/src/vs/platform/files/test/common/nullFileSystemProvider.ts @@ -13,7 +13,7 @@ export class NullFileSystemProvider implements IFileSystemProvider { capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly; onDidChangeCapabilities: Event = Event.None; - onDidChangeFile: Event = Event.None; + onDidChangeFile: Event = Event.None; constructor(private disposableFactory: () => IDisposable = () => Disposable.None) { } @@ -30,4 +30,4 @@ export class NullFileSystemProvider implements IFileSystemProvider { close?(fd: number): Promise { return Promise.resolve(undefined!); } read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return Promise.resolve(undefined!); } write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return Promise.resolve(undefined!); } -} \ No newline at end of file +} diff --git a/src/vs/platform/files/test/node/diskFileService.test.ts b/src/vs/platform/files/test/node/diskFileService.test.ts index 238ccd8ede7..32cbb18e545 100644 --- a/src/vs/platform/files/test/node/diskFileService.test.ts +++ b/src/vs/platform/files/test/node/diskFileService.test.ts @@ -20,20 +20,15 @@ import { NullLogService } from 'vs/platform/log/common/log'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { isEqual } from 'vs/base/common/resources'; -import { VSBuffer, VSBufferReadable, toVSBufferReadableStream, VSBufferReadableStream, bufferToReadable, bufferToStream } from 'vs/base/common/buffer'; +import { VSBuffer, VSBufferReadable, streamToBufferReadableStream, VSBufferReadableStream, bufferToReadable, bufferToStream, streamToBuffer } from 'vs/base/common/buffer'; +import { find } from 'vs/base/common/arrays'; -function getByName(root: IFileStat, name: string): IFileStat | null { +function getByName(root: IFileStat, name: string): IFileStat | undefined { if (root.children === undefined) { - return null; + return undefined; } - for (const child of root.children) { - if (child.name === name) { - return child; - } - } - - return null; + return find(root.children, child => child.name === name); } function toLineByLineReadable(content: string): VSBufferReadable { @@ -63,6 +58,7 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider { totalBytesRead: number = 0; private invalidStatSize: boolean = false; + private smallStatSize: boolean = false; private _testCapabilities!: FileSystemProviderCapabilities; get capabilities(): FileSystemProviderCapabilities { @@ -70,6 +66,7 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider { this._testCapabilities = FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.FileOpenReadWriteClose | + FileSystemProviderCapabilities.FileReadStream | FileSystemProviderCapabilities.FileFolderCopy; if (isLinux) { @@ -84,8 +81,12 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider { this._testCapabilities = capabilities; } - setInvalidStatSize(disabled: boolean): void { - this.invalidStatSize = disabled; + setInvalidStatSize(enabled: boolean): void { + this.invalidStatSize = enabled; + } + + setSmallStatSize(enabled: boolean): void { + this.smallStatSize = enabled; } async stat(resource: URI): Promise { @@ -93,6 +94,8 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider { if (this.invalidStatSize) { res.size = String(res.size) as any; // for https://github.com/Microsoft/vscode/issues/72909 + } else if (this.smallStatSize) { + res.size = 1; } return res; @@ -180,7 +183,7 @@ suite('Disk File Service', function () { assert.equal(event!.target!.isDirectory, true); }); - test('createFolder: creating multiple folders at once', async function () { + test('createFolder: creating multiple folders at once', async () => { let event: FileOperationEvent; disposables.add(service.onAfterOperation(e => event = e)); @@ -425,6 +428,7 @@ suite('Disk File Service', function () { await service.del(source.resource); assert.equal(existsSync(source.resource.fsPath), false); + assert.ok(event!); assert.equal(event!.resource.fsPath, resource.fsPath); assert.equal(event!.operation, FileOperation.DELETE); @@ -487,56 +491,56 @@ suite('Disk File Service', function () { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); setCapabilities(testProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - await testMoveAcrossProviders(); + return testMoveAcrossProviders(); }); test('move - across providers (unbuffered => unbuffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); setCapabilities(testProvider, FileSystemProviderCapabilities.FileReadWrite); - await testMoveAcrossProviders(); + return testMoveAcrossProviders(); }); test('move - across providers (buffered => unbuffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); setCapabilities(testProvider, FileSystemProviderCapabilities.FileReadWrite); - await testMoveAcrossProviders(); + return testMoveAcrossProviders(); }); test('move - across providers (unbuffered => buffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); setCapabilities(testProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - await testMoveAcrossProviders(); + return testMoveAcrossProviders(); }); test('move - across providers - large (buffered => buffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); setCapabilities(testProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - await testMoveAcrossProviders('lorem.txt'); + return testMoveAcrossProviders('lorem.txt'); }); test('move - across providers - large (unbuffered => unbuffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); setCapabilities(testProvider, FileSystemProviderCapabilities.FileReadWrite); - await testMoveAcrossProviders('lorem.txt'); + return testMoveAcrossProviders('lorem.txt'); }); test('move - across providers - large (buffered => unbuffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); setCapabilities(testProvider, FileSystemProviderCapabilities.FileReadWrite); - await testMoveAcrossProviders('lorem.txt'); + return testMoveAcrossProviders('lorem.txt'); }); test('move - across providers - large (unbuffered => buffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); setCapabilities(testProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - await testMoveAcrossProviders('lorem.txt'); + return testMoveAcrossProviders('lorem.txt'); }); async function testMoveAcrossProviders(sourceFile = 'index.html'): Promise { @@ -602,28 +606,28 @@ suite('Disk File Service', function () { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); setCapabilities(testProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - await testMoveFolderAcrossProviders(); + return testMoveFolderAcrossProviders(); }); test('move - directory - across providers (unbuffered => unbuffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); setCapabilities(testProvider, FileSystemProviderCapabilities.FileReadWrite); - await testMoveFolderAcrossProviders(); + return testMoveFolderAcrossProviders(); }); test('move - directory - across providers (buffered => unbuffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); setCapabilities(testProvider, FileSystemProviderCapabilities.FileReadWrite); - await testMoveFolderAcrossProviders(); + return testMoveFolderAcrossProviders(); }); - test('move - directory - across providers (unbuffered => buffered)', async function () { + test('move - directory - across providers (unbuffered => buffered)', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); setCapabilities(testProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - await testMoveFolderAcrossProviders(); + return testMoveFolderAcrossProviders(); }); async function testMoveFolderAcrossProviders(): Promise { @@ -998,6 +1002,10 @@ suite('Disk File Service', function () { assert.equal(source.size, copied.size); }); + test('readFile - small file - default', () => { + return testReadFile(URI.file(join(testDir, 'small.txt'))); + }); + test('readFile - small file - buffered', () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); @@ -1022,6 +1030,22 @@ suite('Disk File Service', function () { return testReadFile(URI.file(join(testDir, 'small.txt'))); }); + test('readFile - small file - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testReadFile(URI.file(join(testDir, 'small.txt'))); + }); + + test('readFile - small file - streamed / readonly', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream | FileSystemProviderCapabilities.Readonly); + + return testReadFile(URI.file(join(testDir, 'small.txt'))); + }); + + test('readFile - large file - default', async () => { + return testReadFile(URI.file(join(testDir, 'lorem.txt'))); + }); + test('readFile - large file - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); @@ -1034,35 +1058,69 @@ suite('Disk File Service', function () { return testReadFile(URI.file(join(testDir, 'lorem.txt'))); }); + test('readFile - large file - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testReadFile(URI.file(join(testDir, 'lorem.txt'))); + }); + async function testReadFile(resource: URI): Promise { const content = await service.readFile(resource); assert.equal(content.value.toString(), readFileSync(resource.fsPath)); } + test('readFileStream - small file - default', () => { + return testReadFileStream(URI.file(join(testDir, 'small.txt'))); + }); + + test('readFileStream - small file - buffered', () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); + + return testReadFileStream(URI.file(join(testDir, 'small.txt'))); + }); + + test('readFileStream - small file - unbuffered', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + + return testReadFileStream(URI.file(join(testDir, 'small.txt'))); + }); + + test('readFileStream - small file - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testReadFileStream(URI.file(join(testDir, 'small.txt'))); + }); + + async function testReadFileStream(resource: URI): Promise { + const content = await service.readFileStream(resource); + + assert.equal((await streamToBuffer(content.value)).toString(), readFileSync(resource.fsPath)); + } + + test('readFile - Files are intermingled #38331 - default', async () => { + return testFilesNotIntermingled(); + }); + test('readFile - Files are intermingled #38331 - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - let resource1 = URI.file(join(testDir, 'lorem.txt')); - let resource2 = URI.file(join(testDir, 'some_utf16le.css')); - - // load in sequence and keep data - const value1 = await service.readFile(resource1); - const value2 = await service.readFile(resource2); - - // load in parallel in expect the same result - const result = await Promise.all([ - service.readFile(resource1), - service.readFile(resource2) - ]); - - assert.equal(result[0].value.toString(), value1.value.toString()); - assert.equal(result[1].value.toString(), value2.value.toString()); + return testFilesNotIntermingled(); }); test('readFile - Files are intermingled #38331 - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testFilesNotIntermingled(); + }); + + test('readFile - Files are intermingled #38331 - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testFilesNotIntermingled(); + }); + + async function testFilesNotIntermingled() { let resource1 = URI.file(join(testDir, 'lorem.txt')); let resource2 = URI.file(join(testDir, 'some_utf16le.css')); @@ -1078,108 +1136,149 @@ suite('Disk File Service', function () { assert.equal(result[0].value.toString(), value1.value.toString()); assert.equal(result[1].value.toString(), value2.value.toString()); + } + + test('readFile - from position (ASCII) - default', async () => { + return testReadFileFromPositionAscii(); }); test('readFile - from position (ASCII) - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const resource = URI.file(join(testDir, 'small.txt')); - - const contents = await service.readFile(resource, { position: 6 }); - - assert.equal(contents.value.toString(), 'File'); - }); - - test('readFile - from position (with umlaut) - buffered', async () => { - setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - - const resource = URI.file(join(testDir, 'small_umlaut.txt')); - - const contents = await service.readFile(resource, { position: Buffer.from('Small File with Ü').length }); - - assert.equal(contents.value.toString(), 'mlaut'); + return testReadFileFromPositionAscii(); }); test('readFile - from position (ASCII) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testReadFileFromPositionAscii(); + }); + + test('readFile - from position (ASCII) - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testReadFileFromPositionAscii(); + }); + + async function testReadFileFromPositionAscii() { const resource = URI.file(join(testDir, 'small.txt')); const contents = await service.readFile(resource, { position: 6 }); assert.equal(contents.value.toString(), 'File'); + } + + test('readFile - from position (with umlaut) - default', async () => { + return testReadFileFromPositionUmlaut(); + }); + + test('readFile - from position (with umlaut) - buffered', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); + + return testReadFileFromPositionUmlaut(); }); test('readFile - from position (with umlaut) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testReadFileFromPositionUmlaut(); + }); + + test('readFile - from position (with umlaut) - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testReadFileFromPositionUmlaut(); + }); + + async function testReadFileFromPositionUmlaut() { const resource = URI.file(join(testDir, 'small_umlaut.txt')); const contents = await service.readFile(resource, { position: Buffer.from('Small File with Ü').length }); assert.equal(contents.value.toString(), 'mlaut'); - }); + } + test('readFile - 3 bytes (ASCII) - default', async () => { + return testReadThreeBytesFromFile(); + }); test('readFile - 3 bytes (ASCII) - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const resource = URI.file(join(testDir, 'small.txt')); - - const contents = await service.readFile(resource, { length: 3 }); - - assert.equal(contents.value.toString(), 'Sma'); + return testReadThreeBytesFromFile(); }); test('readFile - 3 bytes (ASCII) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testReadThreeBytesFromFile(); + }); + + test('readFile - 3 bytes (ASCII) - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testReadThreeBytesFromFile(); + }); + + async function testReadThreeBytesFromFile() { const resource = URI.file(join(testDir, 'small.txt')); const contents = await service.readFile(resource, { length: 3 }); assert.equal(contents.value.toString(), 'Sma'); + } + + test('readFile - 20000 bytes (large) - default', async () => { + return readLargeFileWithLength(20000); }); test('readFile - 20000 bytes (large) - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const resource = URI.file(join(testDir, 'lorem.txt')); - - const contents = await service.readFile(resource, { length: 20000 }); - - assert.equal(contents.value.byteLength, 20000); + return readLargeFileWithLength(20000); }); test('readFile - 20000 bytes (large) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); - const resource = URI.file(join(testDir, 'lorem.txt')); + return readLargeFileWithLength(20000); + }); - const contents = await service.readFile(resource, { length: 20000 }); + test('readFile - 20000 bytes (large) - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); - assert.equal(contents.value.byteLength, 20000); + return readLargeFileWithLength(20000); + }); + + test('readFile - 80000 bytes (large) - default', async () => { + return readLargeFileWithLength(80000); }); test('readFile - 80000 bytes (large) - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const resource = URI.file(join(testDir, 'lorem.txt')); - - const contents = await service.readFile(resource, { length: 80000 }); - - assert.equal(contents.value.byteLength, 80000); + return readLargeFileWithLength(80000); }); test('readFile - 80000 bytes (large) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return readLargeFileWithLength(80000); + }); + + test('readFile - 80000 bytes (large) - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return readLargeFileWithLength(80000); + }); + + async function readLargeFileWithLength(length: number) { const resource = URI.file(join(testDir, 'lorem.txt')); - const contents = await service.readFile(resource, { length: 80000 }); + const contents = await service.readFile(resource, { length }); - assert.equal(contents.value.byteLength, 80000); - }); + assert.equal(contents.value.byteLength, length); + } test('readFile - FILE_IS_DIRECTORY', async () => { const resource = URI.file(join(testDir, 'deep')); @@ -1209,9 +1308,29 @@ suite('Disk File Service', function () { assert.equal(error!.fileOperationResult, FileOperationResult.FILE_NOT_FOUND); }); + test('readFile - FILE_NOT_MODIFIED_SINCE - default', async () => { + return testNotModifiedSince(); + }); + test('readFile - FILE_NOT_MODIFIED_SINCE - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); + return testNotModifiedSince(); + }); + + test('readFile - FILE_NOT_MODIFIED_SINCE - unbuffered', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + + return testNotModifiedSince(); + }); + + test('readFile - FILE_NOT_MODIFIED_SINCE - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testNotModifiedSince(); + }); + + async function testNotModifiedSince() { const resource = URI.file(join(testDir, 'index.html')); const contents = await service.readFile(resource); @@ -1227,10 +1346,9 @@ suite('Disk File Service', function () { assert.ok(error); assert.equal(error!.fileOperationResult, FileOperationResult.FILE_NOT_MODIFIED_SINCE); assert.equal(fileProvider.totalBytesRead, 0); - }); + } test('readFile - FILE_NOT_MODIFIED_SINCE does not fire wrongly - https://github.com/Microsoft/vscode/issues/72909', async () => { - setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); fileProvider.setInvalidStatSize(true); const resource = URI.file(join(testDir, 'index.html')); @@ -1247,45 +1365,37 @@ suite('Disk File Service', function () { assert.ok(!error); }); - test('readFile - FILE_NOT_MODIFIED_SINCE - unbuffered', async () => { - setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); - - const resource = URI.file(join(testDir, 'index.html')); - - const contents = await service.readFile(resource); - fileProvider.totalBytesRead = 0; - - let error: FileOperationError | undefined = undefined; - try { - await service.readFile(resource, { etag: contents.etag }); - } catch (err) { - error = err; - } - - assert.ok(error); - assert.equal(error!.fileOperationResult, FileOperationResult.FILE_NOT_MODIFIED_SINCE); - assert.equal(fileProvider.totalBytesRead, 0); + test('readFile - FILE_EXCEEDS_MEMORY_LIMIT - default', async () => { + return testFileExceedsMemoryLimit(); }); - test('readFile - FILE_EXCEED_MEMORY_LIMIT - buffered', async () => { + test('readFile - FILE_EXCEEDS_MEMORY_LIMIT - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const resource = URI.file(join(testDir, 'index.html')); - - let error: FileOperationError | undefined = undefined; - try { - await service.readFile(resource, { limits: { memory: 10 } }); - } catch (err) { - error = err; - } - - assert.ok(error); - assert.equal(error!.fileOperationResult, FileOperationResult.FILE_EXCEED_MEMORY_LIMIT); + return testFileExceedsMemoryLimit(); }); - test('readFile - FILE_EXCEED_MEMORY_LIMIT - unbuffered', async () => { + test('readFile - FILE_EXCEEDS_MEMORY_LIMIT - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testFileExceedsMemoryLimit(); + }); + + test('readFile - FILE_EXCEEDS_MEMORY_LIMIT - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testFileExceedsMemoryLimit(); + }); + + async function testFileExceedsMemoryLimit() { + await doTestFileExceedsMemoryLimit(); + + // Also test when the stat size is wrong + fileProvider.setSmallStatSize(true); + return doTestFileExceedsMemoryLimit(false); + } + + async function doTestFileExceedsMemoryLimit(testTotalBytesRead = true) { const resource = URI.file(join(testDir, 'index.html')); let error: FileOperationError | undefined = undefined; @@ -1296,28 +1406,44 @@ suite('Disk File Service', function () { } assert.ok(error); - assert.equal(error!.fileOperationResult, FileOperationResult.FILE_EXCEED_MEMORY_LIMIT); + assert.equal(error!.fileOperationResult, FileOperationResult.FILE_EXCEEDS_MEMORY_LIMIT); + + if (testTotalBytesRead) { + assert.equal(fileProvider.totalBytesRead, 0); + } + } + + test('readFile - FILE_TOO_LARGE - default', async () => { + return testFileTooLarge(); }); test('readFile - FILE_TOO_LARGE - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const resource = URI.file(join(testDir, 'index.html')); - - let error: FileOperationError | undefined = undefined; - try { - await service.readFile(resource, { limits: { size: 10 } }); - } catch (err) { - error = err; - } - - assert.ok(error); - assert.equal(error!.fileOperationResult, FileOperationResult.FILE_TOO_LARGE); + return testFileTooLarge(); }); test('readFile - FILE_TOO_LARGE - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testFileTooLarge(); + }); + + test('readFile - FILE_TOO_LARGE - streamed', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadStream); + + return testFileTooLarge(); + }); + + async function testFileTooLarge() { + await doTestFileExceedsMemoryLimit(); + + // Also test when the stat size is wrong + fileProvider.setSmallStatSize(true); + return doTestFileTooLarge(); + } + + async function doTestFileTooLarge() { const resource = URI.file(join(testDir, 'index.html')); let error: FileOperationError | undefined = undefined; @@ -1329,7 +1455,7 @@ suite('Disk File Service', function () { assert.ok(error); assert.equal(error!.fileOperationResult, FileOperationResult.FILE_TOO_LARGE); - }); + } test('createFile', async () => { assertCreateFile(contents => VSBuffer.fromString(contents)); @@ -1396,57 +1522,23 @@ suite('Disk File Service', function () { assert.equal(event!.target!.resource.fsPath, resource.fsPath); }); + test('writeFile - default', async () => { + return testWriteFile(); + }); + test('writeFile - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const resource = URI.file(join(testDir, 'small.txt')); - - const content = readFileSync(resource.fsPath); - assert.equal(content, 'Small File'); - - const newContent = 'Updates to the small file'; - await service.writeFile(resource, VSBuffer.fromString(newContent)); - - assert.equal(readFileSync(resource.fsPath), newContent); - }); - - test('writeFile (large file) - buffered', async () => { - setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - - const resource = URI.file(join(testDir, 'lorem.txt')); - - const content = readFileSync(resource.fsPath); - const newContent = content.toString() + content.toString(); - - const fileStat = await service.writeFile(resource, VSBuffer.fromString(newContent)); - assert.equal(fileStat.name, 'lorem.txt'); - - assert.equal(readFileSync(resource.fsPath), newContent); - }); - - test('writeFile - buffered - readonly throws', async () => { - setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose | FileSystemProviderCapabilities.Readonly); - - const resource = URI.file(join(testDir, 'small.txt')); - - const content = readFileSync(resource.fsPath); - assert.equal(content, 'Small File'); - - const newContent = 'Updates to the small file'; - - let error: Error; - try { - await service.writeFile(resource, VSBuffer.fromString(newContent)); - } catch (err) { - error = err; - } - - assert.ok(error!); + return testWriteFile(); }); test('writeFile - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testWriteFile(); + }); + + async function testWriteFile() { const resource = URI.file(join(testDir, 'small.txt')); const content = readFileSync(resource.fsPath); @@ -1456,11 +1548,25 @@ suite('Disk File Service', function () { await service.writeFile(resource, VSBuffer.fromString(newContent)); assert.equal(readFileSync(resource.fsPath), newContent); + } + + test('writeFile (large file) - default', async () => { + return testWriteFileLarge(); + }); + + test('writeFile (large file) - buffered', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); + + return testWriteFileLarge(); }); test('writeFile (large file) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testWriteFileLarge(); + }); + + async function testWriteFileLarge() { const resource = URI.file(join(testDir, 'lorem.txt')); const content = readFileSync(resource.fsPath); @@ -1470,11 +1576,21 @@ suite('Disk File Service', function () { assert.equal(fileStat.name, 'lorem.txt'); assert.equal(readFileSync(resource.fsPath), newContent); + } + + test('writeFile - buffered - readonly throws', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose | FileSystemProviderCapabilities.Readonly); + + return testWriteFileReadonlyThrows(); }); test('writeFile - unbuffered - readonly throws', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.Readonly); + return testWriteFileReadonlyThrows(); + }); + + async function testWriteFileReadonlyThrows() { const resource = URI.file(join(testDir, 'small.txt')); const content = readFileSync(resource.fsPath); @@ -1490,7 +1606,7 @@ suite('Disk File Service', function () { } assert.ok(error!); - }); + } test('writeFile (large file) - multiple parallel writes queue up', async () => { const resource = URI.file(join(testDir, 'lorem.txt')); @@ -1507,37 +1623,23 @@ suite('Disk File Service', function () { assert.ok(['0', '00', '000', '0000', '00000'].some(offset => fileContent === offset + newContent)); }); + test('writeFile (readable) - default', async () => { + return testWriteFileReadable(); + }); + test('writeFile (readable) - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const resource = URI.file(join(testDir, 'small.txt')); - - const content = readFileSync(resource.fsPath); - assert.equal(content, 'Small File'); - - const newContent = 'Updates to the small file'; - await service.writeFile(resource, toLineByLineReadable(newContent)); - - assert.equal(readFileSync(resource.fsPath), newContent); - }); - - test('writeFile (large file - readable) - buffered', async () => { - setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - - const resource = URI.file(join(testDir, 'lorem.txt')); - - const content = readFileSync(resource.fsPath); - const newContent = content.toString() + content.toString(); - - const fileStat = await service.writeFile(resource, toLineByLineReadable(newContent)); - assert.equal(fileStat.name, 'lorem.txt'); - - assert.equal(readFileSync(resource.fsPath), newContent); + return testWriteFileReadable(); }); test('writeFile (readable) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testWriteFileReadable(); + }); + + async function testWriteFileReadable() { const resource = URI.file(join(testDir, 'small.txt')); const content = readFileSync(resource.fsPath); @@ -1547,11 +1649,25 @@ suite('Disk File Service', function () { await service.writeFile(resource, toLineByLineReadable(newContent)); assert.equal(readFileSync(resource.fsPath), newContent); + } + + test('writeFile (large file - readable) - default', async () => { + return testWriteFileLargeReadable(); + }); + + test('writeFile (large file - readable) - buffered', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); + + return testWriteFileLargeReadable(); }); test('writeFile (large file - readable) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testWriteFileLargeReadable(); + }); + + async function testWriteFileLargeReadable() { const resource = URI.file(join(testDir, 'lorem.txt')); const content = readFileSync(resource.fsPath); @@ -1561,55 +1677,59 @@ suite('Disk File Service', function () { assert.equal(fileStat.name, 'lorem.txt'); assert.equal(readFileSync(resource.fsPath), newContent); + } + + test('writeFile (stream) - default', async () => { + return testWriteFileStream(); }); test('writeFile (stream) - buffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - const source = URI.file(join(testDir, 'small.txt')); - const target = URI.file(join(testDir, 'small-copy.txt')); - - const fileStat = await service.writeFile(target, toVSBufferReadableStream(createReadStream(source.fsPath))); - assert.equal(fileStat.name, 'small-copy.txt'); - - assert.equal(readFileSync(source.fsPath).toString(), readFileSync(target.fsPath).toString()); - }); - - test('writeFile (large file - stream) - buffered', async () => { - setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); - - const source = URI.file(join(testDir, 'lorem.txt')); - const target = URI.file(join(testDir, 'lorem-copy.txt')); - - const fileStat = await service.writeFile(target, toVSBufferReadableStream(createReadStream(source.fsPath))); - assert.equal(fileStat.name, 'lorem-copy.txt'); - - assert.equal(readFileSync(source.fsPath).toString(), readFileSync(target.fsPath).toString()); + return testWriteFileStream(); }); test('writeFile (stream) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testWriteFileStream(); + }); + + async function testWriteFileStream() { const source = URI.file(join(testDir, 'small.txt')); const target = URI.file(join(testDir, 'small-copy.txt')); - const fileStat = await service.writeFile(target, toVSBufferReadableStream(createReadStream(source.fsPath))); + const fileStat = await service.writeFile(target, streamToBufferReadableStream(createReadStream(source.fsPath))); assert.equal(fileStat.name, 'small-copy.txt'); assert.equal(readFileSync(source.fsPath).toString(), readFileSync(target.fsPath).toString()); + } + + test('writeFile (large file - stream) - default', async () => { + return testWriteFileLargeStream(); + }); + + test('writeFile (large file - stream) - buffered', async () => { + setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose); + + return testWriteFileLargeStream(); }); test('writeFile (large file - stream) - unbuffered', async () => { setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite); + return testWriteFileLargeStream(); + }); + + async function testWriteFileLargeStream() { const source = URI.file(join(testDir, 'lorem.txt')); const target = URI.file(join(testDir, 'lorem-copy.txt')); - const fileStat = await service.writeFile(target, toVSBufferReadableStream(createReadStream(source.fsPath))); + const fileStat = await service.writeFile(target, streamToBufferReadableStream(createReadStream(source.fsPath))); assert.equal(fileStat.name, 'lorem-copy.txt'); assert.equal(readFileSync(source.fsPath).toString(), readFileSync(target.fsPath).toString()); - }); + } test('writeFile (file is created including parents)', async () => { const resource = URI.file(join(testDir, 'other', 'newfile.txt')); @@ -1918,7 +2038,7 @@ suite('Disk File Service', function () { }); } - function hasChange(changes: IFileChange[], type: FileChangeType, resource: URI): boolean { + function hasChange(changes: readonly IFileChange[], type: FileChangeType, resource: URI): boolean { return changes.some(change => change.type === type && isEqual(change.resource, resource)); } diff --git a/src/vs/platform/files/test/node/fixtures/service/lorem.txt b/src/vs/platform/files/test/node/fixtures/service/lorem.txt index 9d348ac0901..88c7aaee6b0 100644 --- a/src/vs/platform/files/test/node/fixtures/service/lorem.txt +++ b/src/vs/platform/files/test/node/fixtures/service/lorem.txt @@ -280,4 +280,856 @@ Cras aliquet metus ut purus sagittis, vel venenatis ante consectetur. Pellentesq Donec vehicula mauris eget lacus mollis venenatis et sed nibh. Nam sodales ligula ipsum, scelerisque lacinia ligula sagittis in. Nam sit amet ipsum at erat malesuada congue. Aenean ut sollicitudin sapien. Etiam at tempor odio. Mauris vitae purus ut magna suscipit consequat. Vivamus quis sapien neque. Nulla vulputate sem sit amet massa pellentesque, eleifend tristique ligula egestas. Suspendisse tincidunt gravida mi, in pulvinar lectus egestas non. Aenean imperdiet ex sit amet nunc sollicitudin porta. Integer justo odio, ultricies at interdum in, rhoncus vitae sem. Sed porttitor arcu quis purus aliquet hendrerit. Praesent tempor tortor at dolor dictum pulvinar. Nulla aliquet nunc non ligula scelerisque accumsan. Donec nulla justo, congue vitae massa in, faucibus hendrerit magna. Donec non egestas purus. -Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibus mattis neque dictum sed. Sed convallis fermentum molestie. Nulla facilisi turpis duis. \ No newline at end of file +Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibu + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vulputate, ipsum quis interdum fermentum, lorem sem fermentum eros, vitae auctor neque lacus in nisi. Suspendisse potenti. Maecenas et scelerisque elit, in tincidunt quam. Sed eu tincidunt quam. Nullam justo ex, imperdiet a imperdiet et, fermentum sit amet eros. Aenean quis tempus sem. Pellentesque accumsan magna mi, ut mollis velit sagittis id. Etiam quis ipsum orci. Fusce purus ante, accumsan a lobortis at, venenatis eu nisl. Praesent ornare sed ante placerat accumsan. Suspendisse tempus dignissim fermentum. Nunc a leo ac lacus sodales iaculis eu vitae mi. In feugiat ante at massa finibus cursus. Suspendisse posuere fringilla ornare. Mauris elementum ac quam id convallis. Vestibulum non elit quis urna volutpat aliquam a eu lacus. + +Aliquam vestibulum imperdiet neque, suscipit aliquam elit ultrices bibendum. Suspendisse ultrices pulvinar cursus. Morbi risus nisi, cursus consequat rutrum vitae, molestie sed dui. Fusce posuere, augue quis dignissim aliquam, nisi ipsum porttitor ante, quis fringilla nisl turpis ac nisi. Nulla varius enim eget lorem vehicula gravida. Donec finibus malesuada leo nec semper. Proin ac enim eros. Vivamus non tincidunt nisi, vel tristique lorem. + +Nunc consequat ex id eros dignissim, id rutrum risus laoreet. Sed euismod non erat eu ultricies. Etiam vehicula gravida lacus ut porta. Vestibulum eu eros quis nunc aliquet luctus. Cras quis semper ligula. Nullam gravida vehicula quam sed porta. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In porta cursus vulputate. Quisque porta a nisi eget cursus. Aliquam risus leo, luctus ac magna in, efficitur cursus magna. In condimentum non mi id semper. Donec interdum ante eget commodo maximus. + +Vivamus sit amet vestibulum lectus. Fusce tincidunt mi sapien, dictum sollicitudin diam vulputate in. Integer fringilla consequat mollis. Cras aliquet consequat felis eget feugiat. Nunc tempor cursus arcu, vitae ornare nunc varius et. Vestibulum et tortor vel ante viverra porttitor. Nam at tortor ullamcorper, facilisis augue quis, tristique erat. Aenean ut euismod nibh. Quisque eu tincidunt est, nec euismod eros. + +Proin vehicula nibh non viverra egestas. Phasellus sem dolor, ultricies ac sagittis tristique, lacinia a purus. Vestibulum in ante eros. Pellentesque lacus nulla, tristique vitae interdum vel, malesuada ac diam. Aenean bibendum posuere turpis in accumsan. Ut est nulla, ullamcorper quis turpis at, viverra sagittis mauris. Sed in interdum purus. Praesent scelerisque nibh eget sem euismod, ut imperdiet mi venenatis. Vivamus pulvinar orci sed dapibus auctor. Nulla facilisi. Vestibulum tincidunt erat nec porttitor egestas. Mauris quis risus ante. Nulla facilisi. + +Aliquam ullamcorper ornare lobortis. Phasellus quis sem et ipsum mollis malesuada sed in ex. Ut aliquam ex eget metus finibus maximus. Proin suscipit mauris eu nibh lacinia, quis feugiat dui dapibus. Nam sed libero est. Aenean vulputate orci sit amet diam faucibus, eu sagittis sapien volutpat. Nam imperdiet felis turpis, at pretium odio pulvinar in. Sed vestibulum id eros nec ultricies. Sed quis aliquam tortor, vitae ullamcorper tellus. Donec egestas laoreet eros, id suscipit est rutrum nec. Sed auctor nulla eget metus aliquam, ut condimentum enim elementum. + +Aliquam suscipit non turpis sit amet bibendum. Fusce velit ligula, euismod et maximus at, luctus sed neque. Quisque pretium, nisl at ullamcorper finibus, lectus leo mattis sapien, vel euismod mauris diam ullamcorper ex. Nulla ut risus finibus, lacinia ligula at, auctor erat. Mauris consectetur sagittis ligula vel dapibus. Nullam libero libero, lobortis aliquam libero vel, venenatis ultricies leo. Duis porttitor, nibh congue fermentum posuere, erat libero pulvinar tortor, a pellentesque nunc ipsum vel sem. Nullam volutpat, eros sit amet facilisis consectetur, ipsum est vehicula massa, non vestibulum neque elit in mauris. Nunc hendrerit ipsum non enim bibendum, vitae rhoncus mi egestas. Etiam ullamcorper massa vel nisl sagittis, nec bibendum arcu malesuada. Aenean aliquet turpis justo, a consectetur arcu mollis convallis. Etiam tellus ipsum, ultricies vitae lorem et, ornare facilisis orci. Praesent fringilla justo urna, vel mollis neque pulvinar vestibulum. + +Donec non iaculis erat. Aliquam et mi sed nunc pulvinar ultricies in ut ipsum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Praesent feugiat lacus ac dignissim semper. Phasellus vitae quam nisi. Morbi vel diam ultricies risus lobortis ornare. Fusce maximus et ligula quis iaculis. Sed congue ex eget felis convallis, sit amet hendrerit elit tempor. Donec vehicula blandit ante eget commodo. Vestibulum eleifend diam at feugiat euismod. Etiam magna tellus, dignissim eget fermentum vel, vestibulum vitae mauris. Nam accumsan et erat id sagittis. Donec lacinia, odio ut ornare ultricies, dolor velit accumsan tortor, non finibus erat tellus quis ligula. Nunc quis metus in leo volutpat ornare vulputate eu nisl. + +Donec quis viverra ex. Nullam id feugiat mauris, eu fringilla nulla. Vestibulum id maximus elit. Cras elementum elit sed felis lobortis, eget sagittis nisi hendrerit. Vivamus vitae elit neque. Donec vulputate lacus ut libero ultrices accumsan. Vivamus accumsan nulla orci, in dignissim est laoreet sagittis. Proin at commodo velit. Curabitur in velit felis. Aliquam erat volutpat. Sed consequat, nulla et cursus sodales, nisi lacus mattis risus, quis eleifend erat ex nec turpis. Sed suscipit ultrices lorem in hendrerit. + +Morbi vitae lacus nec libero ornare tempus eu et diam. Suspendisse magna ipsum, fermentum vel odio quis, molestie aliquam urna. Fusce mollis turpis a eros accumsan porttitor. Pellentesque rhoncus dolor sit amet magna rutrum, et dapibus justo tempor. Sed purus nisi, maximus vitae fringilla eu, molestie nec urna. Fusce malesuada finibus pretium. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec sed aliquet eros. Pellentesque luctus diam ante, eget euismod nisl aliquet eu. Sed accumsan elit purus, tempor varius ligula tempus nec. Curabitur ornare leo suscipit suscipit fermentum. Morbi eget nulla est. Maecenas faucibus interdum tristique. + +Etiam ut elit eros. Nulla pharetra suscipit molestie. Nulla facilisis bibendum nisl non molestie. Curabitur turpis lectus, facilisis vel diam non, vulputate ultrices mauris. Aenean placerat aliquam convallis. Suspendisse sed scelerisque tellus. Vivamus lacinia neque eget risus cursus suscipit. Proin consequat dolor vel neque tempor, eu aliquam sem scelerisque. Duis non eros a purus malesuada pharetra non et nulla. Suspendisse potenti. Mauris libero eros, finibus vel nulla id, sagittis dapibus ante. Proin iaculis sed nunc et cursus. + +Quisque accumsan lorem sit amet lorem aliquet euismod. Curabitur fermentum rutrum posuere. Etiam ultricies, sem id pellentesque suscipit, urna magna lacinia eros, quis efficitur risus nisl at lacus. Nulla quis lacus tortor. Mauris placerat ex in dolor tincidunt, vel aliquet nisi pretium. Cras iaculis risus vitae pellentesque aliquet. Quisque a enim imperdiet, ullamcorper arcu vitae, rutrum risus. Nullam consectetur libero at felis fringilla, nec congue nibh dignissim. Nam et lobortis felis, eu pellentesque ligula. Aenean facilisis, ligula non imperdiet maximus, massa orci gravida sapien, at sagittis lacus nisl in lacus. Nulla quis mauris luctus, scelerisque felis consequat, tempus risus. Fusce auctor nisl non nulla luctus molestie. Maecenas sapien nisl, auctor non dolor et, iaculis scelerisque lorem. Suspendisse egestas enim aliquet, accumsan mauris nec, posuere quam. Nulla iaculis dui dui, sit amet vestibulum erat ultricies ac. + +Cras eget dolor erat. Proin at nisl ut leo consectetur ultricies vel ut arcu. Nulla in felis malesuada, ullamcorper tortor et, convallis massa. Nunc urna justo, ornare in nibh vitae, hendrerit condimentum libero. Etiam vitae libero in purus venenatis fringilla. Nullam velit nulla, consequat ut turpis non, egestas hendrerit nibh. Duis tortor turpis, interdum non ante ac, cursus accumsan lectus. Cras pharetra bibendum augue quis dictum. Sed euismod vestibulum justo. Proin porta lobortis purus. Duis venenatis diam tortor, sit amet condimentum eros rhoncus a. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc at magna nec diam lobortis efficitur sit amet ut lacus. Nulla quis orci tortor. Pellentesque tempus velit a odio finibus porta. + +Proin feugiat mauris a tellus scelerisque convallis. Maecenas libero magna, blandit nec ultrices id, congue vel mi. Aliquam lacinia, quam vel condimentum convallis, tortor turpis aliquam odio, sed blandit libero lacus et eros. In eleifend iaculis magna ac finibus. Praesent auctor facilisis tellus in congue. Sed molestie lobortis dictum. Nam quis dignissim augue, vel euismod lorem. Curabitur posuere dapibus luctus. Donec ultricies dictum lectus, quis blandit arcu commodo ac. Aenean tincidunt ligula in nunc imperdiet dignissim. Curabitur egestas sollicitudin sapien ut semper. Aenean nec dignissim lacus. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec aliquam dictum vehicula. Donec tortor est, volutpat non nisi nec, varius gravida ex. Nunc vel tristique nunc, vitae mattis nisi. Nunc nec luctus ex, vitae tincidunt lectus. In hac habitasse platea dictumst. Curabitur lobortis ex eget tincidunt tempor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut a vehicula mi. + +Fusce eu libero finibus, interdum nulla a, placerat neque. Cras bibendum tempor libero nec feugiat. Cras ut sodales eros. Proin viverra, massa sit amet viverra egestas, neque nisl porta ex, sit amet hendrerit libero ligula vel urna. Mauris suscipit lacus id justo rhoncus suscipit. Etiam vel libero tellus. Maecenas non diam molestie, condimentum tellus a, bibendum enim. Mauris aliquet imperdiet tellus, eget sagittis dolor. Sed blandit in neque et luctus. Cras elementum sagittis nunc, vel mollis lorem euismod et. Donec posuere at lacus eget suscipit. + +Nulla nunc mi, pretium non massa vel, tempor semper magna. Nunc a leo pulvinar, tincidunt nunc at, dignissim mi. Aliquam erat volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut viverra nulla a nisl finibus, at hendrerit ligula ullamcorper. Donec a lorem semper, tempor magna et, lobortis libero. Mauris id sapien leo. Donec dignissim, quam vitae porttitor dignissim, quam justo mattis dui, vel consequat odio elit quis orci. Etiam nec pretium neque, sit amet pretium orci. Duis ac tortor venenatis, feugiat purus non, feugiat nunc. Proin scelerisque nisl in turpis aliquam vulputate. + +Praesent sed est semper, fringilla lorem vitae, tincidunt nibh. Cras eros metus, auctor at mauris sit amet, sodales semper orci. Nunc a ornare ex. Curabitur bibendum arcu congue urna vulputate egestas. Vestibulum finibus id risus et accumsan. Aenean ut volutpat tellus. Aenean tincidunt malesuada urna sit amet vestibulum. Mauris vel tellus dictum, varius lacus quis, dictum arcu. + +Aenean quis metus eu erat feugiat cursus vel at ligula. Proin dapibus sodales urna, id euismod lectus tempus id. Pellentesque ex ligula, convallis et erat vel, vulputate condimentum nisl. Pellentesque pharetra nulla quis massa eleifend hendrerit. Praesent sed massa ipsum. Maecenas vehicula dolor massa, id sodales urna faucibus et. Mauris ac quam non massa tincidunt feugiat et at lacus. Fusce libero massa, vulputate vel scelerisque non, mollis in leo. Ut sit amet ultricies odio. Suspendisse in sapien viverra, facilisis purus ut, pretium libero. + +Vivamus tristique pharetra molestie. Nam a volutpat purus. Praesent consequat gravida nisi, ac blandit nisi suscipit ut. Quisque posuere, ligula a ultrices laoreet, ligula nunc vulputate libero, ut rutrum erat odio tincidunt justo. Sed vitae leo at leo fringilla bibendum. Vestibulum ut augue nec dolor auctor accumsan. Praesent laoreet id eros pulvinar commodo. Suspendisse potenti. Ut pharetra, mauris vitae blandit fringilla, odio ante tincidunt lorem, sit amet tempor metus diam ut turpis. + +Praesent quis egestas arcu. Nullam at porta arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi vulputate ligula malesuada ligula luctus, vulputate tempus erat bibendum. Nunc ullamcorper non lectus at euismod. Etiam nibh felis, tincidunt a metus vel, pellentesque rhoncus neque. Etiam at diam in erat luctus interdum. Nunc vel ipsum pulvinar, sollicitudin lacus ac, tempus urna. Etiam vel lacinia sapien. Pellentesque sagittis velit vel mi efficitur iaculis. Integer euismod sit amet urna in sagittis. Cras eleifend ut nibh in facilisis. Donec et lacus vitae nunc placerat sodales. Nulla sed hendrerit ligula, at dapibus sapien. + +Praesent at iaculis ex. Curabitur est purus, cursus a faucibus quis, dictum id velit. Donec dignissim fringilla viverra. Nunc mauris felis, laoreet sit amet sagittis at, vestibulum in libero. Maecenas quis orci turpis. Quisque ut nibh vitae magna mollis consequat id at mauris. Aliquam eu odio eget nulla bibendum sodales. Quisque vel orci eleifend nisi pretium lacinia. Suspendisse eget risus eget mi volutpat molestie eget quis lacus. Duis nisi libero, tincidunt nec nulla id, faucibus cursus felis. + +Donec tempor eget risus pellentesque molestie. Phasellus porta neque vel arcu egestas, nec blandit velit fringilla. Nullam porta faucibus justo vitae laoreet. Pellentesque viverra id nunc eu varius. Nulla pulvinar lobortis iaculis. Etiam vestibulum odio nec velit tristique, a tristique nisi mattis. In sed fringilla orci, vitae efficitur odio. Quisque dui odio, ornare eget velit at, lacinia consequat libero. Quisque lectus nulla, aliquet eu leo in, porta rutrum diam. Donec nec mattis neque. Nam rutrum, odio ac eleifend bibendum, dolor arcu rutrum neque, eget porta elit tellus a lacus. Sed massa metus, sollicitudin et sapien eu, finibus tempus orci. Proin et sapien sit amet erat molestie interdum. In quis rutrum velit, faucibus ultrices tellus. + +Sed sagittis sed justo eget tincidunt. Maecenas ut leo sagittis, feugiat magna et, viverra velit. Maecenas ex arcu, feugiat at consequat vitae, auctor eu massa. Integer egestas, enim vitae maximus convallis, est lectus pretium mauris, ac posuere lectus nisl quis quam. Aliquam tempus laoreet mi, vitae dapibus dolor varius dapibus. Suspendisse potenti. Donec sit amet purus nec libero dapibus tristique. Pellentesque viverra bibendum ligula. Donec sed felis et ex lobortis laoreet. Phasellus a fringilla libero, vitae malesuada nulla. Pellentesque blandit mattis lacus, et blandit tortor laoreet consequat. Suspendisse libero nunc, viverra sed fermentum in, accumsan egestas arcu. Proin in placerat elit. Sed interdum imperdiet malesuada. Suspendisse aliquet quis mauris eget sollicitudin. + +Vivamus accumsan tellus non erat volutpat, quis dictum dolor feugiat. Praesent rutrum nunc ac est mollis cursus. Fusce semper volutpat dui ut egestas. Curabitur sit amet posuere massa. Cras tincidunt nulla et mi mollis imperdiet. Suspendisse scelerisque ex id sodales vulputate. In nunc augue, pharetra in placerat eu, mattis id tellus. Vivamus cursus efficitur vehicula. Nulla aliquet vehicula aliquet. + +Sed cursus tellus sed porta pulvinar. Sed vitae nisi neque. Nullam aliquet, lorem et efficitur scelerisque, arcu diam aliquam felis, sed pulvinar lorem odio et turpis. Praesent convallis pulvinar turpis eu iaculis. Aliquam nec gravida mi. Curabitur eu nibh tempor, blandit justo in, ultrices felis. Fusce placerat metus non mi sagittis rutrum. Morbi sed dui fringilla, sagittis mauris eget, imperdiet nunc. Phasellus hendrerit sem elit, id hendrerit libero auctor sit amet. Integer sodales elit sit amet consequat cursus. + +Nam semper est eget nunc mollis, in pellentesque lectus fringilla. In finibus vel diam id semper. Nunc mattis quis erat eu consectetur. In hac habitasse platea dictumst. Nullam et ipsum vestibulum ex pulvinar ultricies sit amet id velit. Aenean suscipit mi tortor, a lobortis magna viverra non. Nulla condimentum aliquet ante et ullamcorper. Pellentesque porttitor arcu a posuere tempus. Aenean lacus quam, imperdiet eu justo vitae, pretium efficitur ex. Duis id purus id magna rhoncus ultrices id eu risus. Nunc dignissim et libero id dictum. + +Quisque a tincidunt neque. Phasellus commodo mi sit amet tempor fringilla. Ut rhoncus, neque non porttitor elementum, libero nulla egestas augue, sed fringilla sapien felis ac velit. Phasellus viverra rhoncus mollis. Nam ullamcorper leo vel erat laoreet luctus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus semper a metus a cursus. Nulla sed orci egestas, efficitur purus ac, malesuada tellus. Aenean rutrum velit at tellus fermentum mollis. Aliquam eleifend euismod metus. + +In hac habitasse platea dictumst. Vestibulum volutpat neque vitae porttitor laoreet. Nam at tellus consequat, sodales quam in, pulvinar arcu. Maecenas varius convallis diam, ac lobortis tellus pellentesque quis. Maecenas eget augue massa. Nullam volutpat nibh ac justo rhoncus, ut iaculis tellus rutrum. Fusce efficitur efficitur libero quis condimentum. Curabitur congue neque non tincidunt tristique. Fusce eget tempor ex, at pellentesque odio. Praesent luctus dictum vestibulum. Etiam non orci nunc. Vivamus vitae laoreet purus, a lobortis velit. Curabitur tincidunt purus ac lectus elementum pellentesque. Quisque sed tincidunt est. + +Sed vel ultrices massa, vitae ultricies justo. Cras finibus mauris nec lacus tempus dignissim. Cras faucibus maximus velit, eget faucibus orci luctus vehicula. Nulla massa nunc, porta ac consequat eget, rhoncus non tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce sed maximus metus, vel imperdiet ipsum. Ut scelerisque lectus at blandit porttitor. Ut vulputate nunc pharetra, aliquet sapien ac, sollicitudin sapien. Aenean eget ante lorem. Nam accumsan venenatis tellus id dignissim. + +Curabitur fringilla, magna non maximus dapibus, nulla sapien vestibulum lectus, sit amet semper dolor neque vitae nisl. Nunc ultrices vehicula augue sed iaculis. Maecenas nec diam mollis, suscipit orci et, vestibulum ante. Pellentesque eu nisl tortor. Nunc eleifend, lacus quis volutpat volutpat, nisi mi molestie sem, quis mollis ipsum libero a tellus. Ut viverra dolor mattis convallis interdum. Sed tempus nisl at nunc scelerisque aliquet. Quisque tempor tempor lorem id feugiat. Nullam blandit lectus velit, vitae porta lacus tincidunt a. Vivamus sit amet arcu ultrices, tincidunt mi quis, viverra quam. Aenean fringilla libero elementum lorem semper, quis pulvinar eros gravida. Nullam sodales blandit mauris, sed fermentum velit fermentum sit amet. Donec malesuada mauris in augue sodales vulputate. Vestibulum gravida turpis id elit rhoncus dignissim. Integer non congue lorem, eu viverra orci. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at dolor magna. Aliquam consectetur erat augue, id iaculis velit pharetra ac. Integer rutrum venenatis dignissim. Integer non sodales elit. Curabitur ut magna ut nibh feugiat aliquam ac ut risus. Morbi nibh quam, aliquam id placerat nec, vestibulum eget velit. Suspendisse at dignissim quam. Vivamus aliquet sem sed nisl volutpat, ut cursus orci ultrices. Aliquam ultrices lacinia enim, vitae aliquet neque. + +Quisque scelerisque finibus diam in mattis. Cras cursus auctor velit. Aliquam sem leo, fermentum et maximus et, molestie a libero. Aenean justo elit, rutrum a ornare id, egestas eget enim. Aenean auctor tristique erat. Curabitur condimentum libero lacus, nec consequat orci vestibulum sed. Fusce elit ligula, blandit vitae sapien vitae, dictum ultrices risus. Nam laoreet suscipit sapien, at interdum velit faucibus sit amet. Duis quis metus egestas lectus elementum posuere non nec libero. Aliquam a dolor bibendum, facilisis nunc a, maximus diam. Vestibulum suscipit tristique magna, non dignissim turpis sodales sed. Nunc ornare, velit ac facilisis fringilla, dolor mi consectetur lorem, vitae finibus erat justo suscipit urna. Maecenas sit amet eros erat. Nunc non arcu ornare, suscipit lorem eget, sodales mauris. Aliquam tincidunt, quam nec mollis lacinia, nisi orci fermentum libero, consequat eleifend lectus quam et sapien. Vestibulum a quam urna. + +Cras arcu leo, euismod ac ullamcorper at, faucibus sed massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus porttitor velit in enim interdum, non commodo metus ornare. Morbi vel lorem quis nisl luctus tristique quis vitae nisl. Suspendisse condimentum tortor enim, nec eleifend ipsum euismod et. Sed gravida quam ut tristique lacinia. Mauris eu interdum ipsum, ac ultrices odio. Nullam auctor tellus a risus porttitor vehicula. Nulla blandit euismod dictum. In pharetra, enim iaculis pulvinar interdum, dui nunc placerat nunc, sit amet pretium lectus nulla vitae quam. Phasellus quis enim sollicitudin, varius nulla id, ornare purus. Donec quam lacus, vestibulum quis nunc ac, mollis dictum nisi. Cras ut mollis elit. Maecenas ultrices ligula at risus faucibus scelerisque. Etiam vitae porttitor purus. Curabitur blandit lectus urna, ut hendrerit tortor feugiat ut. + +Phasellus fringilla, sapien pellentesque commodo pharetra, ante libero aliquam tellus, ut consectetur augue libero a sapien. Maecenas blandit luctus nisl eget aliquet. Maecenas vitae porta dolor, faucibus laoreet sapien. Suspendisse lobortis, ipsum sed vehicula aliquam, elit purus scelerisque dui, rutrum consectetur diam odio et lorem. In nec lacinia metus. Donec viverra libero est, vel bibendum erat condimentum quis. Donec feugiat purus leo. In laoreet vitae felis a porttitor. Mauris ullamcorper, lacus id condimentum suscipit, neque magna pellentesque arcu, eget cursus neque tellus id metus. Curabitur volutpat ac orci vel ultricies. + +Sed ut finibus erat. Sed diam purus, varius non tincidunt quis, ultrices sit amet ipsum. Donec et egestas nulla. Suspendisse placerat nisi at dui laoreet iaculis. Aliquam aliquet leo at augue faucibus molestie. Nullam lacus augue, hendrerit sed nisi eu, faucibus porta est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam ut leo aliquet sem fermentum rutrum quis ac justo. Integer placerat aliquam nisl ut sagittis. Proin erat orci, lobortis et sem eget, eleifend fringilla augue. Mauris varius laoreet arcu, sed tincidunt felis. Pellentesque venenatis lorem odio, id pulvinar velit molestie feugiat. Donec mattis lacus sed eleifend pulvinar. + +Sed condimentum ex in tincidunt hendrerit. Etiam eget risus lacinia, euismod nibh eu, pellentesque quam. Proin elit eros, convallis id mauris ac, bibendum ultrices lectus. Morbi venenatis, purus id fermentum consequat, nunc libero tincidunt ligula, non dictum ligula orci nec quam. Nulla nec ultrices lorem. Aenean maximus augue vel dictum pharetra. Etiam turpis urna, pellentesque quis malesuada eu, molestie faucibus felis. + +Vestibulum pharetra augue ut quam blandit congue in nec risus. Proin eu nibh eu dui eleifend porta vitae id lectus. Proin lacus nibh, lobortis sed ligula vitae, interdum lobortis erat. Suspendisse potenti. In sollicitudin quis sapien ut aliquet. Mauris ac nulla arcu. Fusce tristique justo quis lectus mollis, eu volutpat lectus finibus. Vivamus venenatis facilisis ex ut vestibulum. + +Etiam varius lobortis purus, in hendrerit elit tristique at. In tempus, augue vestibulum fermentum gravida, ligula tellus vulputate arcu, eu molestie ex sapien at purus. Vestibulum nec egestas metus. Duis pulvinar quam nec consequat interdum. Aenean non dapibus lacus. Aliquam sit amet aliquet nulla. Sed venenatis volutpat purus nec convallis. Phasellus aliquet semper sodales. Cras risus sapien, condimentum auctor urna a, pulvinar ornare nisl. Sed tincidunt felis elit, ut elementum est bibendum ac. Morbi interdum justo vel dui faucibus condimentum. + +Sed convallis eu sem at tincidunt. Nullam at auctor est, et ullamcorper ipsum. Pellentesque eget ante ante. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer euismod, sapien sed dapibus ornare, nibh enim maximus lacus, lacinia placerat urna quam quis felis. Morbi accumsan id nisl ut condimentum. Donec bibendum nisi est, sed volutpat lorem rhoncus in. Vestibulum ac lacinia nunc, eget volutpat magna. Integer aliquam pharetra ipsum, id placerat nunc volutpat quis. Etiam urna diam, rhoncus sit amet varius vel, euismod vel sem. Nullam vel molestie urna. Vivamus ornare erat at venenatis euismod. Suspendisse potenti. Fusce diam justo, tincidunt vel sem at, commodo faucibus nisl. Duis gravida efficitur diam, vel sagittis erat pulvinar ut. + +Quisque vel pharetra felis. Duis efficitur tortor dolor, vitae porttitor erat fermentum sed. Sed eu mi purus. Etiam dignissim tortor eu tempus molestie. Aenean pretium erat enim, in hendrerit ante hendrerit at. Sed ut risus vel nunc venenatis ultricies quis in lacus. Pellentesque vitae purus euismod, placerat risus non, ullamcorper augue. Quisque varius quam ligula, nec aliquet ex faucibus vitae. Quisque rhoncus sit amet leo tincidunt mattis. Cras id mauris eget purus pretium gravida sit amet eu augue. Aliquam dapibus odio augue, id lacinia velit pulvinar eu. + +Mauris fringilla, tellus nec pharetra iaculis, neque nisi ultrices massa, et tincidunt sem dui sed mi. Curabitur erat lorem, venenatis quis tempus lacinia, tempus sit amet nunc. Aliquam at neque ac metus commodo dictum quis vitae justo. Phasellus eget lacus tempus, blandit lorem vel, rutrum est. Aenean pharetra sem ut augue lobortis dignissim. Sed rhoncus at nulla id ultrices. Cras id condimentum felis. In suscipit luctus vulputate. Donec tincidunt lacus nec enim tincidunt sollicitudin ut quis enim. Nam at libero urna. Praesent sit amet massa vitae massa ullamcorper vehicula. + +Nullam bibendum augue ut turpis condimentum bibendum. Proin sit amet urna hendrerit, sodales tortor a, lobortis lectus. Integer sagittis velit turpis, et tincidunt nisi commodo eget. Duis tincidunt elit finibus accumsan cursus. Aenean dignissim scelerisque felis vel lacinia. Nunc lacinia maximus luctus. In hac habitasse platea dictumst. Vestibulum eget urna et enim tempor tempor. Nam feugiat, felis vel vestibulum tempus, orci justo viverra diam, id dapibus lorem justo in ligula. + +Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In ac pellentesque sem. Vestibulum lacinia magna dui, eu lacinia augue placerat et. Maecenas pulvinar congue est. Pellentesque commodo dui non pulvinar scelerisque. Etiam interdum est posuere sem bibendum, ac commodo magna dictum. Cras ipsum turpis, rhoncus nec posuere vitae, laoreet a arcu. Integer ac massa sit amet enim placerat lacinia sed ultrices arcu. Suspendisse sem nibh, luctus sit amet volutpat in, pellentesque eu metus. Ut gravida neque eget mi accumsan tempus. Nam sit amet aliquet nibh. + +Pellentesque a purus cursus nulla hendrerit congue quis et odio. Aenean hendrerit, leo ullamcorper sagittis hendrerit, erat dui molestie quam, sed condimentum lacus risus sed tellus. Morbi a dapibus lectus, ut feugiat ex. Phasellus pretium quam et sapien mollis, vel iaculis dui dignissim. Sed ullamcorper est turpis, a viverra lorem consectetur in. Aenean aliquet nibh non cursus rutrum. Suspendisse at tristique urna, id lobortis urna. In hac habitasse platea dictumst. Phasellus libero velit, rutrum sed tellus nec, dapibus tincidunt ligula. Quisque vel dui venenatis, consequat nisl ut, lacinia ipsum. Phasellus vitae magna pellentesque, lobortis est id, faucibus quam. Nam eleifend faucibus dui vel pellentesque. + +Etiam ut est non lacus tincidunt interdum. Maecenas sed massa urna. Quisque ut nibh tortor. Pellentesque felis ipsum, tempor finibus ipsum et, euismod pretium metus. Donec sit amet est ipsum. Quisque rhoncus justo non finibus elementum. Nulla nec lectus ac tortor placerat fringilla. Phasellus ac ultrices nunc, eu efficitur nisl. Nulla rhoncus nunc vitae ante dictum tincidunt. Nunc ultrices, massa sit amet malesuada dignissim, lectus lacus consequat sapien, non eleifend metus sem in eros. Phasellus mauris ante, dictum sit amet suscipit ac, rhoncus eget nisi. Phasellus at orci mollis, imperdiet neque eget, faucibus nulla. In at purus massa. Pellentesque quis rutrum lectus. + +Integer eu faucibus turpis, sit amet mollis massa. Vestibulum id nulla commodo, rutrum ipsum sed, semper ante. Phasellus condimentum orci nec nibh convallis, ac maximus orci ullamcorper. Maecenas vitae sollicitudin mi. Integer et finibus lectus, et condimentum ligula. Donec elementum tristique quam vitae dapibus. Morbi euismod ipsum in tristique ullamcorper. + +Duis fermentum non enim eu auctor. Quisque lacinia nibh vehicula nibh posuere, eu volutpat turpis facilisis. Ut ac faucibus nulla. Sed eleifend quis ex et pellentesque. Vestibulum sollicitudin in libero id fringilla. Phasellus dignissim purus consequat, condimentum dui sit amet, condimentum ante. Pellentesque ac consectetur massa, quis sagittis est. Nulla maximus tristique risus accumsan convallis. Curabitur imperdiet ac lacus a ultrices. Nulla facilisi. Sed quis quam quis lectus placerat lobortis vel sed turpis. In mollis dui id neque iaculis, ut aliquet tellus malesuada. Proin at luctus odio, vel blandit sapien. Praesent dignissim tortor vehicula libero fringilla, nec ultrices erat suscipit. Maecenas scelerisque purus in dapibus fermentum. + +Curabitur magna odio, mattis in tortor ut, porttitor congue est. Vestibulum mollis lacinia elementum. Fusce maximus erat vitae nunc rutrum lobortis. Integer ligula eros, auctor vel elit non, posuere luctus lacus. Maecenas quis auctor massa. Ut ipsum lacus, efficitur posuere euismod et, hendrerit efficitur est. Phasellus fringilla, quam id tincidunt pretium, nunc dui sollicitudin orci, eu dignissim nisi metus ut magna. Integer lobortis interdum dolor, non bibendum purus posuere et. Donec non lectus aliquet, pretium dolor eu, cursus massa. Sed ut dui sapien. In sed vestibulum massa. Pellentesque blandit, dui non sodales vehicula, orci metus mollis nunc, non pharetra ex tellus ac est. Mauris sagittis metus et fermentum pretium. Nulla facilisi. Quisque quis ante ut nulla placerat mattis ut quis nisi. + +Sed quis nulla ligula. Quisque dignissim ligula urna, sed aliquam purus semper at. Suspendisse potenti. Nunc massa lectus, pharetra vehicula arcu bibendum, imperdiet sodales ipsum. Nam ac sapien diam. Mauris iaculis fringilla mattis. Pellentesque tempus eros sit amet justo volutpat mollis. Phasellus ac turpis ipsum. Morbi vel ante elit. Aenean posuere quam consequat velit varius suscipit. Donec tempor quam ut nibh cursus efficitur. + +Morbi molestie dolor nec sem egestas suscipit. Etiam placerat pharetra lectus, et ullamcorper risus tristique in. Sed faucibus ullamcorper lectus eget fringilla. Maecenas malesuada hendrerit congue. Sed eget neque a erat placerat tincidunt. Aliquam vitae dignissim turpis. Fusce at placerat magna, a laoreet lectus. Maecenas a purus nec diam gravida fringilla. Nam malesuada euismod ante non vehicula. In faucibus bibendum leo, faucibus posuere nisl pretium quis. Fusce finibus bibendum finibus. Vestibulum eu justo maximus, hendrerit diam nec, dignissim sapien. Aenean dolor lacus, malesuada quis vestibulum ac, venenatis ac ipsum. Cras a est id nunc finibus facilisis. Cras lacinia neque et interdum vehicula. Suspendisse vulputate tellus elit, eget tempor dui finibus vel. + +Cras sed pretium odio. Proin hendrerit elementum felis in tincidunt. Nam sed turpis vel justo molestie accumsan condimentum eu nunc. Praesent lobortis euismod rhoncus. Nulla vitae euismod nibh, quis mattis mi. Fusce ultrices placerat porttitor. Duis sem ipsum, pellentesque sit amet odio a, molestie vulputate mauris. + +Duis blandit mollis ligula, sit amet mattis ligula finibus sit amet. Nunc a leo molestie, placerat diam et, vestibulum leo. Suspendisse facilisis neque purus, nec pellentesque ligula fermentum nec. Aenean malesuada mauris lorem, eu blandit arcu pulvinar quis. Duis laoreet urna lacus, non maximus arcu rutrum ultricies. Nulla augue dolor, suscipit eu mollis eu, aliquam condimentum diam. Ut semper orci luctus, pharetra turpis at, euismod mi. Nulla leo diam, finibus sit amet purus sed, maximus dictum lorem. Integer eu mi id turpis laoreet rhoncus. + +Integer a mauris tincidunt, finibus orci ut, pretium mauris. Nulla molestie nunc mi, id finibus lorem elementum sed. Proin quis laoreet ante. Integer nulla augue, commodo id molestie quis, rutrum ut turpis. Suspendisse et tortor turpis. Sed ut pharetra massa. Pellentesque elementum blandit sem, ut elementum tellus egestas a. Fusce eu purus nibh. + +Cras dignissim ligula scelerisque magna faucibus ullamcorper. Proin at condimentum risus, auctor malesuada quam. Nullam interdum interdum egestas. Nulla aliquam nisi vitae felis mollis dictum. Suspendisse dapibus consectetur tortor. Ut ut nisi non sem bibendum tincidunt. Vivamus suscipit leo quis gravida dignissim. + +Aliquam interdum, leo id vehicula mollis, eros eros rhoncus diam, non mollis ligula mi eu mauris. Sed ultrices vel velit sollicitudin tincidunt. Nunc auctor metus at ligula gravida elementum. Praesent interdum eu elit et mollis. Duis egestas quam sit amet velit dignissim consequat. Aliquam ac turpis nec nunc convallis sagittis. Fusce blandit, erat ac fringilla consectetur, dolor eros sodales leo, vel aliquet risus nisl et diam. Aliquam luctus felis vitae est eleifend euismod facilisis et lacus. Sed leo tellus, auctor eu arcu in, volutpat sagittis nisl. Pellentesque nisl ligula, placerat vel ullamcorper at, vulputate ac odio. Morbi ac faucibus orci, et tempus nulla. Proin rhoncus rutrum dolor, in venenatis mauris. Suspendisse a fermentum augue, non semper mi. Nunc eget pretium neque. Phasellus augue erat, feugiat ac aliquam congue, rutrum non sapien. Pellentesque ac diam gravida, consectetur felis at, ornare neque. + +Nullam interdum mattis sapien quis porttitor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus aliquet rutrum ipsum id euismod. Maecenas consectetur massa et mi porta viverra. Nunc quam nibh, dignissim vitae maximus et, ullamcorper nec lorem. Nunc vitae justo dapibus, luctus lacus vitae, pretium elit. Maecenas et efficitur leo. Curabitur mauris lectus, placerat quis vehicula vitae, auctor ut urna. Quisque rhoncus pharetra luctus. In hac habitasse platea dictumst. Integer sit amet metus nec eros malesuada aliquam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi hendrerit mi ac leo aliquam, sit amet ultricies libero commodo. Mauris dapibus purus metus, sit amet viverra nibh imperdiet et. Nullam porta nulla tellus, quis vehicula diam imperdiet non. Vivamus enim massa, bibendum in fermentum in, ultrices at ex. + +Suspendisse fermentum id nibh eget accumsan. Duis dapibus bibendum erat ut sollicitudin. Aliquam nec felis risus. Pellentesque rhoncus ligula id sem maximus mollis sed nec massa. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ipsum ipsum, sodales sed enim id, convallis faucibus eros. Donec ultricies dictum tincidunt. Cras vitae nibh arcu. Pellentesque cursus, sapien nec consequat fermentum, ipsum ante suscipit dui, imperdiet hendrerit est nisl eu massa. Quisque vitae sem ligula. Aenean iaculis metus ut mauris interdum laoreet. Vivamus sed gravida dolor. + +Morbi nulla metus, porttitor sed eros sit amet, efficitur efficitur est. In vel nisl urna. Ut aliquet tellus at congue convallis. Phasellus imperdiet lobortis sollicitudin. Integer sodales, sem eu ultricies pharetra, erat erat porttitor odio, eget dapibus libero ipsum eget velit. Phasellus gravida nulla nisl, eu pharetra mi auctor vel. Sed blandit pharetra velit, ut egestas libero placerat non. Aliquam a interdum quam. Proin at tortor nec dui sollicitudin tempus sed vestibulum elit. Nunc non sollicitudin velit. + +Aenean consequat diam velit, sed rutrum tortor faucibus dictum. Quisque at semper augue. Duis ut est eget mi ornare bibendum id et ligula. Phasellus consequat tortor non leo pulvinar posuere. Proin vestibulum eleifend felis, in hendrerit tortor sollicitudin eu. Phasellus hendrerit, lacus vel laoreet interdum, dui tortor consequat justo, commodo ultricies arcu felis vitae enim. Vivamus eu sapien at leo suscipit rutrum eu at justo. Aenean et dolor a libero ullamcorper posuere. Integer laoreet placerat nisi in vulputate. Mauris laoreet eget risus sed cursus. Donec scelerisque neque a libero eleifend hendrerit. Nulla varius condimentum nunc sit amet fermentum. Aliquam lorem ex, varius nec mollis ut, ultrices in neque. Morbi sit amet porta leo. Integer iaculis fermentum lacus in vestibulum. + +Ut gravida, tellus ut maximus ultrices, erat est venenatis nisl, vitae pretium massa ex ac magna. Sed non purus eget ligula aliquet volutpat non quis arcu. Nam aliquam tincidunt risus, sit amet fringilla sapien vulputate ut. Mauris luctus suscipit pellentesque. Nunc porttitor dapibus ex quis tempus. Ut ullamcorper metus a eros vulputate, vitae viverra lectus convallis. Mauris semper imperdiet augue quis tincidunt. Integer porta pretium magna, sed cursus sem scelerisque sollicitudin. Nam efficitur, nibh pretium eleifend vestibulum, purus diam posuere sem, in egestas mauris augue sit amet urna. + +Vestibulum tincidunt euismod massa in congue. Duis interdum metus non laoreet fringilla. Donec at ligula congue, tincidunt nunc non, scelerisque nunc. Donec bibendum magna non est scelerisque feugiat at nec neque. Ut orci tortor, tempus eget massa non, dignissim faucibus dolor. Nam odio risus, accumsan pretium neque eget, accumsan dignissim dui. In ut neque auctor, scelerisque tellus sed, ullamcorper nisi. Suspendisse varius cursus quam at hendrerit. Vivamus elit libero, sagittis vitae sem ac, vulputate iaculis ligula. + +Sed lobortis laoreet purus sit amet rutrum. Pellentesque feugiat non leo vel lacinia. Quisque feugiat nisl a orci bibendum vestibulum. In et sollicitudin urna. Morbi a arcu ac metus faucibus tempus. Nam eu imperdiet sapien, suscipit mattis tortor. Aenean blandit ipsum nisi, a eleifend ligula euismod at. Integer tincidunt pharetra felis, mollis placerat mauris hendrerit at. Curabitur convallis, est sit amet luctus volutpat, massa lacus cursus augue, sed eleifend magna quam et risus. Aliquam lobortis tincidunt metus vitae porttitor. Suspendisse potenti. Aenean ullamcorper, neque id commodo luctus, nulla nunc lobortis quam, id dapibus neque dui nec mauris. Etiam quis lorem quis elit commodo ornare. Ut pharetra purus ultricies enim ultrices efficitur. Proin vehicula tincidunt molestie. Mauris et placerat sem. + +Aliquam erat volutpat. Suspendisse velit turpis, posuere ac lacus eu, lacinia laoreet velit. Sed interdum felis neque, id blandit sem malesuada sit amet. Ut sagittis justo erat, efficitur semper orci tempor sed. Donec enim massa, posuere varius lectus egestas, pellentesque posuere mi. Cras tincidunt ut libero sed mattis. Suspendisse quis magna et tellus posuere interdum vel at purus. Pellentesque fringilla tristique neque, id aliquet tellus ultricies non. Duis ut tellus vel odio lobortis vulputate. + +Integer at magna ac erat convallis vestibulum. Sed lobortis porttitor mauris. Fusce varius lorem et volutpat pulvinar. Aenean ac vulputate lectus, vitae consequat velit. Suspendisse ex dui, varius ut risus ut, dictum scelerisque sem. Vivamus urna orci, volutpat ut convallis ac, venenatis vitae urna. In hac habitasse platea dictumst. Etiam eu purus arcu. Aenean vulputate leo urna, vel tristique dui sagittis euismod. Suspendisse non tellus efficitur ante rhoncus volutpat at et sapien. + +Sed dapibus accumsan porttitor. Phasellus facilisis lectus finibus ligula dignissim, id pulvinar lectus feugiat. Nullam egestas commodo nisi posuere aliquet. Morbi sit amet tortor sagittis, rutrum dui nec, dapibus sapien. Sed posuere tortor tortor, interdum auctor magna varius vitae. Vestibulum id sagittis augue. Curabitur fermentum arcu sem, eu condimentum quam rutrum non. Phasellus rutrum nibh quis lectus rhoncus pretium. Curabitur dictum interdum elit. Vestibulum maximus sodales imperdiet. Mauris auctor nec purus sed venenatis. In in urna purus. + +Duis placerat molestie suscipit. Morbi a elit id purus efficitur consequat. Nunc ac commodo turpis. Etiam sit amet lacus a ipsum tempus venenatis sed vel nibh. Duis elementum aliquam mi sed tristique. Morbi ligula tortor, semper ac est vel, lobortis maximus erat. Curabitur ipsum felis, laoreet vel condimentum eget, ullamcorper sit amet mauris. Nulla facilisi. Nam at purus sed mi egestas placerat vitae vel magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse at dignissim diam. Phasellus consectetur eget neque vel viverra. Donec sollicitudin mattis dolor vel malesuada. Vivamus vehicula leo neque, vitae fermentum leo posuere et. Praesent dui est, finibus sit amet tristique quis, pharetra vel nibh. + +Duis nulla leo, accumsan eu odio eget, sagittis semper orci. Quisque ullamcorper ligula quam, commodo porttitor mauris ullamcorper eu. Cras varius sagittis felis in aliquam. Duis sodales risus ac justo vehicula, nec mattis diam lacinia. Cras eget lectus ipsum. Ut commodo, enim vitae malesuada hendrerit, ex dolor egestas lectus, sit amet hendrerit metus diam nec est. Vestibulum tortor metus, lobortis sit amet ante eget, tempor molestie lacus. In molestie et urna et semper. Mauris mollis, sem non hendrerit condimentum, sapien nisi cursus est, non suscipit quam justo non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam enim est, porta ac feugiat vitae, rutrum in lorem. Duis vehicula tortor ut posuere maximus. + +Nullam vestibulum non tellus sed commodo. Quisque mattis elit sit amet sapien sollicitudin, ut condimentum nisl congue. Aenean sagittis massa vel elit faucibus fermentum. Donec tincidunt nisi nec nisl sodales pellentesque. Mauris congue congue ligula ut suscipit. Vivamus velit tortor, tempor et gravida eget, fermentum sit amet ante. Nullam fringilla, lorem at ultrices cursus, urna neque ornare dolor, eu lacinia orci enim sed nibh. Ut a ullamcorper lectus, id mattis purus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean maximus sollicitudin posuere. Nunc at augue lacus. Aenean efficitur leo sit amet lacinia efficitur. + +Quisque venenatis quam mi, in pharetra odio vulputate eu. In vel nisl pulvinar, pulvinar ligula ut, sodales risus. Sed efficitur lectus at vestibulum tincidunt. Vestibulum eu ullamcorper elit. Fusce vestibulum magna enim, et tempor lacus posuere vitae. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer leo elit, luctus nec mattis sit amet, sollicitudin in turpis. + +Proin convallis venenatis leo, vitae tristique erat iaculis nec. Nulla facilisi. Duis porttitor, sapien et bibendum vulputate, sem libero sodales lacus, non malesuada felis erat ut libero. Nam non felis semper, finibus est a, mattis mauris. Praesent nec eros quam. Nulla hendrerit, augue consectetur eleifend ultricies, purus mi condimentum nulla, eget dapibus est nunc sed libero. Nullam elementum dui erat, vitae luctus libero sollicitudin et. Nulla odio magna, placerat in augue eu, dapibus imperdiet odio. Suspendisse imperdiet metus sit amet rhoncus dapibus. Cras at enim et urna vehicula cursus eu a mauris. Integer magna ante, eleifend ac placerat vitae, porta at nisi. Cras eget malesuada orci. Curabitur nunc est, vulputate id viverra et, dignissim sed odio. Curabitur non mattis sem. Sed bibendum, turpis vitae vehicula faucibus, nunc quam ultricies lectus, vitae viverra felis turpis at libero. + +Nullam ut egestas ligula. Proin hendrerit justo a lectus commodo venenatis. Nulla facilisi. Ut cursus lorem quis est bibendum condimentum. Aenean in tristique odio. Fusce tempor hendrerit ipsum. Curabitur mollis felis justo, quis dapibus erat auctor vel. Sed augue lectus, finibus ut urna quis, ullamcorper vestibulum dui. Etiam molestie aliquam tempor. Integer mattis sollicitudin erat, et tristique elit varius vel. Mauris a ex justo. + +Nam eros est, imperdiet non volutpat rutrum, pellentesque accumsan ligula. Duis sit amet turpis metus. Aenean in rhoncus metus, ac fringilla ex. Suspendisse condimentum egestas purus, ut pharetra odio vulputate vel. Duis tincidunt massa a placerat ultrices. Mauris ultricies nibh sit amet condimentum malesuada. Duis tincidunt id ipsum sed congue. + +Praesent eu ex augue. Nullam in porta ligula. In tincidunt accumsan arcu, in pellentesque magna tristique in. Mauris eleifend libero ac nisl viverra faucibus. Nam sollicitudin dolor in commodo hendrerit. Cras at orci metus. Ut quis laoreet orci. Vivamus ultrices leo pellentesque tempor aliquet. Maecenas ut eros vitae purus placerat vestibulum. Etiam vitae gravida dolor, quis rhoncus diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. + +Suspendisse fringilla lacinia sagittis. Integer tincidunt consectetur tristique. Morbi non orci convallis, congue sapien quis, vulputate nunc. Donec a libero vel magna elementum facilisis non quis mi. Mauris posuere tellus non ipsum ultrices elementum. Vivamus massa velit, facilisis quis placerat aliquet, aliquet nec leo. Praesent a maximus sem. Sed neque elit, feugiat vel quam non, molestie sagittis nunc. Etiam luctus nunc ac mauris scelerisque, nec rhoncus lacus convallis. Nunc pharetra, nunc ac pulvinar aliquam, ex ipsum euismod augue, nec porttitor lacus turpis vitae neque. Fusce bibendum odio id tortor faucibus pellentesque. Sed ac porta nibh, eu gravida erat. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam quis ullamcorper felis. Nulla mattis sagittis ante ac tincidunt. Integer ac felis efficitur, viverra libero et, facilisis ligula. Suspendisse a metus a massa rhoncus posuere. Phasellus suscipit ligula ut lacus facilisis, ac pellentesque ex tempor. Quisque consectetur massa mi, ac molestie libero dictum quis. Proin porttitor ligula quis erat tincidunt venenatis. Proin congue nunc sed elit gravida, nec consectetur lectus sodales. Etiam tincidunt convallis ipsum at vestibulum. Quisque maximus enim et mauris porttitor, et molestie magna tristique. Morbi vitae metus elit. Maecenas sed volutpat turpis. Aliquam vitae dolor vestibulum, elementum purus eget, dapibus nibh. Nullam egestas dui ac rutrum semper. + +Etiam hendrerit est metus, et condimentum metus aliquam ac. Pellentesque id neque id ipsum rhoncus vulputate. Aliquam erat nisl, posuere sit amet ligula ac, fermentum blandit felis. Vivamus fermentum mi risus, non lacinia purus viverra id. Aenean ac sapien consequat, finibus mauris nec, porta sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed quis consectetur ex, dignissim bibendum nulla. Phasellus ac libero at quam vehicula euismod non eu leo. Phasellus a sapien augue. + +Maecenas ligula dui, bibendum vitae mauris et, auctor laoreet felis. Duis non libero a mi semper mattis. Quisque consequat luctus massa, quis tristique eros auctor feugiat. Maecenas sodales euismod neque vitae facilisis. Nullam laoreet imperdiet velit at pellentesque. Etiam massa odio, facilisis a consequat vitae, placerat vel magna. Nunc sagittis eros nec urna fringilla, pulvinar vestibulum nibh scelerisque. Sed magna metus, cursus eu consequat et, pharetra a est. Suspendisse elementum neque a dui malesuada lacinia. Donec sed ipsum volutpat, cursus urna id, ullamcorper arcu. Maecenas laoreet nisl eget velit egestas sollicitudin. Etiam nisl turpis, mollis id dignissim vitae, tristique vehicula ante. Maecenas eget placerat est, at rutrum augue. Vivamus faucibus lacinia ullamcorper. Sed pulvinar urna sodales ante sodales, at gravida leo dictum. + +Morbi maximus, quam a lobortis bibendum, enim felis varius elit, ac vehicula elit nisl ut lacus. Quisque ut arcu augue. Praesent id turpis quam. Sed sed arcu eros. Maecenas at cursus lorem, ac eleifend nisi. Fusce mattis felis at commodo pharetra. Praesent ac commodo ipsum. Quisque finibus et eros vitae tincidunt. In hac habitasse platea dictumst. Praesent purus ipsum, luctus lobortis ornare quis, auctor eget justo. Nam vel enim sollicitudin, faucibus tortor eu, sagittis eros. Ut nec consectetur erat. Donec ultricies malesuada ligula, a hendrerit sapien volutpat in. Maecenas sed enim vitae sapien pulvinar faucibus. + +Proin semper nunc nibh, non consequat neque ullamcorper vel. Maecenas lobortis sagittis blandit. Aenean et arcu ultricies turpis malesuada malesuada. Ut quam ex, laoreet ut blandit cursus, feugiat vitae dolor. Etiam ex lacus, scelerisque vel erat vel, efficitur tincidunt magna. Morbi tristique lacinia dolor, in egestas magna ultrices vitae. Integer ultrices leo ac tempus venenatis. Praesent ac porta tortor. Vivamus ornare blandit tristique. Nulla rutrum finibus pellentesque. In non dui elementum, fermentum ipsum vel, varius magna. Pellentesque euismod tortor risus, ac pellentesque nisl faucibus eget. + +Vivamus eu enim purus. Cras ultrices rutrum egestas. Sed mollis erat nibh, at posuere nisl luctus nec. Nunc vulputate, sapien id auctor molestie, nisi diam tristique ante, non convallis tellus nibh at orci. Morbi a posuere purus, in ullamcorper ligula. Etiam elementum sit amet dui imperdiet iaculis. Proin vitae tincidunt ipsum, sit amet placerat lectus. Curabitur commodo sapien quam, et accumsan lectus fringilla non. Nullam eget accumsan enim, ac pharetra mauris. Sed quis tristique velit, vitae commodo nisi. Duis turpis dui, maximus ut risus at, finibus consequat nunc. Maecenas sed est accumsan, aliquet diam in, facilisis risus. Curabitur vehicula rutrum auctor. Nam iaculis risus pulvinar maximus viverra. Nulla vel augue et ex sagittis blandit. + +Ut sem nulla, porta ac ante ac, posuere laoreet eros. Donec sodales posuere justo a auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras mollis at orci hendrerit porta. Nullam sodales tortor tortor, non lacinia diam finibus id. Duis libero orci, suscipit ac odio et, dictum consequat ipsum. Pellentesque eu ligula sagittis, volutpat eros at, lacinia lorem. Cras euismod tellus in iaculis tempor. Quisque accumsan, magna a congue venenatis, ante ipsum aliquam lectus, at egestas enim nunc at justo. Quisque sem purus, viverra ut tristique ut, maximus id enim. Etiam quis placerat sem. In sollicitudin, lacus eu rutrum mollis, nulla eros luctus elit, vel dapibus urna purus nec urna. Phasellus egestas massa quam, ac molestie erat hendrerit a. Praesent ultrices neque ut turpis molestie auctor. Etiam molestie placerat purus, et euismod erat aliquam in. Morbi id suscipit justo. + +Proin est ante, consequat at varius a, mattis quis felis. Sed accumsan nibh sit amet ipsum elementum posuere. Vestibulum bibendum id diam sit amet gravida. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi nec dolor vel ipsum dignissim hendrerit vel non ipsum. Praesent facilisis orci quis elit auctor lobortis. Phasellus cursus risus lectus, vel lobortis libero dapibus in. Quisque tristique tempus leo a pulvinar. Pellentesque a magna tincidunt, pellentesque massa nec, laoreet orci. Morbi congue ornare dolor quis commodo. Phasellus massa nisi, tincidunt at eros dictum, hendrerit lobortis urna. Maecenas porta, magna id mattis molestie, nibh tellus lobortis sem, eget tincidunt ipsum quam eu turpis. + +Ut gravida orci risus, vel rutrum mauris vehicula id. Etiam bibendum, neque a placerat condimentum, ex orci imperdiet lectus, quis dapibus arcu lacus eget lectus. Sed consequat non mi sit amet venenatis. Fusce vestibulum erat libero, eget hendrerit risus vulputate sollicitudin. Integer sed eleifend felis. Donec commodo, sem eu mattis placerat, urna odio aliquam tellus, et laoreet justo tellus eget erat. Fusce sed suscipit tortor. Nam hendrerit nibh ac nunc auctor lacinia. Pellentesque placerat condimentum ipsum, eget semper tortor hendrerit vel. Nullam non urna eu lacus pellentesque congue ut id eros. + +Nunc finibus leo in rhoncus tristique. Sed eu ipsum nec nisl egestas faucibus eget a felis. Pellentesque vitae nisi in nulla accumsan fermentum. Sed venenatis feugiat eleifend. Fusce porttitor varius placerat. Aliquam aliquet lacus sit amet mattis mollis. Sed vel nulla quis dolor suscipit vehicula ac viverra lorem. Duis viverra ipsum eget nulla ullamcorper fermentum. Mauris tincidunt arcu quis quam fringilla ornare. Donec et iaculis tortor. Nam ultricies libero vel ipsum aliquet efficitur. Morbi eget dolor aliquam, tempus sapien eget, viverra ante. Donec varius mollis ex, sed efficitur purus euismod interdum. Quisque vel sapien non neque tincidunt semper. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Suspendisse sit amet purus leo. Fusce lectus lorem, aliquam ac nulla eget, imperdiet ornare eros. Nullam sem augue, varius in nisi non, sollicitudin pellentesque ante. Etiam eu odio condimentum, tempor libero et, egestas arcu. Cras pellentesque eleifend aliquet. Pellentesque non blandit ligula. Ut congue viverra rhoncus. Phasellus mattis mi ac eros placerat, eu feugiat tellus ultrices. Aenean mollis laoreet libero eu imperdiet. Cras sed pulvinar mi, ac vehicula ligula. Vestibulum sit amet ex massa. In a egestas eros. + +Mauris pretium ipsum risus, venenatis cursus ante imperdiet id. Praesent eu turpis nec risus feugiat maximus ullamcorper ac lectus. Integer placerat at mi vel dapibus. Vestibulum fermentum turpis sit amet turpis viverra, id aliquet diam suscipit. Nam nec ex sed ante ullamcorper pharetra quis sit amet risus. Sed ac faucibus velit, id feugiat nibh. Nullam eget ipsum ex. Vivamus tincidunt non nunc non faucibus. Quisque bibendum viverra facilisis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at nisi hendrerit quam suscipit egestas. Curabitur laoreet maximus ultricies. Duis ut tellus ac augue molestie dictum. + +Suspendisse rhoncus iaculis erat, ut ullamcorper est tristique eget. Donec auctor nec risus at gravida. Vivamus volutpat vulputate tellus, vel ultricies eros suscipit eget. Ut pulvinar id mi eu tempus. Morbi malesuada augue in dui varius, nec blandit neque vehicula. Donec ornare nec nisl in mollis. Morbi enim nisi, rhoncus nec est id, dapibus tempus urna. Ut id elit a felis vestibulum consectetur. Duis lectus quam, pharetra sit amet diam sed, posuere vestibulum erat. Fusce vitae maximus massa. Nullam id metus tempus, iaculis risus eu, lobortis urna. Quisque in congue urna. Pellentesque placerat neque in augue dapibus, non varius ex malesuada. Curabitur ut eleifend libero. Fusce vitae ligula luctus, fermentum enim vitae, ultrices erat. + +Sed viverra augue turpis, scelerisque egestas sapien mattis eu. Duis laoreet magna at ex pharetra dapibus. Praesent eget odio vel quam venenatis dictum. Nulla in sollicitudin dolor. Mauris lobortis nec eros vel rhoncus. Vestibulum porta viverra venenatis. Curabitur vel scelerisque quam, a egestas velit. Praesent volutpat tincidunt magna at laoreet. + +Cras nec lorem odio. Pellentesque quis dui urna. Praesent at tellus ac lectus scelerisque placerat nec eu risus. Vestibulum sit amet mattis ligula. Vivamus sed nisi at leo elementum accumsan at sit amet arcu. Aenean mattis tellus nec leo gravida, eget hendrerit nisl faucibus. Mauris pellentesque luctus condimentum. Maecenas pretium sapien nunc, eget commodo dolor maximus id. Mauris vestibulum accumsan massa a dictum. Phasellus interdum quam ligula, ut maximus diam blandit aliquam. Nunc vitae ex eu erat condimentum consectetur. Maecenas interdum condimentum volutpat. + +Donec et enim a libero rutrum laoreet. Praesent a condimentum sem, at tincidunt quam. In vel molestie risus. Sed urna dui, molestie vitae mollis laoreet, tempor quis lectus. Praesent vitae auctor est, et aliquet nunc. Curabitur vulputate blandit nulla, at gravida metus. Maecenas gravida dui eu iaculis tristique. Pellentesque posuere turpis nec auctor eleifend. Suspendisse bibendum diam eu tellus lobortis, et laoreet quam congue. In hac habitasse platea dictumst. Morbi dictum neque velit, eget rutrum eros ultrices sit amet. + +Phasellus fermentum risus pharetra consectetur bibendum. Donec magna tortor, lacinia vitae nibh quis, aliquet pretium lorem. Donec turpis nisi, pretium eu enim volutpat, mattis malesuada augue. Nullam vel tellus iaculis, sollicitudin elit eget, tincidunt lacus. Fusce elementum elementum felis et iaculis. Suspendisse porta eros nec neque malesuada, in malesuada ante sollicitudin. Vivamus bibendum viverra molestie. + +Integer feugiat, erat nec convallis aliquam, velit felis congue erat, molestie eleifend tellus erat in tellus. Nunc et justo purus. Donec egestas fermentum dui non feugiat. Quisque in sapien sagittis, gravida quam id, iaculis lectus. Cras sagittis rhoncus bibendum. Fusce quis metus in velit scelerisque tincidunt at non ipsum. Vivamus efficitur ante eu odio vulputate, vitae ultricies risus vehicula. Proin eget odio eu sem tincidunt feugiat vel id lorem. + +Vestibulum sit amet nulla dignissim, euismod mi in, fermentum tortor. Donec ut aliquet libero, lacinia accumsan velit. Donec et nulla quam. Nullam laoreet odio nec nunc imperdiet, a congue eros venenatis. Quisque nec tellus sit amet neque interdum posuere. Duis quis mi gravida, tincidunt diam convallis, ultricies augue. Mauris consequat risus non porttitor congue. Ut in ligula consequat, viverra nunc a, eleifend enim. Duis ligula urna, imperdiet nec facilisis et, ornare eu ex. Proin lobortis lectus a lobortis porttitor. Nulla leo metus, egestas eu libero sed, pretium faucibus felis. Vestibulum non sem tortor. Nam cursus est leo. Vivamus luctus enim odio, non interdum sem dapibus a. Aenean accumsan consequat lectus in imperdiet. + +Donec vehicula laoreet ipsum in posuere. Quisque vel quam imperdiet, sollicitudin nisi quis, suscipit velit. Morbi id sodales mauris. Curabitur tellus arcu, feugiat sed dui sit amet, sodales sagittis libero. Aenean vel suscipit metus, non placerat leo. Vestibulum quis nulla elit. Proin scelerisque non ante ut commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. + +Sed non urna dolor. Suspendisse convallis mi porta pulvinar ultrices. Suspendisse quam ipsum, hendrerit non scelerisque molestie, interdum dictum nunc. Morbi condimentum condimentum turpis eu luctus. Pellentesque sagittis sollicitudin odio, sed ultricies felis ornare sit amet. Sed ultrices ex leo, a tincidunt nisl gravida sed. Nullam ornare accumsan porta. Praesent consectetur id est nec sollicitudin. + +In hac habitasse platea dictumst. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed sed ultrices nibh. Duis accumsan suscipit eros, a dictum odio tempus sit amet. Aenean imperdiet erat ac lacus finibus, scelerisque cursus massa imperdiet. Mauris molestie risus ut lacinia posuere. Nulla et sodales purus. Maecenas orci erat, placerat in tristique quis, placerat in mi. + +Donec sollicitudin pellentesque odio in feugiat. Morbi eu dolor ut mauris congue sollicitudin. Aliquam erat volutpat. Nulla id varius dui. Curabitur finibus urna ante, consectetur interdum nisi volutpat a. Quisque quis mi tristique, consequat tellus eget, rutrum sapien. Vivamus vitae tellus vulputate, rutrum ex eu, vulputate sem. Suspendisse viverra lorem tellus, vel interdum orci gravida quis. Ut laoreet arcu at mi ullamcorper finibus. Duis porta sagittis vestibulum. Sed commodo nisl vitae urna sollicitudin, nec lacinia est sodales. Curabitur imperdiet sodales dui sed iaculis. Sed ac tellus maximus, eleifend quam sit amet, feugiat elit. Aenean viverra, dui at mattis varius, est odio vestibulum sapien, sit amet mollis libero massa nec velit. Etiam quis sodales justo. + +Ut ultricies, sem eget sodales feugiat, nunc arcu congue elit, ac tempor justo massa nec purus. Maecenas enim nunc, pharetra eget dictum sit amet, tempus pellentesque velit. Suspendisse venenatis ligula in nulla mattis, et imperdiet ex tincidunt. Etiam vulputate, tellus et ultrices suscipit, enim velit laoreet massa, vitae congue odio enim ac urna. Morbi quam lorem, iaculis ac varius sagittis, euismod quis dolor. In ut dui eu purus feugiat consectetur. Vestibulum cursus velit quis lacus pellentesque iaculis. Cras in risus sed mauris porta rutrum. Nulla facilisi. Nullam eu bibendum est, non pellentesque lectus. Sed imperdiet feugiat lorem, quis convallis ante auctor in. Maecenas justo magna, scelerisque sit amet tellus eget, varius elementum risus. Duis placerat et quam sed varius. + +Duis nec nibh vitae nibh dignissim mollis quis sed felis. Curabitur vitae quam placerat, venenatis purus ut, euismod nisl. Curabitur porttitor nibh eu pulvinar ullamcorper. Suspendisse posuere nec ipsum ac dapibus. Cras convallis consectetur urna. Phasellus a nibh in dolor lacinia posuere id eget augue. In eu pharetra lorem, vitae cursus lacus. Aliquam tincidunt nibh lectus. Aenean facilisis ultricies posuere. Sed ut placerat orci. Curabitur scelerisque gravida blandit. Maecenas placerat ligula eget suscipit fringilla. Mauris a tortor justo. Aliquam hendrerit semper mollis. Phasellus et tincidunt libero. Etiam vel quam libero. + +Quisque aliquet tempor ex. Ut ante sem, vehicula at enim vel, gravida porta elit. Etiam vitae lacus a neque lobortis consectetur. Mauris sed interdum odio. Mauris elementum ex blandit tempor cursus. Integer in enim in leo viverra elementum. Fusce consectetur metus et sem rutrum, mattis euismod diam semper. Nunc sed ipsum vel urna consequat vehicula. Donec cursus pretium lorem, vestibulum pretium felis commodo sit amet. Nam blandit felis enim, eget gravida ex faucibus a. In nec neque massa. Etiam laoreet posuere ipsum. Praesent volutpat nunc dolor, ac vulputate magna facilisis non. Aenean congue turpis vel lectus sollicitudin tristique. Sed nec consequat purus, non vehicula quam. Etiam ultricies, est ac dictum tincidunt, turpis turpis pretium massa, a vulputate libero justo at nibh. + +Aliquam erat volutpat. Cras ultrices augue ac sollicitudin lobortis. Curabitur et aliquet purus. Duis feugiat semper facilisis. Phasellus lobortis cursus velit, a sollicitudin tortor. Nam feugiat sapien non dapibus condimentum. Morbi at mi bibendum, commodo quam at, laoreet enim. Integer eu ultrices enim. Sed vestibulum eu urna ut dictum. Curabitur at mattis leo, sed cursus massa. Aliquam porttitor, felis quis fermentum porttitor, justo velit feugiat nulla, eget condimentum sem dui ut sapien. + +In fringilla elit eu orci aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut eget fringilla tellus. Curabitur fermentum, mi et condimentum suscipit, elit neque bibendum dui, et hendrerit nunc metus id ipsum. Morbi placerat mi in hendrerit congue. Ut feugiat mauris eget scelerisque viverra. Vivamus sit amet erat dictum, sagittis lectus nec, pulvinar lorem. Sed non enim ac dui sollicitudin aliquet. Quisque ut lacus dolor. Fusce hendrerit malesuada euismod. Nulla faucibus vel mauris eu mollis. Mauris est diam, fringilla ac arcu feugiat, efficitur volutpat turpis. Aliquam venenatis cursus massa sed porttitor. Ut ac finibus enim, in tincidunt sapien. + +Nunc faucibus semper turpis a lacinia. Phasellus gravida, libero vel pulvinar ornare, ex sem tincidunt lectus, sit amet convallis augue risus at tortor. Quisque sit amet ipsum id nulla posuere vestibulum. Pellentesque scelerisque mauris vel leo viverra sodales. Nulla viverra aliquam ex, ut rutrum enim fermentum venenatis. Aenean eget dapibus ex, eget faucibus metus. Vestibulum volutpat leo in diam semper, eget porta magna suscipit. Sed sit amet nulla blandit, aliquam dolor ac, gravida velit. Sed vel velit viverra, maximus est id, convallis justo. + +Curabitur nulla ante, vulputate at libero vel, ullamcorper rutrum nibh. Pellentesque porttitor eu mauris id mattis. Duis vulputate augue elit, eget interdum justo pretium vel. Maecenas eu vulputate arcu, eget posuere purus. Suspendisse viverra a velit dictum eleifend. Suspendisse vitae dapibus diam. Donec vehicula justo in ante interdum, eu luctus diam placerat. Vivamus convallis ipsum eu orci suscipit, sed fermentum enim euismod. Maecenas faucibus elit vitae ex ornare tristique. Donec vestibulum nec elit sit amet porttitor. Aenean tempor lectus eget tortor hendrerit luctus. Nullam interdum vitae lectus vel feugiat. Cras in risus non magna consectetur lobortis. Sed faucibus enim quis gravida convallis. + +Phasellus eget massa sit amet libero ultrices suscipit. Vivamus at risus sapien. Nam mollis nunc eget velit dictum maximus. Sed pellentesque, nunc ac fringilla lacinia, quam enim mattis ex, sed euismod tortor metus eu neque. Ut mattis nisl ut lectus rhoncus, sodales bibendum eros porta. Nulla porttitor enim nec diam sagittis, eget porta velit efficitur. Vestibulum ultricies eros neque. Phasellus rutrum suscipit enim, in interdum ante gravida vitae. Sed in sagittis diam, non commodo velit. + +Morbi hendrerit odio orci, nec tincidunt odio rhoncus nec. Mauris neque velit, vehicula a lorem at, suscipit tristique dui. Sed finibus, nisl in mattis convallis, turpis neque sodales lacus, eu porta enim magna non diam. Nam commodo sodales risus consectetur malesuada. In eget elementum justo. Phasellus sit amet massa imperdiet, dapibus nunc sit amet, suscipit orci. Fusce condimentum laoreet feugiat. Ut ut viverra ante. Praesent bibendum interdum commodo. Nulla mollis nisi a est ornare volutpat. Sed at ligula eu nisi dapibus tempus. Proin cursus vestibulum justo, nec efficitur justo dignissim vel. Nunc quis maximus eros. + +Cras viverra, diam a tristique mattis, libero felis vulputate tellus, a ornare felis leo a dui. Nulla ante nulla, finibus ut tellus ut, blandit pharetra nibh. Proin eleifend fermentum ex, eget auctor libero vulputate in. Nullam ultricies, mauris placerat pretium placerat, leo urna lobortis leo, vel placerat arcu libero sed mauris. Aliquam mauris ligula, ornare at urna at, eleifend gravida ligula. Vestibulum consectetur ut nulla non scelerisque. Donec ornare, sem nec elementum aliquam, urna nulla bibendum metus, eu euismod dui ligula ac est. Fusce laoreet erat eu ex lobortis, quis bibendum ligula interdum. Sed vel mi erat. Vivamus id lacus ac enim mattis tempor. Nunc ultricies pellentesque enim sed euismod. Fusce tincidunt convallis elit quis aliquam. Mauris nulla ipsum, sollicitudin quis diam ac, feugiat volutpat tellus. In nibh nibh, vulputate quis tincidunt quis, pulvinar eget magna. Pellentesque quis finibus dolor. Suspendisse viverra vitae lectus non eleifend. + +Nunc ut orci et sapien maximus semper. Nulla dignissim sem urna, ac varius lectus ultricies id. Quisque aliquet pulvinar pretium. In ultricies molestie tellus vehicula porta. Nam enim lorem, aliquam eget ex et, hendrerit volutpat quam. Maecenas diam lacus, pellentesque eget tempus ac, pharetra eu elit. Donec vel eros a sem facilisis vulputate. Nullam ac nisi vulputate, laoreet nisl ac, eleifend sem. Nullam mi massa, rhoncus sed pharetra interdum, tincidunt eget nunc. Aliquam viverra mattis posuere. Mauris et dui sed nisl sollicitudin fermentum quis ut arcu. Nam placerat eget orci at tincidunt. Curabitur vel turpis metus. Phasellus nibh nulla, fermentum scelerisque sem vel, gravida tincidunt velit. Pellentesque vel quam tempor, finibus massa pellentesque, condimentum dui. + +Donec at mattis neque. Etiam velit diam, consequat auctor mauris id, hendrerit faucibus metus. Maecenas ullamcorper eros a est sodales, ac consectetur odio scelerisque. Donec leo metus, imperdiet at pellentesque vel, feugiat id erat. Suspendisse at magna enim. Vestibulum placerat sodales lorem id sollicitudin. Aenean at euismod ligula, eget mollis diam. Phasellus pulvinar, orci nec pretium condimentum, est erat facilisis purus, quis feugiat augue elit aliquam nulla. Aenean vitae tortor id risus congue tincidunt. Sed dolor enim, mattis a ullamcorper id, volutpat ac leo. + +Proin vehicula feugiat augue, id feugiat quam sodales quis. Donec et ultricies massa, a lacinia nulla. Duis aliquam augue ornare euismod viverra. Ut lectus risus, rutrum sit amet efficitur a, luctus nec nisl. Cras volutpat ullamcorper congue. Sed vitae odio metus. Phasellus aliquet euismod varius. + +Nullam sem ex, malesuada ut magna ut, pretium mollis arcu. Nam porttitor eros cursus mi lacinia faucibus. Suspendisse aliquet eleifend iaculis. Maecenas sit amet viverra tortor. Nunc a mollis risus. Etiam tempus dolor in tortor malesuada mattis. Ut tincidunt venenatis est sit amet dignissim. Vestibulum massa enim, tristique sed scelerisque eu, fringilla ac velit. Donec efficitur quis urna sit amet malesuada. Vestibulum consequat ac ligula in dapibus. Maecenas massa massa, molestie non posuere nec, elementum ut magna. In nisi erat, mollis non venenatis eu, faucibus in justo. Morbi gravida non ex non egestas. Pellentesque finibus laoreet diam, eu commodo augue congue vitae. + +Aenean sem mi, ullamcorper dapibus lobortis vitae, interdum tincidunt tortor. Vivamus eget vulputate libero. Ut bibendum posuere lectus, vel tincidunt tortor aliquet at. Phasellus malesuada orci et bibendum accumsan. Aliquam quis libero vel leo mollis porta. Sed sagittis leo ac lacus dictum, ac malesuada elit finibus. Suspendisse pharetra luctus commodo. Vivamus ultricies a odio non interdum. Vivamus scelerisque tincidunt turpis quis tempor. Pellentesque tortor ligula, varius non nunc eu, blandit sollicitudin neque. Nunc imperdiet, diam et tristique luctus, ipsum ex condimentum nunc, sit amet aliquam justo velit sed libero. Duis vel suscipit ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed tincidunt neque vel massa ultricies, id dictum leo consequat. Curabitur lobortis ultricies tellus, eget mattis nisl aliquam sit amet. + +Proin at suscipit justo. Vivamus ut vestibulum nisl. Pellentesque enim odio, pharetra non magna sed, efficitur auctor magna. Praesent tincidunt ante quis ante hendrerit viverra. Pellentesque vel ipsum id magna vulputate efficitur. Sed nec neque accumsan, pulvinar sapien quis, euismod mauris. Donec condimentum laoreet sapien quis gravida. Quisque sed mattis purus. Vestibulum placerat vel neque maximus scelerisque. + +Vestibulum mattis quam quis efficitur elementum. Duis dictum dolor ac scelerisque commodo. Fusce sollicitudin nisi sit amet dictum placerat. Suspendisse euismod pharetra eleifend. In eros nisl, porttitor sed mauris at, consectetur aliquet mauris. Donec euismod viverra neque sed fermentum. Phasellus libero magna, accumsan ut ultricies vitae, dignissim eget metus. Donec tellus turpis, interdum eget maximus nec, hendrerit eget massa. Curabitur auctor ligula in iaculis auctor. In ultrices quam suscipit cursus finibus. Aenean id mi at dolor interdum iaculis vitae ut lorem. Nullam sed nibh fringilla, lacinia odio nec, placerat erat. In dui libero, viverra ac viverra ac, pellentesque sit amet turpis. + +Nulla in enim ex. Sed feugiat est et consectetur venenatis. Cras varius facilisis dui vel convallis. Vestibulum et elit eget tellus feugiat pellentesque. In ut ante eu purus aliquet posuere. Nulla nec ornare sem, sed luctus lorem. Nam varius iaculis odio, eget faucibus nisl ullamcorper in. Sed eget cursus felis, nec efficitur nisi. + +Vivamus commodo et sem quis pulvinar. Pellentesque libero ante, venenatis vitae ligula sit amet, ornare sollicitudin nulla. Mauris eget tellus hendrerit, pulvinar metus quis, tempor nisi. Proin magna ex, laoreet sed tortor quis, varius fermentum enim. Integer eu dolor dictum, vulputate tortor et, aliquet ligula. Vestibulum vitae justo id mauris luctus sollicitudin. Suspendisse eget auctor neque, sodales egestas lorem. Vestibulum lacinia egestas metus vitae euismod. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus ex tellus, volutpat nec pulvinar sit amet, condimentum vitae dui. Curabitur vel felis sodales, lacinia nunc iaculis, ullamcorper augue. Pellentesque consequat dolor quis eros efficitur malesuada. Nulla ut malesuada lectus. + +Morbi et tristique ante. Aliquam erat volutpat. Vivamus vitae dui nec turpis pellentesque fermentum. Quisque eget velit massa. Pellentesque tristique aliquam nisl, eu sollicitudin justo venenatis sed. Duis eleifend sem eros, ut aliquam libero porttitor id. Sed non nunc consequat, rhoncus diam eu, commodo erat. Praesent fermentum in lectus id blandit. Donec quis ipsum at justo volutpat finibus. Nulla blandit justo nulla, at mollis lacus consequat eget. Aenean sollicitudin quis eros ut ullamcorper. + +Pellentesque venenatis nulla ut mi aliquet feugiat. Cras semper vel magna nec pharetra. Integer mattis felis et sapien commodo imperdiet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis quis luctus felis. Vestibulum justo nibh, aliquam non lectus vitae, molestie placerat justo. Donec lorem nibh, gravida sit amet hendrerit ac, maximus id ipsum. Nunc ac libero sodales risus eleifend sagittis. Phasellus est massa, lobortis elementum ex sed, scelerisque consectetur neque. Nunc faucibus neque id lorem malesuada, eget convallis ex mattis. + +Sed turpis tortor, fermentum non turpis id, posuere varius nibh. Donec iaculis lorem dui. Etiam eros ante, sodales eget venenatis at, consectetur eget risus. Curabitur non aliquam ante, a pretium justo. Maecenas tempor nisl tortor, vitae dictum nisi ultrices eu. Duis eget dui ultrices, porttitor lacus sed, lobortis purus. Quisque mattis elit nec neque sagittis, sed commodo leo blandit. Mauris sodales interdum eleifend. Vestibulum condimentum consectetur augue, id luctus diam convallis et. + +Nunc suscipit risus in justo accumsan, a placerat magna tincidunt. Proin a nisl ipsum. Sed libero dui, tristique in augue quis, auctor tristique risus. Sed porttitor ex augue, eu porta augue molestie a. Duis rhoncus purus libero, eu tempus turpis condimentum at. Sed mollis nisi id lectus placerat tincidunt. Maecenas non scelerisque elit, quis rutrum orci. Donec in tellus pharetra urna ornare lobortis. Phasellus id risus at nisi varius rutrum eu ut turpis. + +Duis dictum justo quis nisl porta, eget tincidunt magna suscipit. Sed velit massa, ullamcorper eu sodales ac, pretium a massa. Duis et rutrum tortor. Nulla accumsan hendrerit sapien, cursus volutpat eros egestas eget. Donec sollicitudin at ante quis sollicitudin. Aenean blandit feugiat diam, id feugiat eros faucibus eget. Donec viverra dolor vel justo scelerisque dignissim. Nulla semper sem nunc, rhoncus semper tellus ultricies sed. Duis in ornare diam. Donec vehicula feugiat varius. Maecenas ut suscipit est. Vivamus sem sem, finibus at dolor sit amet, euismod dapibus ligula. Vestibulum fringilla odio dapibus, congue massa eget, congue sem. Donec feugiat magna eget tortor lacinia scelerisque non et ipsum. + +Suspendisse potenti. Nunc convallis sollicitudin ex eget venenatis. Sed iaculis nibh ex, vel ornare ligula congue dignissim. Quisque sollicitudin dolor ac dui vestibulum, sit amet molestie nisi aliquet. Donec at risus felis. Aenean sollicitudin metus a feugiat porta. Aenean a tortor ut dolor cursus sagittis. Vivamus consectetur porttitor nunc in facilisis. Proin sit amet mi vel lectus consectetur ultrices. + +Sed cursus lectus vitae nunc tristique, nec commodo turpis dapibus. Pellentesque luctus ex id facilisis ornare. Morbi quis placerat dolor. Donec in lectus in arcu mattis porttitor ac sit amet metus. Cras congue mauris non risus sodales, vitae feugiat ipsum bibendum. Nulla venenatis urna sed libero elementum, a cursus lorem commodo. Mauris faucibus lobortis eros nec commodo. + +Nullam suscipit ligula ullamcorper lorem commodo blandit. Nulla porta nibh quis pulvinar placerat. Vivamus eu arcu justo. Vestibulum imperdiet est ut fermentum porttitor. Pellentesque consectetur libero in sapien efficitur scelerisque. Curabitur ac erat sit amet odio aliquet dignissim. Pellentesque mi sem, rhoncus et luctus at, porttitor rutrum lectus. Vestibulum sollicitudin sollicitudin suscipit. Aenean efficitur dolor non ultrices imperdiet. Donec vel sem ex. + +Sed convallis mauris aliquam rutrum cursus. Ut tempor porttitor sodales. Etiam eu risus ac augue gravida egestas et eu dolor. Proin id magna ex. Suspendisse quis lectus quis lorem ultricies tempus. Donec porttitor velit vitae tincidunt faucibus. Aliquam vitae semper nisi. Morbi ultrices, leo non pretium dapibus, dui libero pellentesque ex, vel placerat enim ante vitae dui. Nunc varius, sem sit amet sagittis lobortis, lectus odio scelerisque mauris, ut vestibulum orci magna quis neque. Sed id congue justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris congue nisi est, malesuada mollis elit tincidunt sed. Curabitur sed ex sit amet felis tristique elementum vitae vel nibh. + +Etiam mollis pretium lobortis. Mauris augue lacus, efficitur at lacus sed, mollis tincidunt lectus. Aliquam erat volutpat. Donec at euismod elit, et mattis felis. Sed id lobortis urna. Morbi imperdiet vestibulum leo, sed maximus leo blandit eu. Aliquam semper lorem neque, nec euismod turpis mattis mollis. Quisque lobortis urna ultrices odio pretium, ac venenatis orci faucibus. Suspendisse bibendum odio ligula, sed lobortis massa pharetra nec. Donec turpis justo, iaculis at dictum ac, finibus eu libero. Maecenas quis porttitor mi, sit amet aliquet neque. + +Vivamus auctor vulputate ante, at egestas lorem. Donec eu risus in nulla mollis ultricies at et urna. Duis accumsan porta egestas. Ut vel euismod augue. Fusce convallis nulla ante, nec fringilla velit aliquet at. Nam malesuada dapibus ligula, a aliquam nibh scelerisque ac. Praesent malesuada neque et pellentesque interdum. Curabitur volutpat at turpis vitae tristique. Vivamus porttitor semper congue. Quisque suscipit lacus mi, rhoncus ultrices tortor auctor quis. Maecenas neque neque, molestie ac facilisis eget, luctus ac lorem. In ut odio ut lacus suscipit pulvinar vitae sed elit. Nulla imperdiet, sem quis euismod sagittis, dui erat luctus dolor, faucibus faucibus erat sem eget nunc. Nam accumsan placerat malesuada. Maecenas convallis finibus pulvinar. + +Cras at placerat tortor. Morbi facilisis auctor felis sit amet molestie. Donec sodales sed lorem vitae suscipit. Etiam fermentum pharetra ipsum, nec luctus orci gravida eu. Pellentesque gravida, est non condimentum tempus, mauris ligula molestie est, in congue dolor nisl vel sapien. Duis congue tempor augue, id rutrum eros porta dapibus. Etiam rutrum eget est eget vestibulum. Aenean mollis arcu vel consequat varius. Praesent at condimentum felis. Duis nec interdum nisl. Donec commodo lorem sed sapien scelerisque malesuada non eu urna. In blandit non ipsum at porta. Nam lobortis leo vitae dui auctor, non feugiat quam bibendum. Donec auctor lectus sagittis laoreet maximus. Maecenas rhoncus laoreet porttitor. Vestibulum porttitor augue ut lectus hendrerit, eget posuere mi gravida. + +Sed mattis ex in erat pulvinar, eu imperdiet magna dapibus. Etiam nisi nibh, tempus non tellus sit amet, mattis tempor odio. Quisque nec lorem feugiat, lobortis odio et, commodo nunc. Maecenas semper purus nisi, nec vehicula nibh eleifend vitae. Nulla fermentum a lectus at maximus. Phasellus finibus metus non euismod ultrices. Etiam a pulvinar ante. Quisque convallis nec metus sit amet facilisis. Praesent laoreet massa et sollicitudin laoreet. Vestibulum in mauris aliquet, convallis mi ut, elementum purus. Nulla purus nulla, sodales at hendrerit quis, tempus sed lectus. + +Nam ut laoreet neque, ut maximus nibh. Maecenas quis justo pellentesque, sollicitudin elit at, venenatis velit. Aenean nunc velit, vehicula scelerisque odio at, consectetur laoreet purus. Duis dui purus, malesuada quis ipsum sit amet, tempor interdum libero. Curabitur porta scelerisque sapien, vitae cursus diam condimentum eu. Phasellus sed orci quam. Nullam vitae dui quis purus tincidunt vestibulum. Curabitur quis nulla porta, cursus arcu non, auctor enim. Etiam sollicitudin ex id sem vehicula mollis. Morbi viverra laoreet tincidunt. Praesent ut semper dui. Nam sit amet pretium neque. Mauris vitae luctus diam, in lacinia purus. Maecenas ut placerat justo, ut porta felis. Integer eu mauris ante. + +Aenean porttitor tellus diam, tempor consequat metus efficitur id. Suspendisse ut felis at erat tempor dictum at nec sapien. Sed vestibulum interdum felis, ac mattis mauris porta in. Nunc et condimentum massa. Sed cursus dictum justo et luctus. Integer convallis enim nisl, a rutrum lectus ultricies in. Donec dapibus lacus at nulla dapibus, id sollicitudin velit hendrerit. Fusce a magna at orci mollis rutrum ac a dolor. Aliquam erat volutpat. Morbi varius porta nunc, sit amet sodales ex hendrerit commodo. Donec tincidunt tortor sapien, vitae egestas sapien vehicula eget. + +Suspendisse potenti. Donec pulvinar felis nec leo malesuada interdum. Integer posuere placerat maximus. Donec nibh ipsum, tincidunt vitae luctus vitae, bibendum at leo. Sed cursus nisl ut ex faucibus aliquet sed nec eros. Curabitur molestie posuere felis. Integer faucibus velit eget consequat iaculis. Mauris sed vulputate odio. Phasellus maximus, elit a pharetra egestas, lorem magna semper tellus, vestibulum semper diam felis at sapien. Suspendisse facilisis, nisl sit amet euismod vehicula, libero nulla vehicula dolor, quis fermentum nibh elit sit amet diam. + +Morbi lorem enim, euismod eu varius ut, scelerisque quis odio. Nam tempus vitae eros id molestie. Nunc pretium in nulla eget accumsan. Quisque mattis est ut semper aliquet. Maecenas eget diam elementum, fermentum ipsum a, euismod sapien. Duis quam ligula, cursus et velit nec, ullamcorper tincidunt magna. Donec vulputate nisl est, et ullamcorper urna tempor sit amet. + +Proin lacinia dui non turpis congue pretium. Morbi posuere metus vel purus imperdiet interdum. Morbi venenatis vel eros non ultricies. Nulla vel semper elit. Ut quis purus tincidunt, auctor justo ut, faucibus turpis. Proin quis mattis erat, at faucibus ligula. Mauris in mauris enim. Donec facilisis enim at est feugiat hendrerit. Nam vel nisi lorem. Fusce ultricies convallis diam, in feugiat tortor luctus quis. Donec tempor, leo vitae volutpat aliquam, magna elit feugiat leo, quis placerat sapien felis eget arcu. Donec ornare fermentum eleifend. Integer a est orci. + +Proin rhoncus egestas leo. Nulla ultricies porta elit quis ornare. Nunc fermentum interdum vehicula. In in ligula lorem. Donec nec arcu sit amet orci lobortis iaculis. Mauris at mollis erat, sit amet mollis tortor. Mauris laoreet justo ullamcorper porttitor auctor. Aenean sit amet aliquam lectus, id fermentum eros. Praesent urna sem, vehicula ac fermentum id, dapibus ut purus. Vestibulum vitae tempus nunc. Donec at nunc ornare metus volutpat porta at eget magna. Donec varius aliquet metus, eu lobortis risus aliquam sed. Ut dapibus fermentum velit, ac tincidunt libero faucibus at. + +In in purus auctor, feugiat massa quis, facilisis nisi. Donec dolor purus, gravida eget dolor ac, porttitor imperdiet urna. Donec faucibus placerat erat, a sagittis ante finibus ac. Sed venenatis dignissim elit, in iaculis felis posuere faucibus. Praesent sed viverra dolor. Mauris sed nulla consectetur nunc laoreet molestie in ut metus. Proin ac ex sit amet magna vulputate hendrerit ac condimentum urna. Proin ligula metus, gravida et sollicitudin facilisis, iaculis ut odio. Cras tincidunt urna et augue varius, ut facilisis urna consequat. Aenean vehicula finibus quam. Ut iaculis eu diam ac mollis. Nam mi lorem, tristique eget varius at, sodales at urna. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin vitae dictum erat, et auctor ipsum. Nullam nunc nunc, sollicitudin quis magna a, vestibulum fermentum mauris. Praesent at erat dolor. Proin laoreet tristique nulla vel efficitur. Nam sed ultrices nibh, id rutrum nunc. Curabitur eleifend a erat sit amet sollicitudin. Nullam metus quam, laoreet vitae dapibus id, placerat sed leo. Aliquam erat volutpat. Donec turpis nisl, cursus eu ex sit amet, lacinia pellentesque nisl. Sed id ipsum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec interdum scelerisque lorem eu mattis. + +Vivamus ac tristique massa, nec facilisis nisl. Nam ipsum neque, tincidunt vel urna in, cursus imperdiet enim. Nam pellentesque egestas tempus. Morbi facilisis imperdiet libero vitae fringilla. Nam lacinia ligula at sapien facilisis malesuada. Nullam accumsan pulvinar sem, et cursus libero porta sit amet. Curabitur vulputate erat elit, ut pulvinar erat maximus vel. + +Cras aliquet metus ut purus sagittis, vel venenatis ante consectetur. Pellentesque nulla lacus, viverra viverra mattis non, placerat vitae nibh. Donec enim turpis, accumsan sit amet tincidunt eu, imperdiet non metus. Morbi ipsum eros, tincidunt vel est ac, tristique porttitor nibh. Praesent ut ullamcorper mauris. Sed laoreet sit amet diam congue venenatis. Integer porta purus nec orci sagittis posuere. + +Donec vehicula mauris eget lacus mollis venenatis et sed nibh. Nam sodales ligula ipsum, scelerisque lacinia ligula sagittis in. Nam sit amet ipsum at erat malesuada congue. Aenean ut sollicitudin sapien. Etiam at tempor odio. Mauris vitae purus ut magna suscipit consequat. Vivamus quis sapien neque. Nulla vulputate sem sit amet massa pellentesque, eleifend tristique ligula egestas. Suspendisse tincidunt gravida mi, in pulvinar lectus egestas non. Aenean imperdiet ex sit amet nunc sollicitudin porta. Integer justo odio, ultricies at interdum in, rhoncus vitae sem. Sed porttitor arcu quis purus aliquet hendrerit. Praesent tempor tortor at dolor dictum pulvinar. Nulla aliquet nunc non ligula scelerisque accumsan. Donec nulla justo, congue vitae massa in, faucibus hendrerit magna. Donec non egestas purus. + +Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibus mattis neque dictum sed. Sed convallis fermentum molestie. Nulla facilisi turpis duis. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vulputate, ipsum quis interdum fermentum, lorem sem fermentum eros, vitae auctor neque lacus in nisi. Suspendisse potenti. Maecenas et scelerisque elit, in tincidunt quam. Sed eu tincidunt quam. Nullam justo ex, imperdiet a imperdiet et, fermentum sit amet eros. Aenean quis tempus sem. Pellentesque accumsan magna mi, ut mollis velit sagittis id. Etiam quis ipsum orci. Fusce purus ante, accumsan a lobortis at, venenatis eu nisl. Praesent ornare sed ante placerat accumsan. Suspendisse tempus dignissim fermentum. Nunc a leo ac lacus sodales iaculis eu vitae mi. In feugiat ante at massa finibus cursus. Suspendisse posuere fringilla ornare. Mauris elementum ac quam id convallis. Vestibulum non elit quis urna volutpat aliquam a eu lacus. + +Aliquam vestibulum imperdiet neque, suscipit aliquam elit ultrices bibendum. Suspendisse ultrices pulvinar cursus. Morbi risus nisi, cursus consequat rutrum vitae, molestie sed dui. Fusce posuere, augue quis dignissim aliquam, nisi ipsum porttitor ante, quis fringilla nisl turpis ac nisi. Nulla varius enim eget lorem vehicula gravida. Donec finibus malesuada leo nec semper. Proin ac enim eros. Vivamus non tincidunt nisi, vel tristique lorem. + +Nunc consequat ex id eros dignissim, id rutrum risus laoreet. Sed euismod non erat eu ultricies. Etiam vehicula gravida lacus ut porta. Vestibulum eu eros quis nunc aliquet luctus. Cras quis semper ligula. Nullam gravida vehicula quam sed porta. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In porta cursus vulputate. Quisque porta a nisi eget cursus. Aliquam risus leo, luctus ac magna in, efficitur cursus magna. In condimentum non mi id semper. Donec interdum ante eget commodo maximus. + +Vivamus sit amet vestibulum lectus. Fusce tincidunt mi sapien, dictum sollicitudin diam vulputate in. Integer fringilla consequat mollis. Cras aliquet consequat felis eget feugiat. Nunc tempor cursus arcu, vitae ornare nunc varius et. Vestibulum et tortor vel ante viverra porttitor. Nam at tortor ullamcorper, facilisis augue quis, tristique erat. Aenean ut euismod nibh. Quisque eu tincidunt est, nec euismod eros. + +Proin vehicula nibh non viverra egestas. Phasellus sem dolor, ultricies ac sagittis tristique, lacinia a purus. Vestibulum in ante eros. Pellentesque lacus nulla, tristique vitae interdum vel, malesuada ac diam. Aenean bibendum posuere turpis in accumsan. Ut est nulla, ullamcorper quis turpis at, viverra sagittis mauris. Sed in interdum purus. Praesent scelerisque nibh eget sem euismod, ut imperdiet mi venenatis. Vivamus pulvinar orci sed dapibus auctor. Nulla facilisi. Vestibulum tincidunt erat nec porttitor egestas. Mauris quis risus ante. Nulla facilisi. + +Aliquam ullamcorper ornare lobortis. Phasellus quis sem et ipsum mollis malesuada sed in ex. Ut aliquam ex eget metus finibus maximus. Proin suscipit mauris eu nibh lacinia, quis feugiat dui dapibus. Nam sed libero est. Aenean vulputate orci sit amet diam faucibus, eu sagittis sapien volutpat. Nam imperdiet felis turpis, at pretium odio pulvinar in. Sed vestibulum id eros nec ultricies. Sed quis aliquam tortor, vitae ullamcorper tellus. Donec egestas laoreet eros, id suscipit est rutrum nec. Sed auctor nulla eget metus aliquam, ut condimentum enim elementum. + +Aliquam suscipit non turpis sit amet bibendum. Fusce velit ligula, euismod et maximus at, luctus sed neque. Quisque pretium, nisl at ullamcorper finibus, lectus leo mattis sapien, vel euismod mauris diam ullamcorper ex. Nulla ut risus finibus, lacinia ligula at, auctor erat. Mauris consectetur sagittis ligula vel dapibus. Nullam libero libero, lobortis aliquam libero vel, venenatis ultricies leo. Duis porttitor, nibh congue fermentum posuere, erat libero pulvinar tortor, a pellentesque nunc ipsum vel sem. Nullam volutpat, eros sit amet facilisis consectetur, ipsum est vehicula massa, non vestibulum neque elit in mauris. Nunc hendrerit ipsum non enim bibendum, vitae rhoncus mi egestas. Etiam ullamcorper massa vel nisl sagittis, nec bibendum arcu malesuada. Aenean aliquet turpis justo, a consectetur arcu mollis convallis. Etiam tellus ipsum, ultricies vitae lorem et, ornare facilisis orci. Praesent fringilla justo urna, vel mollis neque pulvinar vestibulum. + +Donec non iaculis erat. Aliquam et mi sed nunc pulvinar ultricies in ut ipsum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Praesent feugiat lacus ac dignissim semper. Phasellus vitae quam nisi. Morbi vel diam ultricies risus lobortis ornare. Fusce maximus et ligula quis iaculis. Sed congue ex eget felis convallis, sit amet hendrerit elit tempor. Donec vehicula blandit ante eget commodo. Vestibulum eleifend diam at feugiat euismod. Etiam magna tellus, dignissim eget fermentum vel, vestibulum vitae mauris. Nam accumsan et erat id sagittis. Donec lacinia, odio ut ornare ultricies, dolor velit accumsan tortor, non finibus erat tellus quis ligula. Nunc quis metus in leo volutpat ornare vulputate eu nisl. + +Donec quis viverra ex. Nullam id feugiat mauris, eu fringilla nulla. Vestibulum id maximus elit. Cras elementum elit sed felis lobortis, eget sagittis nisi hendrerit. Vivamus vitae elit neque. Donec vulputate lacus ut libero ultrices accumsan. Vivamus accumsan nulla orci, in dignissim est laoreet sagittis. Proin at commodo velit. Curabitur in velit felis. Aliquam erat volutpat. Sed consequat, nulla et cursus sodales, nisi lacus mattis risus, quis eleifend erat ex nec turpis. Sed suscipit ultrices lorem in hendrerit. + +Morbi vitae lacus nec libero ornare tempus eu et diam. Suspendisse magna ipsum, fermentum vel odio quis, molestie aliquam urna. Fusce mollis turpis a eros accumsan porttitor. Pellentesque rhoncus dolor sit amet magna rutrum, et dapibus justo tempor. Sed purus nisi, maximus vitae fringilla eu, molestie nec urna. Fusce malesuada finibus pretium. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec sed aliquet eros. Pellentesque luctus diam ante, eget euismod nisl aliquet eu. Sed accumsan elit purus, tempor varius ligula tempus nec. Curabitur ornare leo suscipit suscipit fermentum. Morbi eget nulla est. Maecenas faucibus interdum tristique. + +Etiam ut elit eros. Nulla pharetra suscipit molestie. Nulla facilisis bibendum nisl non molestie. Curabitur turpis lectus, facilisis vel diam non, vulputate ultrices mauris. Aenean placerat aliquam convallis. Suspendisse sed scelerisque tellus. Vivamus lacinia neque eget risus cursus suscipit. Proin consequat dolor vel neque tempor, eu aliquam sem scelerisque. Duis non eros a purus malesuada pharetra non et nulla. Suspendisse potenti. Mauris libero eros, finibus vel nulla id, sagittis dapibus ante. Proin iaculis sed nunc et cursus. + +Quisque accumsan lorem sit amet lorem aliquet euismod. Curabitur fermentum rutrum posuere. Etiam ultricies, sem id pellentesque suscipit, urna magna lacinia eros, quis efficitur risus nisl at lacus. Nulla quis lacus tortor. Mauris placerat ex in dolor tincidunt, vel aliquet nisi pretium. Cras iaculis risus vitae pellentesque aliquet. Quisque a enim imperdiet, ullamcorper arcu vitae, rutrum risus. Nullam consectetur libero at felis fringilla, nec congue nibh dignissim. Nam et lobortis felis, eu pellentesque ligula. Aenean facilisis, ligula non imperdiet maximus, massa orci gravida sapien, at sagittis lacus nisl in lacus. Nulla quis mauris luctus, scelerisque felis consequat, tempus risus. Fusce auctor nisl non nulla luctus molestie. Maecenas sapien nisl, auctor non dolor et, iaculis scelerisque lorem. Suspendisse egestas enim aliquet, accumsan mauris nec, posuere quam. Nulla iaculis dui dui, sit amet vestibulum erat ultricies ac. + +Cras eget dolor erat. Proin at nisl ut leo consectetur ultricies vel ut arcu. Nulla in felis malesuada, ullamcorper tortor et, convallis massa. Nunc urna justo, ornare in nibh vitae, hendrerit condimentum libero. Etiam vitae libero in purus venenatis fringilla. Nullam velit nulla, consequat ut turpis non, egestas hendrerit nibh. Duis tortor turpis, interdum non ante ac, cursus accumsan lectus. Cras pharetra bibendum augue quis dictum. Sed euismod vestibulum justo. Proin porta lobortis purus. Duis venenatis diam tortor, sit amet condimentum eros rhoncus a. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc at magna nec diam lobortis efficitur sit amet ut lacus. Nulla quis orci tortor. Pellentesque tempus velit a odio finibus porta. + +Proin feugiat mauris a tellus scelerisque convallis. Maecenas libero magna, blandit nec ultrices id, congue vel mi. Aliquam lacinia, quam vel condimentum convallis, tortor turpis aliquam odio, sed blandit libero lacus et eros. In eleifend iaculis magna ac finibus. Praesent auctor facilisis tellus in congue. Sed molestie lobortis dictum. Nam quis dignissim augue, vel euismod lorem. Curabitur posuere dapibus luctus. Donec ultricies dictum lectus, quis blandit arcu commodo ac. Aenean tincidunt ligula in nunc imperdiet dignissim. Curabitur egestas sollicitudin sapien ut semper. Aenean nec dignissim lacus. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec aliquam dictum vehicula. Donec tortor est, volutpat non nisi nec, varius gravida ex. Nunc vel tristique nunc, vitae mattis nisi. Nunc nec luctus ex, vitae tincidunt lectus. In hac habitasse platea dictumst. Curabitur lobortis ex eget tincidunt tempor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut a vehicula mi. + +Fusce eu libero finibus, interdum nulla a, placerat neque. Cras bibendum tempor libero nec feugiat. Cras ut sodales eros. Proin viverra, massa sit amet viverra egestas, neque nisl porta ex, sit amet hendrerit libero ligula vel urna. Mauris suscipit lacus id justo rhoncus suscipit. Etiam vel libero tellus. Maecenas non diam molestie, condimentum tellus a, bibendum enim. Mauris aliquet imperdiet tellus, eget sagittis dolor. Sed blandit in neque et luctus. Cras elementum sagittis nunc, vel mollis lorem euismod et. Donec posuere at lacus eget suscipit. + +Nulla nunc mi, pretium non massa vel, tempor semper magna. Nunc a leo pulvinar, tincidunt nunc at, dignissim mi. Aliquam erat volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut viverra nulla a nisl finibus, at hendrerit ligula ullamcorper. Donec a lorem semper, tempor magna et, lobortis libero. Mauris id sapien leo. Donec dignissim, quam vitae porttitor dignissim, quam justo mattis dui, vel consequat odio elit quis orci. Etiam nec pretium neque, sit amet pretium orci. Duis ac tortor venenatis, feugiat purus non, feugiat nunc. Proin scelerisque nisl in turpis aliquam vulputate. + +Praesent sed est semper, fringilla lorem vitae, tincidunt nibh. Cras eros metus, auctor at mauris sit amet, sodales semper orci. Nunc a ornare ex. Curabitur bibendum arcu congue urna vulputate egestas. Vestibulum finibus id risus et accumsan. Aenean ut volutpat tellus. Aenean tincidunt malesuada urna sit amet vestibulum. Mauris vel tellus dictum, varius lacus quis, dictum arcu. + +Aenean quis metus eu erat feugiat cursus vel at ligula. Proin dapibus sodales urna, id euismod lectus tempus id. Pellentesque ex ligula, convallis et erat vel, vulputate condimentum nisl. Pellentesque pharetra nulla quis massa eleifend hendrerit. Praesent sed massa ipsum. Maecenas vehicula dolor massa, id sodales urna faucibus et. Mauris ac quam non massa tincidunt feugiat et at lacus. Fusce libero massa, vulputate vel scelerisque non, mollis in leo. Ut sit amet ultricies odio. Suspendisse in sapien viverra, facilisis purus ut, pretium libero. + +Vivamus tristique pharetra molestie. Nam a volutpat purus. Praesent consequat gravida nisi, ac blandit nisi suscipit ut. Quisque posuere, ligula a ultrices laoreet, ligula nunc vulputate libero, ut rutrum erat odio tincidunt justo. Sed vitae leo at leo fringilla bibendum. Vestibulum ut augue nec dolor auctor accumsan. Praesent laoreet id eros pulvinar commodo. Suspendisse potenti. Ut pharetra, mauris vitae blandit fringilla, odio ante tincidunt lorem, sit amet tempor metus diam ut turpis. + +Praesent quis egestas arcu. Nullam at porta arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi vulputate ligula malesuada ligula luctus, vulputate tempus erat bibendum. Nunc ullamcorper non lectus at euismod. Etiam nibh felis, tincidunt a metus vel, pellentesque rhoncus neque. Etiam at diam in erat luctus interdum. Nunc vel ipsum pulvinar, sollicitudin lacus ac, tempus urna. Etiam vel lacinia sapien. Pellentesque sagittis velit vel mi efficitur iaculis. Integer euismod sit amet urna in sagittis. Cras eleifend ut nibh in facilisis. Donec et lacus vitae nunc placerat sodales. Nulla sed hendrerit ligula, at dapibus sapien. + +Praesent at iaculis ex. Curabitur est purus, cursus a faucibus quis, dictum id velit. Donec dignissim fringilla viverra. Nunc mauris felis, laoreet sit amet sagittis at, vestibulum in libero. Maecenas quis orci turpis. Quisque ut nibh vitae magna mollis consequat id at mauris. Aliquam eu odio eget nulla bibendum sodales. Quisque vel orci eleifend nisi pretium lacinia. Suspendisse eget risus eget mi volutpat molestie eget quis lacus. Duis nisi libero, tincidunt nec nulla id, faucibus cursus felis. + +Donec tempor eget risus pellentesque molestie. Phasellus porta neque vel arcu egestas, nec blandit velit fringilla. Nullam porta faucibus justo vitae laoreet. Pellentesque viverra id nunc eu varius. Nulla pulvinar lobortis iaculis. Etiam vestibulum odio nec velit tristique, a tristique nisi mattis. In sed fringilla orci, vitae efficitur odio. Quisque dui odio, ornare eget velit at, lacinia consequat libero. Quisque lectus nulla, aliquet eu leo in, porta rutrum diam. Donec nec mattis neque. Nam rutrum, odio ac eleifend bibendum, dolor arcu rutrum neque, eget porta elit tellus a lacus. Sed massa metus, sollicitudin et sapien eu, finibus tempus orci. Proin et sapien sit amet erat molestie interdum. In quis rutrum velit, faucibus ultrices tellus. + +Sed sagittis sed justo eget tincidunt. Maecenas ut leo sagittis, feugiat magna et, viverra velit. Maecenas ex arcu, feugiat at consequat vitae, auctor eu massa. Integer egestas, enim vitae maximus convallis, est lectus pretium mauris, ac posuere lectus nisl quis quam. Aliquam tempus laoreet mi, vitae dapibus dolor varius dapibus. Suspendisse potenti. Donec sit amet purus nec libero dapibus tristique. Pellentesque viverra bibendum ligula. Donec sed felis et ex lobortis laoreet. Phasellus a fringilla libero, vitae malesuada nulla. Pellentesque blandit mattis lacus, et blandit tortor laoreet consequat. Suspendisse libero nunc, viverra sed fermentum in, accumsan egestas arcu. Proin in placerat elit. Sed interdum imperdiet malesuada. Suspendisse aliquet quis mauris eget sollicitudin. + +Vivamus accumsan tellus non erat volutpat, quis dictum dolor feugiat. Praesent rutrum nunc ac est mollis cursus. Fusce semper volutpat dui ut egestas. Curabitur sit amet posuere massa. Cras tincidunt nulla et mi mollis imperdiet. Suspendisse scelerisque ex id sodales vulputate. In nunc augue, pharetra in placerat eu, mattis id tellus. Vivamus cursus efficitur vehicula. Nulla aliquet vehicula aliquet. + +Sed cursus tellus sed porta pulvinar. Sed vitae nisi neque. Nullam aliquet, lorem et efficitur scelerisque, arcu diam aliquam felis, sed pulvinar lorem odio et turpis. Praesent convallis pulvinar turpis eu iaculis. Aliquam nec gravida mi. Curabitur eu nibh tempor, blandit justo in, ultrices felis. Fusce placerat metus non mi sagittis rutrum. Morbi sed dui fringilla, sagittis mauris eget, imperdiet nunc. Phasellus hendrerit sem elit, id hendrerit libero auctor sit amet. Integer sodales elit sit amet consequat cursus. + +Nam semper est eget nunc mollis, in pellentesque lectus fringilla. In finibus vel diam id semper. Nunc mattis quis erat eu consectetur. In hac habitasse platea dictumst. Nullam et ipsum vestibulum ex pulvinar ultricies sit amet id velit. Aenean suscipit mi tortor, a lobortis magna viverra non. Nulla condimentum aliquet ante et ullamcorper. Pellentesque porttitor arcu a posuere tempus. Aenean lacus quam, imperdiet eu justo vitae, pretium efficitur ex. Duis id purus id magna rhoncus ultrices id eu risus. Nunc dignissim et libero id dictum. + +Quisque a tincidunt neque. Phasellus commodo mi sit amet tempor fringilla. Ut rhoncus, neque non porttitor elementum, libero nulla egestas augue, sed fringilla sapien felis ac velit. Phasellus viverra rhoncus mollis. Nam ullamcorper leo vel erat laoreet luctus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus semper a metus a cursus. Nulla sed orci egestas, efficitur purus ac, malesuada tellus. Aenean rutrum velit at tellus fermentum mollis. Aliquam eleifend euismod metus. + +In hac habitasse platea dictumst. Vestibulum volutpat neque vitae porttitor laoreet. Nam at tellus consequat, sodales quam in, pulvinar arcu. Maecenas varius convallis diam, ac lobortis tellus pellentesque quis. Maecenas eget augue massa. Nullam volutpat nibh ac justo rhoncus, ut iaculis tellus rutrum. Fusce efficitur efficitur libero quis condimentum. Curabitur congue neque non tincidunt tristique. Fusce eget tempor ex, at pellentesque odio. Praesent luctus dictum vestibulum. Etiam non orci nunc. Vivamus vitae laoreet purus, a lobortis velit. Curabitur tincidunt purus ac lectus elementum pellentesque. Quisque sed tincidunt est. + +Sed vel ultrices massa, vitae ultricies justo. Cras finibus mauris nec lacus tempus dignissim. Cras faucibus maximus velit, eget faucibus orci luctus vehicula. Nulla massa nunc, porta ac consequat eget, rhoncus non tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce sed maximus metus, vel imperdiet ipsum. Ut scelerisque lectus at blandit porttitor. Ut vulputate nunc pharetra, aliquet sapien ac, sollicitudin sapien. Aenean eget ante lorem. Nam accumsan venenatis tellus id dignissim. + +Curabitur fringilla, magna non maximus dapibus, nulla sapien vestibulum lectus, sit amet semper dolor neque vitae nisl. Nunc ultrices vehicula augue sed iaculis. Maecenas nec diam mollis, suscipit orci et, vestibulum ante. Pellentesque eu nisl tortor. Nunc eleifend, lacus quis volutpat volutpat, nisi mi molestie sem, quis mollis ipsum libero a tellus. Ut viverra dolor mattis convallis interdum. Sed tempus nisl at nunc scelerisque aliquet. Quisque tempor tempor lorem id feugiat. Nullam blandit lectus velit, vitae porta lacus tincidunt a. Vivamus sit amet arcu ultrices, tincidunt mi quis, viverra quam. Aenean fringilla libero elementum lorem semper, quis pulvinar eros gravida. Nullam sodales blandit mauris, sed fermentum velit fermentum sit amet. Donec malesuada mauris in augue sodales vulputate. Vestibulum gravida turpis id elit rhoncus dignissim. Integer non congue lorem, eu viverra orci. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at dolor magna. Aliquam consectetur erat augue, id iaculis velit pharetra ac. Integer rutrum venenatis dignissim. Integer non sodales elit. Curabitur ut magna ut nibh feugiat aliquam ac ut risus. Morbi nibh quam, aliquam id placerat nec, vestibulum eget velit. Suspendisse at dignissim quam. Vivamus aliquet sem sed nisl volutpat, ut cursus orci ultrices. Aliquam ultrices lacinia enim, vitae aliquet neque. + +Quisque scelerisque finibus diam in mattis. Cras cursus auctor velit. Aliquam sem leo, fermentum et maximus et, molestie a libero. Aenean justo elit, rutrum a ornare id, egestas eget enim. Aenean auctor tristique erat. Curabitur condimentum libero lacus, nec consequat orci vestibulum sed. Fusce elit ligula, blandit vitae sapien vitae, dictum ultrices risus. Nam laoreet suscipit sapien, at interdum velit faucibus sit amet. Duis quis metus egestas lectus elementum posuere non nec libero. Aliquam a dolor bibendum, facilisis nunc a, maximus diam. Vestibulum suscipit tristique magna, non dignissim turpis sodales sed. Nunc ornare, velit ac facilisis fringilla, dolor mi consectetur lorem, vitae finibus erat justo suscipit urna. Maecenas sit amet eros erat. Nunc non arcu ornare, suscipit lorem eget, sodales mauris. Aliquam tincidunt, quam nec mollis lacinia, nisi orci fermentum libero, consequat eleifend lectus quam et sapien. Vestibulum a quam urna. + +Cras arcu leo, euismod ac ullamcorper at, faucibus sed massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus porttitor velit in enim interdum, non commodo metus ornare. Morbi vel lorem quis nisl luctus tristique quis vitae nisl. Suspendisse condimentum tortor enim, nec eleifend ipsum euismod et. Sed gravida quam ut tristique lacinia. Mauris eu interdum ipsum, ac ultrices odio. Nullam auctor tellus a risus porttitor vehicula. Nulla blandit euismod dictum. In pharetra, enim iaculis pulvinar interdum, dui nunc placerat nunc, sit amet pretium lectus nulla vitae quam. Phasellus quis enim sollicitudin, varius nulla id, ornare purus. Donec quam lacus, vestibulum quis nunc ac, mollis dictum nisi. Cras ut mollis elit. Maecenas ultrices ligula at risus faucibus scelerisque. Etiam vitae porttitor purus. Curabitur blandit lectus urna, ut hendrerit tortor feugiat ut. + +Phasellus fringilla, sapien pellentesque commodo pharetra, ante libero aliquam tellus, ut consectetur augue libero a sapien. Maecenas blandit luctus nisl eget aliquet. Maecenas vitae porta dolor, faucibus laoreet sapien. Suspendisse lobortis, ipsum sed vehicula aliquam, elit purus scelerisque dui, rutrum consectetur diam odio et lorem. In nec lacinia metus. Donec viverra libero est, vel bibendum erat condimentum quis. Donec feugiat purus leo. In laoreet vitae felis a porttitor. Mauris ullamcorper, lacus id condimentum suscipit, neque magna pellentesque arcu, eget cursus neque tellus id metus. Curabitur volutpat ac orci vel ultricies. + +Sed ut finibus erat. Sed diam purus, varius non tincidunt quis, ultrices sit amet ipsum. Donec et egestas nulla. Suspendisse placerat nisi at dui laoreet iaculis. Aliquam aliquet leo at augue faucibus molestie. Nullam lacus augue, hendrerit sed nisi eu, faucibus porta est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam ut leo aliquet sem fermentum rutrum quis ac justo. Integer placerat aliquam nisl ut sagittis. Proin erat orci, lobortis et sem eget, eleifend fringilla augue. Mauris varius laoreet arcu, sed tincidunt felis. Pellentesque venenatis lorem odio, id pulvinar velit molestie feugiat. Donec mattis lacus sed eleifend pulvinar. + +Sed condimentum ex in tincidunt hendrerit. Etiam eget risus lacinia, euismod nibh eu, pellentesque quam. Proin elit eros, convallis id mauris ac, bibendum ultrices lectus. Morbi venenatis, purus id fermentum consequat, nunc libero tincidunt ligula, non dictum ligula orci nec quam. Nulla nec ultrices lorem. Aenean maximus augue vel dictum pharetra. Etiam turpis urna, pellentesque quis malesuada eu, molestie faucibus felis. + +Vestibulum pharetra augue ut quam blandit congue in nec risus. Proin eu nibh eu dui eleifend porta vitae id lectus. Proin lacus nibh, lobortis sed ligula vitae, interdum lobortis erat. Suspendisse potenti. In sollicitudin quis sapien ut aliquet. Mauris ac nulla arcu. Fusce tristique justo quis lectus mollis, eu volutpat lectus finibus. Vivamus venenatis facilisis ex ut vestibulum. + +Etiam varius lobortis purus, in hendrerit elit tristique at. In tempus, augue vestibulum fermentum gravida, ligula tellus vulputate arcu, eu molestie ex sapien at purus. Vestibulum nec egestas metus. Duis pulvinar quam nec consequat interdum. Aenean non dapibus lacus. Aliquam sit amet aliquet nulla. Sed venenatis volutpat purus nec convallis. Phasellus aliquet semper sodales. Cras risus sapien, condimentum auctor urna a, pulvinar ornare nisl. Sed tincidunt felis elit, ut elementum est bibendum ac. Morbi interdum justo vel dui faucibus condimentum. + +Sed convallis eu sem at tincidunt. Nullam at auctor est, et ullamcorper ipsum. Pellentesque eget ante ante. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer euismod, sapien sed dapibus ornare, nibh enim maximus lacus, lacinia placerat urna quam quis felis. Morbi accumsan id nisl ut condimentum. Donec bibendum nisi est, sed volutpat lorem rhoncus in. Vestibulum ac lacinia nunc, eget volutpat magna. Integer aliquam pharetra ipsum, id placerat nunc volutpat quis. Etiam urna diam, rhoncus sit amet varius vel, euismod vel sem. Nullam vel molestie urna. Vivamus ornare erat at venenatis euismod. Suspendisse potenti. Fusce diam justo, tincidunt vel sem at, commodo faucibus nisl. Duis gravida efficitur diam, vel sagittis erat pulvinar ut. + +Quisque vel pharetra felis. Duis efficitur tortor dolor, vitae porttitor erat fermentum sed. Sed eu mi purus. Etiam dignissim tortor eu tempus molestie. Aenean pretium erat enim, in hendrerit ante hendrerit at. Sed ut risus vel nunc venenatis ultricies quis in lacus. Pellentesque vitae purus euismod, placerat risus non, ullamcorper augue. Quisque varius quam ligula, nec aliquet ex faucibus vitae. Quisque rhoncus sit amet leo tincidunt mattis. Cras id mauris eget purus pretium gravida sit amet eu augue. Aliquam dapibus odio augue, id lacinia velit pulvinar eu. + +Mauris fringilla, tellus nec pharetra iaculis, neque nisi ultrices massa, et tincidunt sem dui sed mi. Curabitur erat lorem, venenatis quis tempus lacinia, tempus sit amet nunc. Aliquam at neque ac metus commodo dictum quis vitae justo. Phasellus eget lacus tempus, blandit lorem vel, rutrum est. Aenean pharetra sem ut augue lobortis dignissim. Sed rhoncus at nulla id ultrices. Cras id condimentum felis. In suscipit luctus vulputate. Donec tincidunt lacus nec enim tincidunt sollicitudin ut quis enim. Nam at libero urna. Praesent sit amet massa vitae massa ullamcorper vehicula. + +Nullam bibendum augue ut turpis condimentum bibendum. Proin sit amet urna hendrerit, sodales tortor a, lobortis lectus. Integer sagittis velit turpis, et tincidunt nisi commodo eget. Duis tincidunt elit finibus accumsan cursus. Aenean dignissim scelerisque felis vel lacinia. Nunc lacinia maximus luctus. In hac habitasse platea dictumst. Vestibulum eget urna et enim tempor tempor. Nam feugiat, felis vel vestibulum tempus, orci justo viverra diam, id dapibus lorem justo in ligula. + +Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In ac pellentesque sem. Vestibulum lacinia magna dui, eu lacinia augue placerat et. Maecenas pulvinar congue est. Pellentesque commodo dui non pulvinar scelerisque. Etiam interdum est posuere sem bibendum, ac commodo magna dictum. Cras ipsum turpis, rhoncus nec posuere vitae, laoreet a arcu. Integer ac massa sit amet enim placerat lacinia sed ultrices arcu. Suspendisse sem nibh, luctus sit amet volutpat in, pellentesque eu metus. Ut gravida neque eget mi accumsan tempus. Nam sit amet aliquet nibh. + +Pellentesque a purus cursus nulla hendrerit congue quis et odio. Aenean hendrerit, leo ullamcorper sagittis hendrerit, erat dui molestie quam, sed condimentum lacus risus sed tellus. Morbi a dapibus lectus, ut feugiat ex. Phasellus pretium quam et sapien mollis, vel iaculis dui dignissim. Sed ullamcorper est turpis, a viverra lorem consectetur in. Aenean aliquet nibh non cursus rutrum. Suspendisse at tristique urna, id lobortis urna. In hac habitasse platea dictumst. Phasellus libero velit, rutrum sed tellus nec, dapibus tincidunt ligula. Quisque vel dui venenatis, consequat nisl ut, lacinia ipsum. Phasellus vitae magna pellentesque, lobortis est id, faucibus quam. Nam eleifend faucibus dui vel pellentesque. + +Etiam ut est non lacus tincidunt interdum. Maecenas sed massa urna. Quisque ut nibh tortor. Pellentesque felis ipsum, tempor finibus ipsum et, euismod pretium metus. Donec sit amet est ipsum. Quisque rhoncus justo non finibus elementum. Nulla nec lectus ac tortor placerat fringilla. Phasellus ac ultrices nunc, eu efficitur nisl. Nulla rhoncus nunc vitae ante dictum tincidunt. Nunc ultrices, massa sit amet malesuada dignissim, lectus lacus consequat sapien, non eleifend metus sem in eros. Phasellus mauris ante, dictum sit amet suscipit ac, rhoncus eget nisi. Phasellus at orci mollis, imperdiet neque eget, faucibus nulla. In at purus massa. Pellentesque quis rutrum lectus. + +Integer eu faucibus turpis, sit amet mollis massa. Vestibulum id nulla commodo, rutrum ipsum sed, semper ante. Phasellus condimentum orci nec nibh convallis, ac maximus orci ullamcorper. Maecenas vitae sollicitudin mi. Integer et finibus lectus, et condimentum ligula. Donec elementum tristique quam vitae dapibus. Morbi euismod ipsum in tristique ullamcorper. + +Duis fermentum non enim eu auctor. Quisque lacinia nibh vehicula nibh posuere, eu volutpat turpis facilisis. Ut ac faucibus nulla. Sed eleifend quis ex et pellentesque. Vestibulum sollicitudin in libero id fringilla. Phasellus dignissim purus consequat, condimentum dui sit amet, condimentum ante. Pellentesque ac consectetur massa, quis sagittis est. Nulla maximus tristique risus accumsan convallis. Curabitur imperdiet ac lacus a ultrices. Nulla facilisi. Sed quis quam quis lectus placerat lobortis vel sed turpis. In mollis dui id neque iaculis, ut aliquet tellus malesuada. Proin at luctus odio, vel blandit sapien. Praesent dignissim tortor vehicula libero fringilla, nec ultrices erat suscipit. Maecenas scelerisque purus in dapibus fermentum. + +Curabitur magna odio, mattis in tortor ut, porttitor congue est. Vestibulum mollis lacinia elementum. Fusce maximus erat vitae nunc rutrum lobortis. Integer ligula eros, auctor vel elit non, posuere luctus lacus. Maecenas quis auctor massa. Ut ipsum lacus, efficitur posuere euismod et, hendrerit efficitur est. Phasellus fringilla, quam id tincidunt pretium, nunc dui sollicitudin orci, eu dignissim nisi metus ut magna. Integer lobortis interdum dolor, non bibendum purus posuere et. Donec non lectus aliquet, pretium dolor eu, cursus massa. Sed ut dui sapien. In sed vestibulum massa. Pellentesque blandit, dui non sodales vehicula, orci metus mollis nunc, non pharetra ex tellus ac est. Mauris sagittis metus et fermentum pretium. Nulla facilisi. Quisque quis ante ut nulla placerat mattis ut quis nisi. + +Sed quis nulla ligula. Quisque dignissim ligula urna, sed aliquam purus semper at. Suspendisse potenti. Nunc massa lectus, pharetra vehicula arcu bibendum, imperdiet sodales ipsum. Nam ac sapien diam. Mauris iaculis fringilla mattis. Pellentesque tempus eros sit amet justo volutpat mollis. Phasellus ac turpis ipsum. Morbi vel ante elit. Aenean posuere quam consequat velit varius suscipit. Donec tempor quam ut nibh cursus efficitur. + +Morbi molestie dolor nec sem egestas suscipit. Etiam placerat pharetra lectus, et ullamcorper risus tristique in. Sed faucibus ullamcorper lectus eget fringilla. Maecenas malesuada hendrerit congue. Sed eget neque a erat placerat tincidunt. Aliquam vitae dignissim turpis. Fusce at placerat magna, a laoreet lectus. Maecenas a purus nec diam gravida fringilla. Nam malesuada euismod ante non vehicula. In faucibus bibendum leo, faucibus posuere nisl pretium quis. Fusce finibus bibendum finibus. Vestibulum eu justo maximus, hendrerit diam nec, dignissim sapien. Aenean dolor lacus, malesuada quis vestibulum ac, venenatis ac ipsum. Cras a est id nunc finibus facilisis. Cras lacinia neque et interdum vehicula. Suspendisse vulputate tellus elit, eget tempor dui finibus vel. + +Cras sed pretium odio. Proin hendrerit elementum felis in tincidunt. Nam sed turpis vel justo molestie accumsan condimentum eu nunc. Praesent lobortis euismod rhoncus. Nulla vitae euismod nibh, quis mattis mi. Fusce ultrices placerat porttitor. Duis sem ipsum, pellentesque sit amet odio a, molestie vulputate mauris. + +Duis blandit mollis ligula, sit amet mattis ligula finibus sit amet. Nunc a leo molestie, placerat diam et, vestibulum leo. Suspendisse facilisis neque purus, nec pellentesque ligula fermentum nec. Aenean malesuada mauris lorem, eu blandit arcu pulvinar quis. Duis laoreet urna lacus, non maximus arcu rutrum ultricies. Nulla augue dolor, suscipit eu mollis eu, aliquam condimentum diam. Ut semper orci luctus, pharetra turpis at, euismod mi. Nulla leo diam, finibus sit amet purus sed, maximus dictum lorem. Integer eu mi id turpis laoreet rhoncus. + +Integer a mauris tincidunt, finibus orci ut, pretium mauris. Nulla molestie nunc mi, id finibus lorem elementum sed. Proin quis laoreet ante. Integer nulla augue, commodo id molestie quis, rutrum ut turpis. Suspendisse et tortor turpis. Sed ut pharetra massa. Pellentesque elementum blandit sem, ut elementum tellus egestas a. Fusce eu purus nibh. + +Cras dignissim ligula scelerisque magna faucibus ullamcorper. Proin at condimentum risus, auctor malesuada quam. Nullam interdum interdum egestas. Nulla aliquam nisi vitae felis mollis dictum. Suspendisse dapibus consectetur tortor. Ut ut nisi non sem bibendum tincidunt. Vivamus suscipit leo quis gravida dignissim. + +Aliquam interdum, leo id vehicula mollis, eros eros rhoncus diam, non mollis ligula mi eu mauris. Sed ultrices vel velit sollicitudin tincidunt. Nunc auctor metus at ligula gravida elementum. Praesent interdum eu elit et mollis. Duis egestas quam sit amet velit dignissim consequat. Aliquam ac turpis nec nunc convallis sagittis. Fusce blandit, erat ac fringilla consectetur, dolor eros sodales leo, vel aliquet risus nisl et diam. Aliquam luctus felis vitae est eleifend euismod facilisis et lacus. Sed leo tellus, auctor eu arcu in, volutpat sagittis nisl. Pellentesque nisl ligula, placerat vel ullamcorper at, vulputate ac odio. Morbi ac faucibus orci, et tempus nulla. Proin rhoncus rutrum dolor, in venenatis mauris. Suspendisse a fermentum augue, non semper mi. Nunc eget pretium neque. Phasellus augue erat, feugiat ac aliquam congue, rutrum non sapien. Pellentesque ac diam gravida, consectetur felis at, ornare neque. + +Nullam interdum mattis sapien quis porttitor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus aliquet rutrum ipsum id euismod. Maecenas consectetur massa et mi porta viverra. Nunc quam nibh, dignissim vitae maximus et, ullamcorper nec lorem. Nunc vitae justo dapibus, luctus lacus vitae, pretium elit. Maecenas et efficitur leo. Curabitur mauris lectus, placerat quis vehicula vitae, auctor ut urna. Quisque rhoncus pharetra luctus. In hac habitasse platea dictumst. Integer sit amet metus nec eros malesuada aliquam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi hendrerit mi ac leo aliquam, sit amet ultricies libero commodo. Mauris dapibus purus metus, sit amet viverra nibh imperdiet et. Nullam porta nulla tellus, quis vehicula diam imperdiet non. Vivamus enim massa, bibendum in fermentum in, ultrices at ex. + +Suspendisse fermentum id nibh eget accumsan. Duis dapibus bibendum erat ut sollicitudin. Aliquam nec felis risus. Pellentesque rhoncus ligula id sem maximus mollis sed nec massa. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ipsum ipsum, sodales sed enim id, convallis faucibus eros. Donec ultricies dictum tincidunt. Cras vitae nibh arcu. Pellentesque cursus, sapien nec consequat fermentum, ipsum ante suscipit dui, imperdiet hendrerit est nisl eu massa. Quisque vitae sem ligula. Aenean iaculis metus ut mauris interdum laoreet. Vivamus sed gravida dolor. + +Morbi nulla metus, porttitor sed eros sit amet, efficitur efficitur est. In vel nisl urna. Ut aliquet tellus at congue convallis. Phasellus imperdiet lobortis sollicitudin. Integer sodales, sem eu ultricies pharetra, erat erat porttitor odio, eget dapibus libero ipsum eget velit. Phasellus gravida nulla nisl, eu pharetra mi auctor vel. Sed blandit pharetra velit, ut egestas libero placerat non. Aliquam a interdum quam. Proin at tortor nec dui sollicitudin tempus sed vestibulum elit. Nunc non sollicitudin velit. + +Aenean consequat diam velit, sed rutrum tortor faucibus dictum. Quisque at semper augue. Duis ut est eget mi ornare bibendum id et ligula. Phasellus consequat tortor non leo pulvinar posuere. Proin vestibulum eleifend felis, in hendrerit tortor sollicitudin eu. Phasellus hendrerit, lacus vel laoreet interdum, dui tortor consequat justo, commodo ultricies arcu felis vitae enim. Vivamus eu sapien at leo suscipit rutrum eu at justo. Aenean et dolor a libero ullamcorper posuere. Integer laoreet placerat nisi in vulputate. Mauris laoreet eget risus sed cursus. Donec scelerisque neque a libero eleifend hendrerit. Nulla varius condimentum nunc sit amet fermentum. Aliquam lorem ex, varius nec mollis ut, ultrices in neque. Morbi sit amet porta leo. Integer iaculis fermentum lacus in vestibulum. + +Ut gravida, tellus ut maximus ultrices, erat est venenatis nisl, vitae pretium massa ex ac magna. Sed non purus eget ligula aliquet volutpat non quis arcu. Nam aliquam tincidunt risus, sit amet fringilla sapien vulputate ut. Mauris luctus suscipit pellentesque. Nunc porttitor dapibus ex quis tempus. Ut ullamcorper metus a eros vulputate, vitae viverra lectus convallis. Mauris semper imperdiet augue quis tincidunt. Integer porta pretium magna, sed cursus sem scelerisque sollicitudin. Nam efficitur, nibh pretium eleifend vestibulum, purus diam posuere sem, in egestas mauris augue sit amet urna. + +Vestibulum tincidunt euismod massa in congue. Duis interdum metus non laoreet fringilla. Donec at ligula congue, tincidunt nunc non, scelerisque nunc. Donec bibendum magna non est scelerisque feugiat at nec neque. Ut orci tortor, tempus eget massa non, dignissim faucibus dolor. Nam odio risus, accumsan pretium neque eget, accumsan dignissim dui. In ut neque auctor, scelerisque tellus sed, ullamcorper nisi. Suspendisse varius cursus quam at hendrerit. Vivamus elit libero, sagittis vitae sem ac, vulputate iaculis ligula. + +Sed lobortis laoreet purus sit amet rutrum. Pellentesque feugiat non leo vel lacinia. Quisque feugiat nisl a orci bibendum vestibulum. In et sollicitudin urna. Morbi a arcu ac metus faucibus tempus. Nam eu imperdiet sapien, suscipit mattis tortor. Aenean blandit ipsum nisi, a eleifend ligula euismod at. Integer tincidunt pharetra felis, mollis placerat mauris hendrerit at. Curabitur convallis, est sit amet luctus volutpat, massa lacus cursus augue, sed eleifend magna quam et risus. Aliquam lobortis tincidunt metus vitae porttitor. Suspendisse potenti. Aenean ullamcorper, neque id commodo luctus, nulla nunc lobortis quam, id dapibus neque dui nec mauris. Etiam quis lorem quis elit commodo ornare. Ut pharetra purus ultricies enim ultrices efficitur. Proin vehicula tincidunt molestie. Mauris et placerat sem. + +Aliquam erat volutpat. Suspendisse velit turpis, posuere ac lacus eu, lacinia laoreet velit. Sed interdum felis neque, id blandit sem malesuada sit amet. Ut sagittis justo erat, efficitur semper orci tempor sed. Donec enim massa, posuere varius lectus egestas, pellentesque posuere mi. Cras tincidunt ut libero sed mattis. Suspendisse quis magna et tellus posuere interdum vel at purus. Pellentesque fringilla tristique neque, id aliquet tellus ultricies non. Duis ut tellus vel odio lobortis vulputate. + +Integer at magna ac erat convallis vestibulum. Sed lobortis porttitor mauris. Fusce varius lorem et volutpat pulvinar. Aenean ac vulputate lectus, vitae consequat velit. Suspendisse ex dui, varius ut risus ut, dictum scelerisque sem. Vivamus urna orci, volutpat ut convallis ac, venenatis vitae urna. In hac habitasse platea dictumst. Etiam eu purus arcu. Aenean vulputate leo urna, vel tristique dui sagittis euismod. Suspendisse non tellus efficitur ante rhoncus volutpat at et sapien. + +Sed dapibus accumsan porttitor. Phasellus facilisis lectus finibus ligula dignissim, id pulvinar lectus feugiat. Nullam egestas commodo nisi posuere aliquet. Morbi sit amet tortor sagittis, rutrum dui nec, dapibus sapien. Sed posuere tortor tortor, interdum auctor magna varius vitae. Vestibulum id sagittis augue. Curabitur fermentum arcu sem, eu condimentum quam rutrum non. Phasellus rutrum nibh quis lectus rhoncus pretium. Curabitur dictum interdum elit. Vestibulum maximus sodales imperdiet. Mauris auctor nec purus sed venenatis. In in urna purus. + +Duis placerat molestie suscipit. Morbi a elit id purus efficitur consequat. Nunc ac commodo turpis. Etiam sit amet lacus a ipsum tempus venenatis sed vel nibh. Duis elementum aliquam mi sed tristique. Morbi ligula tortor, semper ac est vel, lobortis maximus erat. Curabitur ipsum felis, laoreet vel condimentum eget, ullamcorper sit amet mauris. Nulla facilisi. Nam at purus sed mi egestas placerat vitae vel magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse at dignissim diam. Phasellus consectetur eget neque vel viverra. Donec sollicitudin mattis dolor vel malesuada. Vivamus vehicula leo neque, vitae fermentum leo posuere et. Praesent dui est, finibus sit amet tristique quis, pharetra vel nibh. + +Duis nulla leo, accumsan eu odio eget, sagittis semper orci. Quisque ullamcorper ligula quam, commodo porttitor mauris ullamcorper eu. Cras varius sagittis felis in aliquam. Duis sodales risus ac justo vehicula, nec mattis diam lacinia. Cras eget lectus ipsum. Ut commodo, enim vitae malesuada hendrerit, ex dolor egestas lectus, sit amet hendrerit metus diam nec est. Vestibulum tortor metus, lobortis sit amet ante eget, tempor molestie lacus. In molestie et urna et semper. Mauris mollis, sem non hendrerit condimentum, sapien nisi cursus est, non suscipit quam justo non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam enim est, porta ac feugiat vitae, rutrum in lorem. Duis vehicula tortor ut posuere maximus. + +Nullam vestibulum non tellus sed commodo. Quisque mattis elit sit amet sapien sollicitudin, ut condimentum nisl congue. Aenean sagittis massa vel elit faucibus fermentum. Donec tincidunt nisi nec nisl sodales pellentesque. Mauris congue congue ligula ut suscipit. Vivamus velit tortor, tempor et gravida eget, fermentum sit amet ante. Nullam fringilla, lorem at ultrices cursus, urna neque ornare dolor, eu lacinia orci enim sed nibh. Ut a ullamcorper lectus, id mattis purus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean maximus sollicitudin posuere. Nunc at augue lacus. Aenean efficitur leo sit amet lacinia efficitur. + +Quisque venenatis quam mi, in pharetra odio vulputate eu. In vel nisl pulvinar, pulvinar ligula ut, sodales risus. Sed efficitur lectus at vestibulum tincidunt. Vestibulum eu ullamcorper elit. Fusce vestibulum magna enim, et tempor lacus posuere vitae. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer leo elit, luctus nec mattis sit amet, sollicitudin in turpis. + +Proin convallis venenatis leo, vitae tristique erat iaculis nec. Nulla facilisi. Duis porttitor, sapien et bibendum vulputate, sem libero sodales lacus, non malesuada felis erat ut libero. Nam non felis semper, finibus est a, mattis mauris. Praesent nec eros quam. Nulla hendrerit, augue consectetur eleifend ultricies, purus mi condimentum nulla, eget dapibus est nunc sed libero. Nullam elementum dui erat, vitae luctus libero sollicitudin et. Nulla odio magna, placerat in augue eu, dapibus imperdiet odio. Suspendisse imperdiet metus sit amet rhoncus dapibus. Cras at enim et urna vehicula cursus eu a mauris. Integer magna ante, eleifend ac placerat vitae, porta at nisi. Cras eget malesuada orci. Curabitur nunc est, vulputate id viverra et, dignissim sed odio. Curabitur non mattis sem. Sed bibendum, turpis vitae vehicula faucibus, nunc quam ultricies lectus, vitae viverra felis turpis at libero. + +Nullam ut egestas ligula. Proin hendrerit justo a lectus commodo venenatis. Nulla facilisi. Ut cursus lorem quis est bibendum condimentum. Aenean in tristique odio. Fusce tempor hendrerit ipsum. Curabitur mollis felis justo, quis dapibus erat auctor vel. Sed augue lectus, finibus ut urna quis, ullamcorper vestibulum dui. Etiam molestie aliquam tempor. Integer mattis sollicitudin erat, et tristique elit varius vel. Mauris a ex justo. + +Nam eros est, imperdiet non volutpat rutrum, pellentesque accumsan ligula. Duis sit amet turpis metus. Aenean in rhoncus metus, ac fringilla ex. Suspendisse condimentum egestas purus, ut pharetra odio vulputate vel. Duis tincidunt massa a placerat ultrices. Mauris ultricies nibh sit amet condimentum malesuada. Duis tincidunt id ipsum sed congue. + +Praesent eu ex augue. Nullam in porta ligula. In tincidunt accumsan arcu, in pellentesque magna tristique in. Mauris eleifend libero ac nisl viverra faucibus. Nam sollicitudin dolor in commodo hendrerit. Cras at orci metus. Ut quis laoreet orci. Vivamus ultrices leo pellentesque tempor aliquet. Maecenas ut eros vitae purus placerat vestibulum. Etiam vitae gravida dolor, quis rhoncus diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. + +Suspendisse fringilla lacinia sagittis. Integer tincidunt consectetur tristique. Morbi non orci convallis, congue sapien quis, vulputate nunc. Donec a libero vel magna elementum facilisis non quis mi. Mauris posuere tellus non ipsum ultrices elementum. Vivamus massa velit, facilisis quis placerat aliquet, aliquet nec leo. Praesent a maximus sem. Sed neque elit, feugiat vel quam non, molestie sagittis nunc. Etiam luctus nunc ac mauris scelerisque, nec rhoncus lacus convallis. Nunc pharetra, nunc ac pulvinar aliquam, ex ipsum euismod augue, nec porttitor lacus turpis vitae neque. Fusce bibendum odio id tortor faucibus pellentesque. Sed ac porta nibh, eu gravida erat. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam quis ullamcorper felis. Nulla mattis sagittis ante ac tincidunt. Integer ac felis efficitur, viverra libero et, facilisis ligula. Suspendisse a metus a massa rhoncus posuere. Phasellus suscipit ligula ut lacus facilisis, ac pellentesque ex tempor. Quisque consectetur massa mi, ac molestie libero dictum quis. Proin porttitor ligula quis erat tincidunt venenatis. Proin congue nunc sed elit gravida, nec consectetur lectus sodales. Etiam tincidunt convallis ipsum at vestibulum. Quisque maximus enim et mauris porttitor, et molestie magna tristique. Morbi vitae metus elit. Maecenas sed volutpat turpis. Aliquam vitae dolor vestibulum, elementum purus eget, dapibus nibh. Nullam egestas dui ac rutrum semper. + +Etiam hendrerit est metus, et condimentum metus aliquam ac. Pellentesque id neque id ipsum rhoncus vulputate. Aliquam erat nisl, posuere sit amet ligula ac, fermentum blandit felis. Vivamus fermentum mi risus, non lacinia purus viverra id. Aenean ac sapien consequat, finibus mauris nec, porta sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed quis consectetur ex, dignissim bibendum nulla. Phasellus ac libero at quam vehicula euismod non eu leo. Phasellus a sapien augue. + +Maecenas ligula dui, bibendum vitae mauris et, auctor laoreet felis. Duis non libero a mi semper mattis. Quisque consequat luctus massa, quis tristique eros auctor feugiat. Maecenas sodales euismod neque vitae facilisis. Nullam laoreet imperdiet velit at pellentesque. Etiam massa odio, facilisis a consequat vitae, placerat vel magna. Nunc sagittis eros nec urna fringilla, pulvinar vestibulum nibh scelerisque. Sed magna metus, cursus eu consequat et, pharetra a est. Suspendisse elementum neque a dui malesuada lacinia. Donec sed ipsum volutpat, cursus urna id, ullamcorper arcu. Maecenas laoreet nisl eget velit egestas sollicitudin. Etiam nisl turpis, mollis id dignissim vitae, tristique vehicula ante. Maecenas eget placerat est, at rutrum augue. Vivamus faucibus lacinia ullamcorper. Sed pulvinar urna sodales ante sodales, at gravida leo dictum. + +Morbi maximus, quam a lobortis bibendum, enim felis varius elit, ac vehicula elit nisl ut lacus. Quisque ut arcu augue. Praesent id turpis quam. Sed sed arcu eros. Maecenas at cursus lorem, ac eleifend nisi. Fusce mattis felis at commodo pharetra. Praesent ac commodo ipsum. Quisque finibus et eros vitae tincidunt. In hac habitasse platea dictumst. Praesent purus ipsum, luctus lobortis ornare quis, auctor eget justo. Nam vel enim sollicitudin, faucibus tortor eu, sagittis eros. Ut nec consectetur erat. Donec ultricies malesuada ligula, a hendrerit sapien volutpat in. Maecenas sed enim vitae sapien pulvinar faucibus. + +Proin semper nunc nibh, non consequat neque ullamcorper vel. Maecenas lobortis sagittis blandit. Aenean et arcu ultricies turpis malesuada malesuada. Ut quam ex, laoreet ut blandit cursus, feugiat vitae dolor. Etiam ex lacus, scelerisque vel erat vel, efficitur tincidunt magna. Morbi tristique lacinia dolor, in egestas magna ultrices vitae. Integer ultrices leo ac tempus venenatis. Praesent ac porta tortor. Vivamus ornare blandit tristique. Nulla rutrum finibus pellentesque. In non dui elementum, fermentum ipsum vel, varius magna. Pellentesque euismod tortor risus, ac pellentesque nisl faucibus eget. + +Vivamus eu enim purus. Cras ultrices rutrum egestas. Sed mollis erat nibh, at posuere nisl luctus nec. Nunc vulputate, sapien id auctor molestie, nisi diam tristique ante, non convallis tellus nibh at orci. Morbi a posuere purus, in ullamcorper ligula. Etiam elementum sit amet dui imperdiet iaculis. Proin vitae tincidunt ipsum, sit amet placerat lectus. Curabitur commodo sapien quam, et accumsan lectus fringilla non. Nullam eget accumsan enim, ac pharetra mauris. Sed quis tristique velit, vitae commodo nisi. Duis turpis dui, maximus ut risus at, finibus consequat nunc. Maecenas sed est accumsan, aliquet diam in, facilisis risus. Curabitur vehicula rutrum auctor. Nam iaculis risus pulvinar maximus viverra. Nulla vel augue et ex sagittis blandit. + +Ut sem nulla, porta ac ante ac, posuere laoreet eros. Donec sodales posuere justo a auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras mollis at orci hendrerit porta. Nullam sodales tortor tortor, non lacinia diam finibus id. Duis libero orci, suscipit ac odio et, dictum consequat ipsum. Pellentesque eu ligula sagittis, volutpat eros at, lacinia lorem. Cras euismod tellus in iaculis tempor. Quisque accumsan, magna a congue venenatis, ante ipsum aliquam lectus, at egestas enim nunc at justo. Quisque sem purus, viverra ut tristique ut, maximus id enim. Etiam quis placerat sem. In sollicitudin, lacus eu rutrum mollis, nulla eros luctus elit, vel dapibus urna purus nec urna. Phasellus egestas massa quam, ac molestie erat hendrerit a. Praesent ultrices neque ut turpis molestie auctor. Etiam molestie placerat purus, et euismod erat aliquam in. Morbi id suscipit justo. + +Proin est ante, consequat at varius a, mattis quis felis. Sed accumsan nibh sit amet ipsum elementum posuere. Vestibulum bibendum id diam sit amet gravida. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi nec dolor vel ipsum dignissim hendrerit vel non ipsum. Praesent facilisis orci quis elit auctor lobortis. Phasellus cursus risus lectus, vel lobortis libero dapibus in. Quisque tristique tempus leo a pulvinar. Pellentesque a magna tincidunt, pellentesque massa nec, laoreet orci. Morbi congue ornare dolor quis commodo. Phasellus massa nisi, tincidunt at eros dictum, hendrerit lobortis urna. Maecenas porta, magna id mattis molestie, nibh tellus lobortis sem, eget tincidunt ipsum quam eu turpis. + +Ut gravida orci risus, vel rutrum mauris vehicula id. Etiam bibendum, neque a placerat condimentum, ex orci imperdiet lectus, quis dapibus arcu lacus eget lectus. Sed consequat non mi sit amet venenatis. Fusce vestibulum erat libero, eget hendrerit risus vulputate sollicitudin. Integer sed eleifend felis. Donec commodo, sem eu mattis placerat, urna odio aliquam tellus, et laoreet justo tellus eget erat. Fusce sed suscipit tortor. Nam hendrerit nibh ac nunc auctor lacinia. Pellentesque placerat condimentum ipsum, eget semper tortor hendrerit vel. Nullam non urna eu lacus pellentesque congue ut id eros. + +Nunc finibus leo in rhoncus tristique. Sed eu ipsum nec nisl egestas faucibus eget a felis. Pellentesque vitae nisi in nulla accumsan fermentum. Sed venenatis feugiat eleifend. Fusce porttitor varius placerat. Aliquam aliquet lacus sit amet mattis mollis. Sed vel nulla quis dolor suscipit vehicula ac viverra lorem. Duis viverra ipsum eget nulla ullamcorper fermentum. Mauris tincidunt arcu quis quam fringilla ornare. Donec et iaculis tortor. Nam ultricies libero vel ipsum aliquet efficitur. Morbi eget dolor aliquam, tempus sapien eget, viverra ante. Donec varius mollis ex, sed efficitur purus euismod interdum. Quisque vel sapien non neque tincidunt semper. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Suspendisse sit amet purus leo. Fusce lectus lorem, aliquam ac nulla eget, imperdiet ornare eros. Nullam sem augue, varius in nisi non, sollicitudin pellentesque ante. Etiam eu odio condimentum, tempor libero et, egestas arcu. Cras pellentesque eleifend aliquet. Pellentesque non blandit ligula. Ut congue viverra rhoncus. Phasellus mattis mi ac eros placerat, eu feugiat tellus ultrices. Aenean mollis laoreet libero eu imperdiet. Cras sed pulvinar mi, ac vehicula ligula. Vestibulum sit amet ex massa. In a egestas eros. + +Mauris pretium ipsum risus, venenatis cursus ante imperdiet id. Praesent eu turpis nec risus feugiat maximus ullamcorper ac lectus. Integer placerat at mi vel dapibus. Vestibulum fermentum turpis sit amet turpis viverra, id aliquet diam suscipit. Nam nec ex sed ante ullamcorper pharetra quis sit amet risus. Sed ac faucibus velit, id feugiat nibh. Nullam eget ipsum ex. Vivamus tincidunt non nunc non faucibus. Quisque bibendum viverra facilisis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at nisi hendrerit quam suscipit egestas. Curabitur laoreet maximus ultricies. Duis ut tellus ac augue molestie dictum. + +Suspendisse rhoncus iaculis erat, ut ullamcorper est tristique eget. Donec auctor nec risus at gravida. Vivamus volutpat vulputate tellus, vel ultricies eros suscipit eget. Ut pulvinar id mi eu tempus. Morbi malesuada augue in dui varius, nec blandit neque vehicula. Donec ornare nec nisl in mollis. Morbi enim nisi, rhoncus nec est id, dapibus tempus urna. Ut id elit a felis vestibulum consectetur. Duis lectus quam, pharetra sit amet diam sed, posuere vestibulum erat. Fusce vitae maximus massa. Nullam id metus tempus, iaculis risus eu, lobortis urna. Quisque in congue urna. Pellentesque placerat neque in augue dapibus, non varius ex malesuada. Curabitur ut eleifend libero. Fusce vitae ligula luctus, fermentum enim vitae, ultrices erat. + +Sed viverra augue turpis, scelerisque egestas sapien mattis eu. Duis laoreet magna at ex pharetra dapibus. Praesent eget odio vel quam venenatis dictum. Nulla in sollicitudin dolor. Mauris lobortis nec eros vel rhoncus. Vestibulum porta viverra venenatis. Curabitur vel scelerisque quam, a egestas velit. Praesent volutpat tincidunt magna at laoreet. + +Cras nec lorem odio. Pellentesque quis dui urna. Praesent at tellus ac lectus scelerisque placerat nec eu risus. Vestibulum sit amet mattis ligula. Vivamus sed nisi at leo elementum accumsan at sit amet arcu. Aenean mattis tellus nec leo gravida, eget hendrerit nisl faucibus. Mauris pellentesque luctus condimentum. Maecenas pretium sapien nunc, eget commodo dolor maximus id. Mauris vestibulum accumsan massa a dictum. Phasellus interdum quam ligula, ut maximus diam blandit aliquam. Nunc vitae ex eu erat condimentum consectetur. Maecenas interdum condimentum volutpat. + +Donec et enim a libero rutrum laoreet. Praesent a condimentum sem, at tincidunt quam. In vel molestie risus. Sed urna dui, molestie vitae mollis laoreet, tempor quis lectus. Praesent vitae auctor est, et aliquet nunc. Curabitur vulputate blandit nulla, at gravida metus. Maecenas gravida dui eu iaculis tristique. Pellentesque posuere turpis nec auctor eleifend. Suspendisse bibendum diam eu tellus lobortis, et laoreet quam congue. In hac habitasse platea dictumst. Morbi dictum neque velit, eget rutrum eros ultrices sit amet. + +Phasellus fermentum risus pharetra consectetur bibendum. Donec magna tortor, lacinia vitae nibh quis, aliquet pretium lorem. Donec turpis nisi, pretium eu enim volutpat, mattis malesuada augue. Nullam vel tellus iaculis, sollicitudin elit eget, tincidunt lacus. Fusce elementum elementum felis et iaculis. Suspendisse porta eros nec neque malesuada, in malesuada ante sollicitudin. Vivamus bibendum viverra molestie. + +Integer feugiat, erat nec convallis aliquam, velit felis congue erat, molestie eleifend tellus erat in tellus. Nunc et justo purus. Donec egestas fermentum dui non feugiat. Quisque in sapien sagittis, gravida quam id, iaculis lectus. Cras sagittis rhoncus bibendum. Fusce quis metus in velit scelerisque tincidunt at non ipsum. Vivamus efficitur ante eu odio vulputate, vitae ultricies risus vehicula. Proin eget odio eu sem tincidunt feugiat vel id lorem. + +Vestibulum sit amet nulla dignissim, euismod mi in, fermentum tortor. Donec ut aliquet libero, lacinia accumsan velit. Donec et nulla quam. Nullam laoreet odio nec nunc imperdiet, a congue eros venenatis. Quisque nec tellus sit amet neque interdum posuere. Duis quis mi gravida, tincidunt diam convallis, ultricies augue. Mauris consequat risus non porttitor congue. Ut in ligula consequat, viverra nunc a, eleifend enim. Duis ligula urna, imperdiet nec facilisis et, ornare eu ex. Proin lobortis lectus a lobortis porttitor. Nulla leo metus, egestas eu libero sed, pretium faucibus felis. Vestibulum non sem tortor. Nam cursus est leo. Vivamus luctus enim odio, non interdum sem dapibus a. Aenean accumsan consequat lectus in imperdiet. + +Donec vehicula laoreet ipsum in posuere. Quisque vel quam imperdiet, sollicitudin nisi quis, suscipit velit. Morbi id sodales mauris. Curabitur tellus arcu, feugiat sed dui sit amet, sodales sagittis libero. Aenean vel suscipit metus, non placerat leo. Vestibulum quis nulla elit. Proin scelerisque non ante ut commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. + +Sed non urna dolor. Suspendisse convallis mi porta pulvinar ultrices. Suspendisse quam ipsum, hendrerit non scelerisque molestie, interdum dictum nunc. Morbi condimentum condimentum turpis eu luctus. Pellentesque sagittis sollicitudin odio, sed ultricies felis ornare sit amet. Sed ultrices ex leo, a tincidunt nisl gravida sed. Nullam ornare accumsan porta. Praesent consectetur id est nec sollicitudin. + +In hac habitasse platea dictumst. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed sed ultrices nibh. Duis accumsan suscipit eros, a dictum odio tempus sit amet. Aenean imperdiet erat ac lacus finibus, scelerisque cursus massa imperdiet. Mauris molestie risus ut lacinia posuere. Nulla et sodales purus. Maecenas orci erat, placerat in tristique quis, placerat in mi. + +Donec sollicitudin pellentesque odio in feugiat. Morbi eu dolor ut mauris congue sollicitudin. Aliquam erat volutpat. Nulla id varius dui. Curabitur finibus urna ante, consectetur interdum nisi volutpat a. Quisque quis mi tristique, consequat tellus eget, rutrum sapien. Vivamus vitae tellus vulputate, rutrum ex eu, vulputate sem. Suspendisse viverra lorem tellus, vel interdum orci gravida quis. Ut laoreet arcu at mi ullamcorper finibus. Duis porta sagittis vestibulum. Sed commodo nisl vitae urna sollicitudin, nec lacinia est sodales. Curabitur imperdiet sodales dui sed iaculis. Sed ac tellus maximus, eleifend quam sit amet, feugiat elit. Aenean viverra, dui at mattis varius, est odio vestibulum sapien, sit amet mollis libero massa nec velit. Etiam quis sodales justo. + +Ut ultricies, sem eget sodales feugiat, nunc arcu congue elit, ac tempor justo massa nec purus. Maecenas enim nunc, pharetra eget dictum sit amet, tempus pellentesque velit. Suspendisse venenatis ligula in nulla mattis, et imperdiet ex tincidunt. Etiam vulputate, tellus et ultrices suscipit, enim velit laoreet massa, vitae congue odio enim ac urna. Morbi quam lorem, iaculis ac varius sagittis, euismod quis dolor. In ut dui eu purus feugiat consectetur. Vestibulum cursus velit quis lacus pellentesque iaculis. Cras in risus sed mauris porta rutrum. Nulla facilisi. Nullam eu bibendum est, non pellentesque lectus. Sed imperdiet feugiat lorem, quis convallis ante auctor in. Maecenas justo magna, scelerisque sit amet tellus eget, varius elementum risus. Duis placerat et quam sed varius. + +Duis nec nibh vitae nibh dignissim mollis quis sed felis. Curabitur vitae quam placerat, venenatis purus ut, euismod nisl. Curabitur porttitor nibh eu pulvinar ullamcorper. Suspendisse posuere nec ipsum ac dapibus. Cras convallis consectetur urna. Phasellus a nibh in dolor lacinia posuere id eget augue. In eu pharetra lorem, vitae cursus lacus. Aliquam tincidunt nibh lectus. Aenean facilisis ultricies posuere. Sed ut placerat orci. Curabitur scelerisque gravida blandit. Maecenas placerat ligula eget suscipit fringilla. Mauris a tortor justo. Aliquam hendrerit semper mollis. Phasellus et tincidunt libero. Etiam vel quam libero. + +Quisque aliquet tempor ex. Ut ante sem, vehicula at enim vel, gravida porta elit. Etiam vitae lacus a neque lobortis consectetur. Mauris sed interdum odio. Mauris elementum ex blandit tempor cursus. Integer in enim in leo viverra elementum. Fusce consectetur metus et sem rutrum, mattis euismod diam semper. Nunc sed ipsum vel urna consequat vehicula. Donec cursus pretium lorem, vestibulum pretium felis commodo sit amet. Nam blandit felis enim, eget gravida ex faucibus a. In nec neque massa. Etiam laoreet posuere ipsum. Praesent volutpat nunc dolor, ac vulputate magna facilisis non. Aenean congue turpis vel lectus sollicitudin tristique. Sed nec consequat purus, non vehicula quam. Etiam ultricies, est ac dictum tincidunt, turpis turpis pretium massa, a vulputate libero justo at nibh. + +Aliquam erat volutpat. Cras ultrices augue ac sollicitudin lobortis. Curabitur et aliquet purus. Duis feugiat semper facilisis. Phasellus lobortis cursus velit, a sollicitudin tortor. Nam feugiat sapien non dapibus condimentum. Morbi at mi bibendum, commodo quam at, laoreet enim. Integer eu ultrices enim. Sed vestibulum eu urna ut dictum. Curabitur at mattis leo, sed cursus massa. Aliquam porttitor, felis quis fermentum porttitor, justo velit feugiat nulla, eget condimentum sem dui ut sapien. + +In fringilla elit eu orci aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut eget fringilla tellus. Curabitur fermentum, mi et condimentum suscipit, elit neque bibendum dui, et hendrerit nunc metus id ipsum. Morbi placerat mi in hendrerit congue. Ut feugiat mauris eget scelerisque viverra. Vivamus sit amet erat dictum, sagittis lectus nec, pulvinar lorem. Sed non enim ac dui sollicitudin aliquet. Quisque ut lacus dolor. Fusce hendrerit malesuada euismod. Nulla faucibus vel mauris eu mollis. Mauris est diam, fringilla ac arcu feugiat, efficitur volutpat turpis. Aliquam venenatis cursus massa sed porttitor. Ut ac finibus enim, in tincidunt sapien. + +Nunc faucibus semper turpis a lacinia. Phasellus gravida, libero vel pulvinar ornare, ex sem tincidunt lectus, sit amet convallis augue risus at tortor. Quisque sit amet ipsum id nulla posuere vestibulum. Pellentesque scelerisque mauris vel leo viverra sodales. Nulla viverra aliquam ex, ut rutrum enim fermentum venenatis. Aenean eget dapibus ex, eget faucibus metus. Vestibulum volutpat leo in diam semper, eget porta magna suscipit. Sed sit amet nulla blandit, aliquam dolor ac, gravida velit. Sed vel velit viverra, maximus est id, convallis justo. + +Curabitur nulla ante, vulputate at libero vel, ullamcorper rutrum nibh. Pellentesque porttitor eu mauris id mattis. Duis vulputate augue elit, eget interdum justo pretium vel. Maecenas eu vulputate arcu, eget posuere purus. Suspendisse viverra a velit dictum eleifend. Suspendisse vitae dapibus diam. Donec vehicula justo in ante interdum, eu luctus diam placerat. Vivamus convallis ipsum eu orci suscipit, sed fermentum enim euismod. Maecenas faucibus elit vitae ex ornare tristique. Donec vestibulum nec elit sit amet porttitor. Aenean tempor lectus eget tortor hendrerit luctus. Nullam interdum vitae lectus vel feugiat. Cras in risus non magna consectetur lobortis. Sed faucibus enim quis gravida convallis. + +Phasellus eget massa sit amet libero ultrices suscipit. Vivamus at risus sapien. Nam mollis nunc eget velit dictum maximus. Sed pellentesque, nunc ac fringilla lacinia, quam enim mattis ex, sed euismod tortor metus eu neque. Ut mattis nisl ut lectus rhoncus, sodales bibendum eros porta. Nulla porttitor enim nec diam sagittis, eget porta velit efficitur. Vestibulum ultricies eros neque. Phasellus rutrum suscipit enim, in interdum ante gravida vitae. Sed in sagittis diam, non commodo velit. + +Morbi hendrerit odio orci, nec tincidunt odio rhoncus nec. Mauris neque velit, vehicula a lorem at, suscipit tristique dui. Sed finibus, nisl in mattis convallis, turpis neque sodales lacus, eu porta enim magna non diam. Nam commodo sodales risus consectetur malesuada. In eget elementum justo. Phasellus sit amet massa imperdiet, dapibus nunc sit amet, suscipit orci. Fusce condimentum laoreet feugiat. Ut ut viverra ante. Praesent bibendum interdum commodo. Nulla mollis nisi a est ornare volutpat. Sed at ligula eu nisi dapibus tempus. Proin cursus vestibulum justo, nec efficitur justo dignissim vel. Nunc quis maximus eros. + +Cras viverra, diam a tristique mattis, libero felis vulputate tellus, a ornare felis leo a dui. Nulla ante nulla, finibus ut tellus ut, blandit pharetra nibh. Proin eleifend fermentum ex, eget auctor libero vulputate in. Nullam ultricies, mauris placerat pretium placerat, leo urna lobortis leo, vel placerat arcu libero sed mauris. Aliquam mauris ligula, ornare at urna at, eleifend gravida ligula. Vestibulum consectetur ut nulla non scelerisque. Donec ornare, sem nec elementum aliquam, urna nulla bibendum metus, eu euismod dui ligula ac est. Fusce laoreet erat eu ex lobortis, quis bibendum ligula interdum. Sed vel mi erat. Vivamus id lacus ac enim mattis tempor. Nunc ultricies pellentesque enim sed euismod. Fusce tincidunt convallis elit quis aliquam. Mauris nulla ipsum, sollicitudin quis diam ac, feugiat volutpat tellus. In nibh nibh, vulputate quis tincidunt quis, pulvinar eget magna. Pellentesque quis finibus dolor. Suspendisse viverra vitae lectus non eleifend. + +Nunc ut orci et sapien maximus semper. Nulla dignissim sem urna, ac varius lectus ultricies id. Quisque aliquet pulvinar pretium. In ultricies molestie tellus vehicula porta. Nam enim lorem, aliquam eget ex et, hendrerit volutpat quam. Maecenas diam lacus, pellentesque eget tempus ac, pharetra eu elit. Donec vel eros a sem facilisis vulputate. Nullam ac nisi vulputate, laoreet nisl ac, eleifend sem. Nullam mi massa, rhoncus sed pharetra interdum, tincidunt eget nunc. Aliquam viverra mattis posuere. Mauris et dui sed nisl sollicitudin fermentum quis ut arcu. Nam placerat eget orci at tincidunt. Curabitur vel turpis metus. Phasellus nibh nulla, fermentum scelerisque sem vel, gravida tincidunt velit. Pellentesque vel quam tempor, finibus massa pellentesque, condimentum dui. + +Donec at mattis neque. Etiam velit diam, consequat auctor mauris id, hendrerit faucibus metus. Maecenas ullamcorper eros a est sodales, ac consectetur odio scelerisque. Donec leo metus, imperdiet at pellentesque vel, feugiat id erat. Suspendisse at magna enim. Vestibulum placerat sodales lorem id sollicitudin. Aenean at euismod ligula, eget mollis diam. Phasellus pulvinar, orci nec pretium condimentum, est erat facilisis purus, quis feugiat augue elit aliquam nulla. Aenean vitae tortor id risus congue tincidunt. Sed dolor enim, mattis a ullamcorper id, volutpat ac leo. + +Proin vehicula feugiat augue, id feugiat quam sodales quis. Donec et ultricies massa, a lacinia nulla. Duis aliquam augue ornare euismod viverra. Ut lectus risus, rutrum sit amet efficitur a, luctus nec nisl. Cras volutpat ullamcorper congue. Sed vitae odio metus. Phasellus aliquet euismod varius. + +Nullam sem ex, malesuada ut magna ut, pretium mollis arcu. Nam porttitor eros cursus mi lacinia faucibus. Suspendisse aliquet eleifend iaculis. Maecenas sit amet viverra tortor. Nunc a mollis risus. Etiam tempus dolor in tortor malesuada mattis. Ut tincidunt venenatis est sit amet dignissim. Vestibulum massa enim, tristique sed scelerisque eu, fringilla ac velit. Donec efficitur quis urna sit amet malesuada. Vestibulum consequat ac ligula in dapibus. Maecenas massa massa, molestie non posuere nec, elementum ut magna. In nisi erat, mollis non venenatis eu, faucibus in justo. Morbi gravida non ex non egestas. Pellentesque finibus laoreet diam, eu commodo augue congue vitae. + +Aenean sem mi, ullamcorper dapibus lobortis vitae, interdum tincidunt tortor. Vivamus eget vulputate libero. Ut bibendum posuere lectus, vel tincidunt tortor aliquet at. Phasellus malesuada orci et bibendum accumsan. Aliquam quis libero vel leo mollis porta. Sed sagittis leo ac lacus dictum, ac malesuada elit finibus. Suspendisse pharetra luctus commodo. Vivamus ultricies a odio non interdum. Vivamus scelerisque tincidunt turpis quis tempor. Pellentesque tortor ligula, varius non nunc eu, blandit sollicitudin neque. Nunc imperdiet, diam et tristique luctus, ipsum ex condimentum nunc, sit amet aliquam justo velit sed libero. Duis vel suscipit ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed tincidunt neque vel massa ultricies, id dictum leo consequat. Curabitur lobortis ultricies tellus, eget mattis nisl aliquam sit amet. + +Proin at suscipit justo. Vivamus ut vestibulum nisl. Pellentesque enim odio, pharetra non magna sed, efficitur auctor magna. Praesent tincidunt ante quis ante hendrerit viverra. Pellentesque vel ipsum id magna vulputate efficitur. Sed nec neque accumsan, pulvinar sapien quis, euismod mauris. Donec condimentum laoreet sapien quis gravida. Quisque sed mattis purus. Vestibulum placerat vel neque maximus scelerisque. + +Vestibulum mattis quam quis efficitur elementum. Duis dictum dolor ac scelerisque commodo. Fusce sollicitudin nisi sit amet dictum placerat. Suspendisse euismod pharetra eleifend. In eros nisl, porttitor sed mauris at, consectetur aliquet mauris. Donec euismod viverra neque sed fermentum. Phasellus libero magna, accumsan ut ultricies vitae, dignissim eget metus. Donec tellus turpis, interdum eget maximus nec, hendrerit eget massa. Curabitur auctor ligula in iaculis auctor. In ultrices quam suscipit cursus finibus. Aenean id mi at dolor interdum iaculis vitae ut lorem. Nullam sed nibh fringilla, lacinia odio nec, placerat erat. In dui libero, viverra ac viverra ac, pellentesque sit amet turpis. + +Nulla in enim ex. Sed feugiat est et consectetur venenatis. Cras varius facilisis dui vel convallis. Vestibulum et elit eget tellus feugiat pellentesque. In ut ante eu purus aliquet posuere. Nulla nec ornare sem, sed luctus lorem. Nam varius iaculis odio, eget faucibus nisl ullamcorper in. Sed eget cursus felis, nec efficitur nisi. + +Vivamus commodo et sem quis pulvinar. Pellentesque libero ante, venenatis vitae ligula sit amet, ornare sollicitudin nulla. Mauris eget tellus hendrerit, pulvinar metus quis, tempor nisi. Proin magna ex, laoreet sed tortor quis, varius fermentum enim. Integer eu dolor dictum, vulputate tortor et, aliquet ligula. Vestibulum vitae justo id mauris luctus sollicitudin. Suspendisse eget auctor neque, sodales egestas lorem. Vestibulum lacinia egestas metus vitae euismod. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus ex tellus, volutpat nec pulvinar sit amet, condimentum vitae dui. Curabitur vel felis sodales, lacinia nunc iaculis, ullamcorper augue. Pellentesque consequat dolor quis eros efficitur malesuada. Nulla ut malesuada lectus. + +Morbi et tristique ante. Aliquam erat volutpat. Vivamus vitae dui nec turpis pellentesque fermentum. Quisque eget velit massa. Pellentesque tristique aliquam nisl, eu sollicitudin justo venenatis sed. Duis eleifend sem eros, ut aliquam libero porttitor id. Sed non nunc consequat, rhoncus diam eu, commodo erat. Praesent fermentum in lectus id blandit. Donec quis ipsum at justo volutpat finibus. Nulla blandit justo nulla, at mollis lacus consequat eget. Aenean sollicitudin quis eros ut ullamcorper. + +Pellentesque venenatis nulla ut mi aliquet feugiat. Cras semper vel magna nec pharetra. Integer mattis felis et sapien commodo imperdiet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis quis luctus felis. Vestibulum justo nibh, aliquam non lectus vitae, molestie placerat justo. Donec lorem nibh, gravida sit amet hendrerit ac, maximus id ipsum. Nunc ac libero sodales risus eleifend sagittis. Phasellus est massa, lobortis elementum ex sed, scelerisque consectetur neque. Nunc faucibus neque id lorem malesuada, eget convallis ex mattis. + +Sed turpis tortor, fermentum non turpis id, posuere varius nibh. Donec iaculis lorem dui. Etiam eros ante, sodales eget venenatis at, consectetur eget risus. Curabitur non aliquam ante, a pretium justo. Maecenas tempor nisl tortor, vitae dictum nisi ultrices eu. Duis eget dui ultrices, porttitor lacus sed, lobortis purus. Quisque mattis elit nec neque sagittis, sed commodo leo blandit. Mauris sodales interdum eleifend. Vestibulum condimentum consectetur augue, id luctus diam convallis et. + +Nunc suscipit risus in justo accumsan, a placerat magna tincidunt. Proin a nisl ipsum. Sed libero dui, tristique in augue quis, auctor tristique risus. Sed porttitor ex augue, eu porta augue molestie a. Duis rhoncus purus libero, eu tempus turpis condimentum at. Sed mollis nisi id lectus placerat tincidunt. Maecenas non scelerisque elit, quis rutrum orci. Donec in tellus pharetra urna ornare lobortis. Phasellus id risus at nisi varius rutrum eu ut turpis. + +Duis dictum justo quis nisl porta, eget tincidunt magna suscipit. Sed velit massa, ullamcorper eu sodales ac, pretium a massa. Duis et rutrum tortor. Nulla accumsan hendrerit sapien, cursus volutpat eros egestas eget. Donec sollicitudin at ante quis sollicitudin. Aenean blandit feugiat diam, id feugiat eros faucibus eget. Donec viverra dolor vel justo scelerisque dignissim. Nulla semper sem nunc, rhoncus semper tellus ultricies sed. Duis in ornare diam. Donec vehicula feugiat varius. Maecenas ut suscipit est. Vivamus sem sem, finibus at dolor sit amet, euismod dapibus ligula. Vestibulum fringilla odio dapibus, congue massa eget, congue sem. Donec feugiat magna eget tortor lacinia scelerisque non et ipsum. + +Suspendisse potenti. Nunc convallis sollicitudin ex eget venenatis. Sed iaculis nibh ex, vel ornare ligula congue dignissim. Quisque sollicitudin dolor ac dui vestibulum, sit amet molestie nisi aliquet. Donec at risus felis. Aenean sollicitudin metus a feugiat porta. Aenean a tortor ut dolor cursus sagittis. Vivamus consectetur porttitor nunc in facilisis. Proin sit amet mi vel lectus consectetur ultrices. + +Sed cursus lectus vitae nunc tristique, nec commodo turpis dapibus. Pellentesque luctus ex id facilisis ornare. Morbi quis placerat dolor. Donec in lectus in arcu mattis porttitor ac sit amet metus. Cras congue mauris non risus sodales, vitae feugiat ipsum bibendum. Nulla venenatis urna sed libero elementum, a cursus lorem commodo. Mauris faucibus lobortis eros nec commodo. + +Nullam suscipit ligula ullamcorper lorem commodo blandit. Nulla porta nibh quis pulvinar placerat. Vivamus eu arcu justo. Vestibulum imperdiet est ut fermentum porttitor. Pellentesque consectetur libero in sapien efficitur scelerisque. Curabitur ac erat sit amet odio aliquet dignissim. Pellentesque mi sem, rhoncus et luctus at, porttitor rutrum lectus. Vestibulum sollicitudin sollicitudin suscipit. Aenean efficitur dolor non ultrices imperdiet. Donec vel sem ex. + +Sed convallis mauris aliquam rutrum cursus. Ut tempor porttitor sodales. Etiam eu risus ac augue gravida egestas et eu dolor. Proin id magna ex. Suspendisse quis lectus quis lorem ultricies tempus. Donec porttitor velit vitae tincidunt faucibus. Aliquam vitae semper nisi. Morbi ultrices, leo non pretium dapibus, dui libero pellentesque ex, vel placerat enim ante vitae dui. Nunc varius, sem sit amet sagittis lobortis, lectus odio scelerisque mauris, ut vestibulum orci magna quis neque. Sed id congue justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris congue nisi est, malesuada mollis elit tincidunt sed. Curabitur sed ex sit amet felis tristique elementum vitae vel nibh. + +Etiam mollis pretium lobortis. Mauris augue lacus, efficitur at lacus sed, mollis tincidunt lectus. Aliquam erat volutpat. Donec at euismod elit, et mattis felis. Sed id lobortis urna. Morbi imperdiet vestibulum leo, sed maximus leo blandit eu. Aliquam semper lorem neque, nec euismod turpis mattis mollis. Quisque lobortis urna ultrices odio pretium, ac venenatis orci faucibus. Suspendisse bibendum odio ligula, sed lobortis massa pharetra nec. Donec turpis justo, iaculis at dictum ac, finibus eu libero. Maecenas quis porttitor mi, sit amet aliquet neque. + +Vivamus auctor vulputate ante, at egestas lorem. Donec eu risus in nulla mollis ultricies at et urna. Duis accumsan porta egestas. Ut vel euismod augue. Fusce convallis nulla ante, nec fringilla velit aliquet at. Nam malesuada dapibus ligula, a aliquam nibh scelerisque ac. Praesent malesuada neque et pellentesque interdum. Curabitur volutpat at turpis vitae tristique. Vivamus porttitor semper congue. Quisque suscipit lacus mi, rhoncus ultrices tortor auctor quis. Maecenas neque neque, molestie ac facilisis eget, luctus ac lorem. In ut odio ut lacus suscipit pulvinar vitae sed elit. Nulla imperdiet, sem quis euismod sagittis, dui erat luctus dolor, faucibus faucibus erat sem eget nunc. Nam accumsan placerat malesuada. Maecenas convallis finibus pulvinar. + +Cras at placerat tortor. Morbi facilisis auctor felis sit amet molestie. Donec sodales sed lorem vitae suscipit. Etiam fermentum pharetra ipsum, nec luctus orci gravida eu. Pellentesque gravida, est non condimentum tempus, mauris ligula molestie est, in congue dolor nisl vel sapien. Duis congue tempor augue, id rutrum eros porta dapibus. Etiam rutrum eget est eget vestibulum. Aenean mollis arcu vel consequat varius. Praesent at condimentum felis. Duis nec interdum nisl. Donec commodo lorem sed sapien scelerisque malesuada non eu urna. In blandit non ipsum at porta. Nam lobortis leo vitae dui auctor, non feugiat quam bibendum. Donec auctor lectus sagittis laoreet maximus. Maecenas rhoncus laoreet porttitor. Vestibulum porttitor augue ut lectus hendrerit, eget posuere mi gravida. + +Sed mattis ex in erat pulvinar, eu imperdiet magna dapibus. Etiam nisi nibh, tempus non tellus sit amet, mattis tempor odio. Quisque nec lorem feugiat, lobortis odio et, commodo nunc. Maecenas semper purus nisi, nec vehicula nibh eleifend vitae. Nulla fermentum a lectus at maximus. Phasellus finibus metus non euismod ultrices. Etiam a pulvinar ante. Quisque convallis nec metus sit amet facilisis. Praesent laoreet massa et sollicitudin laoreet. Vestibulum in mauris aliquet, convallis mi ut, elementum purus. Nulla purus nulla, sodales at hendrerit quis, tempus sed lectus. + +Nam ut laoreet neque, ut maximus nibh. Maecenas quis justo pellentesque, sollicitudin elit at, venenatis velit. Aenean nunc velit, vehicula scelerisque odio at, consectetur laoreet purus. Duis dui purus, malesuada quis ipsum sit amet, tempor interdum libero. Curabitur porta scelerisque sapien, vitae cursus diam condimentum eu. Phasellus sed orci quam. Nullam vitae dui quis purus tincidunt vestibulum. Curabitur quis nulla porta, cursus arcu non, auctor enim. Etiam sollicitudin ex id sem vehicula mollis. Morbi viverra laoreet tincidunt. Praesent ut semper dui. Nam sit amet pretium neque. Mauris vitae luctus diam, in lacinia purus. Maecenas ut placerat justo, ut porta felis. Integer eu mauris ante. + +Aenean porttitor tellus diam, tempor consequat metus efficitur id. Suspendisse ut felis at erat tempor dictum at nec sapien. Sed vestibulum interdum felis, ac mattis mauris porta in. Nunc et condimentum massa. Sed cursus dictum justo et luctus. Integer convallis enim nisl, a rutrum lectus ultricies in. Donec dapibus lacus at nulla dapibus, id sollicitudin velit hendrerit. Fusce a magna at orci mollis rutrum ac a dolor. Aliquam erat volutpat. Morbi varius porta nunc, sit amet sodales ex hendrerit commodo. Donec tincidunt tortor sapien, vitae egestas sapien vehicula eget. + +Suspendisse potenti. Donec pulvinar felis nec leo malesuada interdum. Integer posuere placerat maximus. Donec nibh ipsum, tincidunt vitae luctus vitae, bibendum at leo. Sed cursus nisl ut ex faucibus aliquet sed nec eros. Curabitur molestie posuere felis. Integer faucibus velit eget consequat iaculis. Mauris sed vulputate odio. Phasellus maximus, elit a pharetra egestas, lorem magna semper tellus, vestibulum semper diam felis at sapien. Suspendisse facilisis, nisl sit amet euismod vehicula, libero nulla vehicula dolor, quis fermentum nibh elit sit amet diam. + +Morbi lorem enim, euismod eu varius ut, scelerisque quis odio. Nam tempus vitae eros id molestie. Nunc pretium in nulla eget accumsan. Quisque mattis est ut semper aliquet. Maecenas eget diam elementum, fermentum ipsum a, euismod sapien. Duis quam ligula, cursus et velit nec, ullamcorper tincidunt magna. Donec vulputate nisl est, et ullamcorper urna tempor sit amet. + +Proin lacinia dui non turpis congue pretium. Morbi posuere metus vel purus imperdiet interdum. Morbi venenatis vel eros non ultricies. Nulla vel semper elit. Ut quis purus tincidunt, auctor justo ut, faucibus turpis. Proin quis mattis erat, at faucibus ligula. Mauris in mauris enim. Donec facilisis enim at est feugiat hendrerit. Nam vel nisi lorem. Fusce ultricies convallis diam, in feugiat tortor luctus quis. Donec tempor, leo vitae volutpat aliquam, magna elit feugiat leo, quis placerat sapien felis eget arcu. Donec ornare fermentum eleifend. Integer a est orci. + +Proin rhoncus egestas leo. Nulla ultricies porta elit quis ornare. Nunc fermentum interdum vehicula. In in ligula lorem. Donec nec arcu sit amet orci lobortis iaculis. Mauris at mollis erat, sit amet mollis tortor. Mauris laoreet justo ullamcorper porttitor auctor. Aenean sit amet aliquam lectus, id fermentum eros. Praesent urna sem, vehicula ac fermentum id, dapibus ut purus. Vestibulum vitae tempus nunc. Donec at nunc ornare metus volutpat porta at eget magna. Donec varius aliquet metus, eu lobortis risus aliquam sed. Ut dapibus fermentum velit, ac tincidunt libero faucibus at. + +In in purus auctor, feugiat massa quis, facilisis nisi. Donec dolor purus, gravida eget dolor ac, porttitor imperdiet urna. Donec faucibus placerat erat, a sagittis ante finibus ac. Sed venenatis dignissim elit, in iaculis felis posuere faucibus. Praesent sed viverra dolor. Mauris sed nulla consectetur nunc laoreet molestie in ut metus. Proin ac ex sit amet magna vulputate hendrerit ac condimentum urna. Proin ligula metus, gravida et sollicitudin facilisis, iaculis ut odio. Cras tincidunt urna et augue varius, ut facilisis urna consequat. Aenean vehicula finibus quam. Ut iaculis eu diam ac mollis. Nam mi lorem, tristique eget varius at, sodales at urna. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin vitae dictum erat, et auctor ipsum. Nullam nunc nunc, sollicitudin quis magna a, vestibulum fermentum mauris. Praesent at erat dolor. Proin laoreet tristique nulla vel efficitur. Nam sed ultrices nibh, id rutrum nunc. Curabitur eleifend a erat sit amet sollicitudin. Nullam metus quam, laoreet vitae dapibus id, placerat sed leo. Aliquam erat volutpat. Donec turpis nisl, cursus eu ex sit amet, lacinia pellentesque nisl. Sed id ipsum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec interdum scelerisque lorem eu mattis. + +Vivamus ac tristique massa, nec facilisis nisl. Nam ipsum neque, tincidunt vel urna in, cursus imperdiet enim. Nam pellentesque egestas tempus. Morbi facilisis imperdiet libero vitae fringilla. Nam lacinia ligula at sapien facilisis malesuada. Nullam accumsan pulvinar sem, et cursus libero porta sit amet. Curabitur vulputate erat elit, ut pulvinar erat maximus vel. + +Cras aliquet metus ut purus sagittis, vel venenatis ante consectetur. Pellentesque nulla lacus, viverra viverra mattis non, placerat vitae nibh. Donec enim turpis, accumsan sit amet tincidunt eu, imperdiet non metus. Morbi ipsum eros, tincidunt vel est ac, tristique porttitor nibh. Praesent ut ullamcorper mauris. Sed laoreet sit amet diam congue venenatis. Integer porta purus nec orci sagittis posuere. + +Donec vehicula mauris eget lacus mollis venenatis et sed nibh. Nam sodales ligula ipsum, scelerisque lacinia ligula sagittis in. Nam sit amet ipsum at erat malesuada congue. Aenean ut sollicitudin sapien. Etiam at tempor odio. Mauris vitae purus ut magna suscipit consequat. Vivamus quis sapien neque. Nulla vulputate sem sit amet massa pellentesque, eleifend tristique ligula egestas. Suspendisse tincidunt gravida mi, in pulvinar lectus egestas non. Aenean imperdiet ex sit amet nunc sollicitudin porta. Integer justo odio, ultricies at interdum in, rhoncus vitae sem. Sed porttitor arcu quis purus aliquet hendrerit. Praesent tempor tortor at dolor dictum pulvinar. Nulla aliquet nunc non ligula scelerisque accumsan. Donec nulla justo, congue vitae massa in, faucibus hendrerit magna. Donec non egestas purus. + +Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibus mattis neque dictum sed. Sed convallis fermentum molestie. Nulla facilisi turpis duis. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vulputate, ipsum quis interdum fermentum, lorem sem fermentum eros, vitae auctor neque lacus in nisi. Suspendisse potenti. Maecenas et scelerisque elit, in tincidunt quam. Sed eu tincidunt quam. Nullam justo ex, imperdiet a imperdiet et, fermentum sit amet eros. Aenean quis tempus sem. Pellentesque accumsan magna mi, ut mollis velit sagittis id. Etiam quis ipsum orci. Fusce purus ante, accumsan a lobortis at, venenatis eu nisl. Praesent ornare sed ante placerat accumsan. Suspendisse tempus dignissim fermentum. Nunc a leo ac lacus sodales iaculis eu vitae mi. In feugiat ante at massa finibus cursus. Suspendisse posuere fringilla ornare. Mauris elementum ac quam id convallis. Vestibulum non elit quis urna volutpat aliquam a eu lacus. + +Aliquam vestibulum imperdiet neque, suscipit aliquam elit ultrices bibendum. Suspendisse ultrices pulvinar cursus. Morbi risus nisi, cursus consequat rutrum vitae, molestie sed dui. Fusce posuere, augue quis dignissim aliquam, nisi ipsum porttitor ante, quis fringilla nisl turpis ac nisi. Nulla varius enim eget lorem vehicula gravida. Donec finibus malesuada leo nec semper. Proin ac enim eros. Vivamus non tincidunt nisi, vel tristique lorem. + +Nunc consequat ex id eros dignissim, id rutrum risus laoreet. Sed euismod non erat eu ultricies. Etiam vehicula gravida lacus ut porta. Vestibulum eu eros quis nunc aliquet luctus. Cras quis semper ligula. Nullam gravida vehicula quam sed porta. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In porta cursus vulputate. Quisque porta a nisi eget cursus. Aliquam risus leo, luctus ac magna in, efficitur cursus magna. In condimentum non mi id semper. Donec interdum ante eget commodo maximus. + +Vivamus sit amet vestibulum lectus. Fusce tincidunt mi sapien, dictum sollicitudin diam vulputate in. Integer fringilla consequat mollis. Cras aliquet consequat felis eget feugiat. Nunc tempor cursus arcu, vitae ornare nunc varius et. Vestibulum et tortor vel ante viverra porttitor. Nam at tortor ullamcorper, facilisis augue quis, tristique erat. Aenean ut euismod nibh. Quisque eu tincidunt est, nec euismod eros. + +Proin vehicula nibh non viverra egestas. Phasellus sem dolor, ultricies ac sagittis tristique, lacinia a purus. Vestibulum in ante eros. Pellentesque lacus nulla, tristique vitae interdum vel, malesuada ac diam. Aenean bibendum posuere turpis in accumsan. Ut est nulla, ullamcorper quis turpis at, viverra sagittis mauris. Sed in interdum purus. Praesent scelerisque nibh eget sem euismod, ut imperdiet mi venenatis. Vivamus pulvinar orci sed dapibus auctor. Nulla facilisi. Vestibulum tincidunt erat nec porttitor egestas. Mauris quis risus ante. Nulla facilisi. + +Aliquam ullamcorper ornare lobortis. Phasellus quis sem et ipsum mollis malesuada sed in ex. Ut aliquam ex eget metus finibus maximus. Proin suscipit mauris eu nibh lacinia, quis feugiat dui dapibus. Nam sed libero est. Aenean vulputate orci sit amet diam faucibus, eu sagittis sapien volutpat. Nam imperdiet felis turpis, at pretium odio pulvinar in. Sed vestibulum id eros nec ultricies. Sed quis aliquam tortor, vitae ullamcorper tellus. Donec egestas laoreet eros, id suscipit est rutrum nec. Sed auctor nulla eget metus aliquam, ut condimentum enim elementum. + +Aliquam suscipit non turpis sit amet bibendum. Fusce velit ligula, euismod et maximus at, luctus sed neque. Quisque pretium, nisl at ullamcorper finibus, lectus leo mattis sapien, vel euismod mauris diam ullamcorper ex. Nulla ut risus finibus, lacinia ligula at, auctor erat. Mauris consectetur sagittis ligula vel dapibus. Nullam libero libero, lobortis aliquam libero vel, venenatis ultricies leo. Duis porttitor, nibh congue fermentum posuere, erat libero pulvinar tortor, a pellentesque nunc ipsum vel sem. Nullam volutpat, eros sit amet facilisis consectetur, ipsum est vehicula massa, non vestibulum neque elit in mauris. Nunc hendrerit ipsum non enim bibendum, vitae rhoncus mi egestas. Etiam ullamcorper massa vel nisl sagittis, nec bibendum arcu malesuada. Aenean aliquet turpis justo, a consectetur arcu mollis convallis. Etiam tellus ipsum, ultricies vitae lorem et, ornare facilisis orci. Praesent fringilla justo urna, vel mollis neque pulvinar vestibulum. + +Donec non iaculis erat. Aliquam et mi sed nunc pulvinar ultricies in ut ipsum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Praesent feugiat lacus ac dignissim semper. Phasellus vitae quam nisi. Morbi vel diam ultricies risus lobortis ornare. Fusce maximus et ligula quis iaculis. Sed congue ex eget felis convallis, sit amet hendrerit elit tempor. Donec vehicula blandit ante eget commodo. Vestibulum eleifend diam at feugiat euismod. Etiam magna tellus, dignissim eget fermentum vel, vestibulum vitae mauris. Nam accumsan et erat id sagittis. Donec lacinia, odio ut ornare ultricies, dolor velit accumsan tortor, non finibus erat tellus quis ligula. Nunc quis metus in leo volutpat ornare vulputate eu nisl. + +Donec quis viverra ex. Nullam id feugiat mauris, eu fringilla nulla. Vestibulum id maximus elit. Cras elementum elit sed felis lobortis, eget sagittis nisi hendrerit. Vivamus vitae elit neque. Donec vulputate lacus ut libero ultrices accumsan. Vivamus accumsan nulla orci, in dignissim est laoreet sagittis. Proin at commodo velit. Curabitur in velit felis. Aliquam erat volutpat. Sed consequat, nulla et cursus sodales, nisi lacus mattis risus, quis eleifend erat ex nec turpis. Sed suscipit ultrices lorem in hendrerit. + +Morbi vitae lacus nec libero ornare tempus eu et diam. Suspendisse magna ipsum, fermentum vel odio quis, molestie aliquam urna. Fusce mollis turpis a eros accumsan porttitor. Pellentesque rhoncus dolor sit amet magna rutrum, et dapibus justo tempor. Sed purus nisi, maximus vitae fringilla eu, molestie nec urna. Fusce malesuada finibus pretium. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec sed aliquet eros. Pellentesque luctus diam ante, eget euismod nisl aliquet eu. Sed accumsan elit purus, tempor varius ligula tempus nec. Curabitur ornare leo suscipit suscipit fermentum. Morbi eget nulla est. Maecenas faucibus interdum tristique. + +Etiam ut elit eros. Nulla pharetra suscipit molestie. Nulla facilisis bibendum nisl non molestie. Curabitur turpis lectus, facilisis vel diam non, vulputate ultrices mauris. Aenean placerat aliquam convallis. Suspendisse sed scelerisque tellus. Vivamus lacinia neque eget risus cursus suscipit. Proin consequat dolor vel neque tempor, eu aliquam sem scelerisque. Duis non eros a purus malesuada pharetra non et nulla. Suspendisse potenti. Mauris libero eros, finibus vel nulla id, sagittis dapibus ante. Proin iaculis sed nunc et cursus. + +Quisque accumsan lorem sit amet lorem aliquet euismod. Curabitur fermentum rutrum posuere. Etiam ultricies, sem id pellentesque suscipit, urna magna lacinia eros, quis efficitur risus nisl at lacus. Nulla quis lacus tortor. Mauris placerat ex in dolor tincidunt, vel aliquet nisi pretium. Cras iaculis risus vitae pellentesque aliquet. Quisque a enim imperdiet, ullamcorper arcu vitae, rutrum risus. Nullam consectetur libero at felis fringilla, nec congue nibh dignissim. Nam et lobortis felis, eu pellentesque ligula. Aenean facilisis, ligula non imperdiet maximus, massa orci gravida sapien, at sagittis lacus nisl in lacus. Nulla quis mauris luctus, scelerisque felis consequat, tempus risus. Fusce auctor nisl non nulla luctus molestie. Maecenas sapien nisl, auctor non dolor et, iaculis scelerisque lorem. Suspendisse egestas enim aliquet, accumsan mauris nec, posuere quam. Nulla iaculis dui dui, sit amet vestibulum erat ultricies ac. + +Cras eget dolor erat. Proin at nisl ut leo consectetur ultricies vel ut arcu. Nulla in felis malesuada, ullamcorper tortor et, convallis massa. Nunc urna justo, ornare in nibh vitae, hendrerit condimentum libero. Etiam vitae libero in purus venenatis fringilla. Nullam velit nulla, consequat ut turpis non, egestas hendrerit nibh. Duis tortor turpis, interdum non ante ac, cursus accumsan lectus. Cras pharetra bibendum augue quis dictum. Sed euismod vestibulum justo. Proin porta lobortis purus. Duis venenatis diam tortor, sit amet condimentum eros rhoncus a. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc at magna nec diam lobortis efficitur sit amet ut lacus. Nulla quis orci tortor. Pellentesque tempus velit a odio finibus porta. + +Proin feugiat mauris a tellus scelerisque convallis. Maecenas libero magna, blandit nec ultrices id, congue vel mi. Aliquam lacinia, quam vel condimentum convallis, tortor turpis aliquam odio, sed blandit libero lacus et eros. In eleifend iaculis magna ac finibus. Praesent auctor facilisis tellus in congue. Sed molestie lobortis dictum. Nam quis dignissim augue, vel euismod lorem. Curabitur posuere dapibus luctus. Donec ultricies dictum lectus, quis blandit arcu commodo ac. Aenean tincidunt ligula in nunc imperdiet dignissim. Curabitur egestas sollicitudin sapien ut semper. Aenean nec dignissim lacus. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec aliquam dictum vehicula. Donec tortor est, volutpat non nisi nec, varius gravida ex. Nunc vel tristique nunc, vitae mattis nisi. Nunc nec luctus ex, vitae tincidunt lectus. In hac habitasse platea dictumst. Curabitur lobortis ex eget tincidunt tempor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut a vehicula mi. + +Fusce eu libero finibus, interdum nulla a, placerat neque. Cras bibendum tempor libero nec feugiat. Cras ut sodales eros. Proin viverra, massa sit amet viverra egestas, neque nisl porta ex, sit amet hendrerit libero ligula vel urna. Mauris suscipit lacus id justo rhoncus suscipit. Etiam vel libero tellus. Maecenas non diam molestie, condimentum tellus a, bibendum enim. Mauris aliquet imperdiet tellus, eget sagittis dolor. Sed blandit in neque et luctus. Cras elementum sagittis nunc, vel mollis lorem euismod et. Donec posuere at lacus eget suscipit. + +Nulla nunc mi, pretium non massa vel, tempor semper magna. Nunc a leo pulvinar, tincidunt nunc at, dignissim mi. Aliquam erat volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut viverra nulla a nisl finibus, at hendrerit ligula ullamcorper. Donec a lorem semper, tempor magna et, lobortis libero. Mauris id sapien leo. Donec dignissim, quam vitae porttitor dignissim, quam justo mattis dui, vel consequat odio elit quis orci. Etiam nec pretium neque, sit amet pretium orci. Duis ac tortor venenatis, feugiat purus non, feugiat nunc. Proin scelerisque nisl in turpis aliquam vulputate. + +Praesent sed est semper, fringilla lorem vitae, tincidunt nibh. Cras eros metus, auctor at mauris sit amet, sodales semper orci. Nunc a ornare ex. Curabitur bibendum arcu congue urna vulputate egestas. Vestibulum finibus id risus et accumsan. Aenean ut volutpat tellus. Aenean tincidunt malesuada urna sit amet vestibulum. Mauris vel tellus dictum, varius lacus quis, dictum arcu. + +Aenean quis metus eu erat feugiat cursus vel at ligula. Proin dapibus sodales urna, id euismod lectus tempus id. Pellentesque ex ligula, convallis et erat vel, vulputate condimentum nisl. Pellentesque pharetra nulla quis massa eleifend hendrerit. Praesent sed massa ipsum. Maecenas vehicula dolor massa, id sodales urna faucibus et. Mauris ac quam non massa tincidunt feugiat et at lacus. Fusce libero massa, vulputate vel scelerisque non, mollis in leo. Ut sit amet ultricies odio. Suspendisse in sapien viverra, facilisis purus ut, pretium libero. + +Vivamus tristique pharetra molestie. Nam a volutpat purus. Praesent consequat gravida nisi, ac blandit nisi suscipit ut. Quisque posuere, ligula a ultrices laoreet, ligula nunc vulputate libero, ut rutrum erat odio tincidunt justo. Sed vitae leo at leo fringilla bibendum. Vestibulum ut augue nec dolor auctor accumsan. Praesent laoreet id eros pulvinar commodo. Suspendisse potenti. Ut pharetra, mauris vitae blandit fringilla, odio ante tincidunt lorem, sit amet tempor metus diam ut turpis. + +Praesent quis egestas arcu. Nullam at porta arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi vulputate ligula malesuada ligula luctus, vulputate tempus erat bibendum. Nunc ullamcorper non lectus at euismod. Etiam nibh felis, tincidunt a metus vel, pellentesque rhoncus neque. Etiam at diam in erat luctus interdum. Nunc vel ipsum pulvinar, sollicitudin lacus ac, tempus urna. Etiam vel lacinia sapien. Pellentesque sagittis velit vel mi efficitur iaculis. Integer euismod sit amet urna in sagittis. Cras eleifend ut nibh in facilisis. Donec et lacus vitae nunc placerat sodales. Nulla sed hendrerit ligula, at dapibus sapien. + +Praesent at iaculis ex. Curabitur est purus, cursus a faucibus quis, dictum id velit. Donec dignissim fringilla viverra. Nunc mauris felis, laoreet sit amet sagittis at, vestibulum in libero. Maecenas quis orci turpis. Quisque ut nibh vitae magna mollis consequat id at mauris. Aliquam eu odio eget nulla bibendum sodales. Quisque vel orci eleifend nisi pretium lacinia. Suspendisse eget risus eget mi volutpat molestie eget quis lacus. Duis nisi libero, tincidunt nec nulla id, faucibus cursus felis. + +Donec tempor eget risus pellentesque molestie. Phasellus porta neque vel arcu egestas, nec blandit velit fringilla. Nullam porta faucibus justo vitae laoreet. Pellentesque viverra id nunc eu varius. Nulla pulvinar lobortis iaculis. Etiam vestibulum odio nec velit tristique, a tristique nisi mattis. In sed fringilla orci, vitae efficitur odio. Quisque dui odio, ornare eget velit at, lacinia consequat libero. Quisque lectus nulla, aliquet eu leo in, porta rutrum diam. Donec nec mattis neque. Nam rutrum, odio ac eleifend bibendum, dolor arcu rutrum neque, eget porta elit tellus a lacus. Sed massa metus, sollicitudin et sapien eu, finibus tempus orci. Proin et sapien sit amet erat molestie interdum. In quis rutrum velit, faucibus ultrices tellus. + +Sed sagittis sed justo eget tincidunt. Maecenas ut leo sagittis, feugiat magna et, viverra velit. Maecenas ex arcu, feugiat at consequat vitae, auctor eu massa. Integer egestas, enim vitae maximus convallis, est lectus pretium mauris, ac posuere lectus nisl quis quam. Aliquam tempus laoreet mi, vitae dapibus dolor varius dapibus. Suspendisse potenti. Donec sit amet purus nec libero dapibus tristique. Pellentesque viverra bibendum ligula. Donec sed felis et ex lobortis laoreet. Phasellus a fringilla libero, vitae malesuada nulla. Pellentesque blandit mattis lacus, et blandit tortor laoreet consequat. Suspendisse libero nunc, viverra sed fermentum in, accumsan egestas arcu. Proin in placerat elit. Sed interdum imperdiet malesuada. Suspendisse aliquet quis mauris eget sollicitudin. + +Vivamus accumsan tellus non erat volutpat, quis dictum dolor feugiat. Praesent rutrum nunc ac est mollis cursus. Fusce semper volutpat dui ut egestas. Curabitur sit amet posuere massa. Cras tincidunt nulla et mi mollis imperdiet. Suspendisse scelerisque ex id sodales vulputate. In nunc augue, pharetra in placerat eu, mattis id tellus. Vivamus cursus efficitur vehicula. Nulla aliquet vehicula aliquet. + +Sed cursus tellus sed porta pulvinar. Sed vitae nisi neque. Nullam aliquet, lorem et efficitur scelerisque, arcu diam aliquam felis, sed pulvinar lorem odio et turpis. Praesent convallis pulvinar turpis eu iaculis. Aliquam nec gravida mi. Curabitur eu nibh tempor, blandit justo in, ultrices felis. Fusce placerat metus non mi sagittis rutrum. Morbi sed dui fringilla, sagittis mauris eget, imperdiet nunc. Phasellus hendrerit sem elit, id hendrerit libero auctor sit amet. Integer sodales elit sit amet consequat cursus. + +Nam semper est eget nunc mollis, in pellentesque lectus fringilla. In finibus vel diam id semper. Nunc mattis quis erat eu consectetur. In hac habitasse platea dictumst. Nullam et ipsum vestibulum ex pulvinar ultricies sit amet id velit. Aenean suscipit mi tortor, a lobortis magna viverra non. Nulla condimentum aliquet ante et ullamcorper. Pellentesque porttitor arcu a posuere tempus. Aenean lacus quam, imperdiet eu justo vitae, pretium efficitur ex. Duis id purus id magna rhoncus ultrices id eu risus. Nunc dignissim et libero id dictum. + +Quisque a tincidunt neque. Phasellus commodo mi sit amet tempor fringilla. Ut rhoncus, neque non porttitor elementum, libero nulla egestas augue, sed fringilla sapien felis ac velit. Phasellus viverra rhoncus mollis. Nam ullamcorper leo vel erat laoreet luctus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus semper a metus a cursus. Nulla sed orci egestas, efficitur purus ac, malesuada tellus. Aenean rutrum velit at tellus fermentum mollis. Aliquam eleifend euismod metus. + +In hac habitasse platea dictumst. Vestibulum volutpat neque vitae porttitor laoreet. Nam at tellus consequat, sodales quam in, pulvinar arcu. Maecenas varius convallis diam, ac lobortis tellus pellentesque quis. Maecenas eget augue massa. Nullam volutpat nibh ac justo rhoncus, ut iaculis tellus rutrum. Fusce efficitur efficitur libero quis condimentum. Curabitur congue neque non tincidunt tristique. Fusce eget tempor ex, at pellentesque odio. Praesent luctus dictum vestibulum. Etiam non orci nunc. Vivamus vitae laoreet purus, a lobortis velit. Curabitur tincidunt purus ac lectus elementum pellentesque. Quisque sed tincidunt est. + +Sed vel ultrices massa, vitae ultricies justo. Cras finibus mauris nec lacus tempus dignissim. Cras faucibus maximus velit, eget faucibus orci luctus vehicula. Nulla massa nunc, porta ac consequat eget, rhoncus non tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce sed maximus metus, vel imperdiet ipsum. Ut scelerisque lectus at blandit porttitor. Ut vulputate nunc pharetra, aliquet sapien ac, sollicitudin sapien. Aenean eget ante lorem. Nam accumsan venenatis tellus id dignissim. + +Curabitur fringilla, magna non maximus dapibus, nulla sapien vestibulum lectus, sit amet semper dolor neque vitae nisl. Nunc ultrices vehicula augue sed iaculis. Maecenas nec diam mollis, suscipit orci et, vestibulum ante. Pellentesque eu nisl tortor. Nunc eleifend, lacus quis volutpat volutpat, nisi mi molestie sem, quis mollis ipsum libero a tellus. Ut viverra dolor mattis convallis interdum. Sed tempus nisl at nunc scelerisque aliquet. Quisque tempor tempor lorem id feugiat. Nullam blandit lectus velit, vitae porta lacus tincidunt a. Vivamus sit amet arcu ultrices, tincidunt mi quis, viverra quam. Aenean fringilla libero elementum lorem semper, quis pulvinar eros gravida. Nullam sodales blandit mauris, sed fermentum velit fermentum sit amet. Donec malesuada mauris in augue sodales vulputate. Vestibulum gravida turpis id elit rhoncus dignissim. Integer non congue lorem, eu viverra orci. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec at dolor magna. Aliquam consectetur erat augue, id iaculis velit pharetra ac. Integer rutrum venenatis dignissim. Integer non sodales elit. Curabitur ut magna ut nibh feugiat aliquam ac ut risus. Morbi nibh quam, aliquam id placerat nec, vestibulum eget velit. Suspendisse at dignissim quam. Vivamus aliquet sem sed nisl volutpat, ut cursus orci ultrices. Aliquam ultrices lacinia enim, vitae aliquet neque. + +Quisque scelerisque finibus diam in mattis. Cras cursus auctor velit. Aliquam sem leo, fermentum et maximus et, molestie a libero. Aenean justo elit, rutrum a ornare id, egestas eget enim. Aenean auctor tristique erat. Curabitur condimentum libero lacus, nec consequat orci vestibulum sed. Fusce elit ligula, blandit vitae sapien vitae, dictum ultrices risus. Nam laoreet suscipit sapien, at interdum velit faucibus sit amet. Duis quis metus egestas lectus elementum posuere non nec libero. Aliquam a dolor bibendum, facilisis nunc a, maximus diam. Vestibulum suscipit tristique magna, non dignissim turpis sodales sed. Nunc ornare, velit ac facilisis fringilla, dolor mi consectetur lorem, vitae finibus erat justo suscipit urna. Maecenas sit amet eros erat. Nunc non arcu ornare, suscipit lorem eget, sodales mauris. Aliquam tincidunt, quam nec mollis lacinia, nisi orci fermentum libero, consequat eleifend lectus quam et sapien. Vestibulum a quam urna. + +Cras arcu leo, euismod ac ullamcorper at, faucibus sed massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus porttitor velit in enim interdum, non commodo metus ornare. Morbi vel lorem quis nisl luctus tristique quis vitae nisl. Suspendisse condimentum tortor enim, nec eleifend ipsum euismod et. Sed gravida quam ut tristique lacinia. Mauris eu interdum ipsum, ac ultrices odio. Nullam auctor tellus a risus porttitor vehicula. Nulla blandit euismod dictum. In pharetra, enim iaculis pulvinar interdum, dui nunc placerat nunc, sit amet pretium lectus nulla vitae quam. Phasellus quis enim sollicitudin, varius nulla id, ornare purus. Donec quam lacus, vestibulum quis nunc ac, mollis dictum nisi. Cras ut mollis elit. Maecenas ultrices ligula at risus faucibus scelerisque. Etiam vitae porttitor purus. Curabitur blandit lectus urna, ut hendrerit tortor feugiat ut. + +Phasellus fringilla, sapien pellentesque commodo pharetra, ante libero aliquam tellus, ut consectetur augue libero a sapien. Maecenas blandit luctus nisl eget aliquet. Maecenas vitae porta dolor, faucibus laoreet sapien. Suspendisse lobortis, ipsum sed vehicula aliquam, elit purus scelerisque dui, rutrum consectetur diam odio et lorem. In nec lacinia metus. Donec viverra libero est, vel bibendum erat condimentum quis. Donec feugiat purus leo. In laoreet vitae felis a porttitor. Mauris ullamcorper, lacus id condimentum suscipit, neque magna pellentesque arcu, eget cursus neque tellus id metus. Curabitur volutpat ac orci vel ultricies. + +Sed ut finibus erat. Sed diam purus, varius non tincidunt quis, ultrices sit amet ipsum. Donec et egestas nulla. Suspendisse placerat nisi at dui laoreet iaculis. Aliquam aliquet leo at augue faucibus molestie. Nullam lacus augue, hendrerit sed nisi eu, faucibus porta est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam ut leo aliquet sem fermentum rutrum quis ac justo. Integer placerat aliquam nisl ut sagittis. Proin erat orci, lobortis et sem eget, eleifend fringilla augue. Mauris varius laoreet arcu, sed tincidunt felis. Pellentesque venenatis lorem odio, id pulvinar velit molestie feugiat. Donec mattis lacus sed eleifend pulvinar. + +Sed condimentum ex in tincidunt hendrerit. Etiam eget risus lacinia, euismod nibh eu, pellentesque quam. Proin elit eros, convallis id mauris ac, bibendum ultrices lectus. Morbi venenatis, purus id fermentum consequat, nunc libero tincidunt ligula, non dictum ligula orci nec quam. Nulla nec ultrices lorem. Aenean maximus augue vel dictum pharetra. Etiam turpis urna, pellentesque quis malesuada eu, molestie faucibus felis. + +Vestibulum pharetra augue ut quam blandit congue in nec risus. Proin eu nibh eu dui eleifend porta vitae id lectus. Proin lacus nibh, lobortis sed ligula vitae, interdum lobortis erat. Suspendisse potenti. In sollicitudin quis sapien ut aliquet. Mauris ac nulla arcu. Fusce tristique justo quis lectus mollis, eu volutpat lectus finibus. Vivamus venenatis facilisis ex ut vestibulum. + +Etiam varius lobortis purus, in hendrerit elit tristique at. In tempus, augue vestibulum fermentum gravida, ligula tellus vulputate arcu, eu molestie ex sapien at purus. Vestibulum nec egestas metus. Duis pulvinar quam nec consequat interdum. Aenean non dapibus lacus. Aliquam sit amet aliquet nulla. Sed venenatis volutpat purus nec convallis. Phasellus aliquet semper sodales. Cras risus sapien, condimentum auctor urna a, pulvinar ornare nisl. Sed tincidunt felis elit, ut elementum est bibendum ac. Morbi interdum justo vel dui faucibus condimentum. + +Sed convallis eu sem at tincidunt. Nullam at auctor est, et ullamcorper ipsum. Pellentesque eget ante ante. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer euismod, sapien sed dapibus ornare, nibh enim maximus lacus, lacinia placerat urna quam quis felis. Morbi accumsan id nisl ut condimentum. Donec bibendum nisi est, sed volutpat lorem rhoncus in. Vestibulum ac lacinia nunc, eget volutpat magna. Integer aliquam pharetra ipsum, id placerat nunc volutpat quis. Etiam urna diam, rhoncus sit amet varius vel, euismod vel sem. Nullam vel molestie urna. Vivamus ornare erat at venenatis euismod. Suspendisse potenti. Fusce diam justo, tincidunt vel sem at, commodo faucibus nisl. Duis gravida efficitur diam, vel sagittis erat pulvinar ut. + +Quisque vel pharetra felis. Duis efficitur tortor dolor, vitae porttitor erat fermentum sed. Sed eu mi purus. Etiam dignissim tortor eu tempus molestie. Aenean pretium erat enim, in hendrerit ante hendrerit at. Sed ut risus vel nunc venenatis ultricies quis in lacus. Pellentesque vitae purus euismod, placerat risus non, ullamcorper augue. Quisque varius quam ligula, nec aliquet ex faucibus vitae. Quisque rhoncus sit amet leo tincidunt mattis. Cras id mauris eget purus pretium gravida sit amet eu augue. Aliquam dapibus odio augue, id lacinia velit pulvinar eu. + +Mauris fringilla, tellus nec pharetra iaculis, neque nisi ultrices massa, et tincidunt sem dui sed mi. Curabitur erat lorem, venenatis quis tempus lacinia, tempus sit amet nunc. Aliquam at neque ac metus commodo dictum quis vitae justo. Phasellus eget lacus tempus, blandit lorem vel, rutrum est. Aenean pharetra sem ut augue lobortis dignissim. Sed rhoncus at nulla id ultrices. Cras id condimentum felis. In suscipit luctus vulputate. Donec tincidunt lacus nec enim tincidunt sollicitudin ut quis enim. Nam at libero urna. Praesent sit amet massa vitae massa ullamcorper vehicula. + +Nullam bibendum augue ut turpis condimentum bibendum. Proin sit amet urna hendrerit, sodales tortor a, lobortis lectus. Integer sagittis velit turpis, et tincidunt nisi commodo eget. Duis tincidunt elit finibus accumsan cursus. Aenean dignissim scelerisque felis vel lacinia. Nunc lacinia maximus luctus. In hac habitasse platea dictumst. Vestibulum eget urna et enim tempor tempor. Nam feugiat, felis vel vestibulum tempus, orci justo viverra diam, id dapibus lorem justo in ligula. + +Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In ac pellentesque sem. Vestibulum lacinia magna dui, eu lacinia augue placerat et. Maecenas pulvinar congue est. Pellentesque commodo dui non pulvinar scelerisque. Etiam interdum est posuere sem bibendum, ac commodo magna dictum. Cras ipsum turpis, rhoncus nec posuere vitae, laoreet a arcu. Integer ac massa sit amet enim placerat lacinia sed ultrices arcu. Suspendisse sem nibh, luctus sit amet volutpat in, pellentesque eu metus. Ut gravida neque eget mi accumsan tempus. Nam sit amet aliquet nibh. + +Pellentesque a purus cursus nulla hendrerit congue quis et odio. Aenean hendrerit, leo ullamcorper sagittis hendrerit, erat dui molestie quam, sed condimentum lacus risus sed tellus. Morbi a dapibus lectus, ut feugiat ex. Phasellus pretium quam et sapien mollis, vel iaculis dui dignissim. Sed ullamcorper est turpis, a viverra lorem consectetur in. Aenean aliquet nibh non cursus rutrum. Suspendisse at tristique urna, id lobortis urna. In hac habitasse platea dictumst. Phasellus libero velit, rutrum sed tellus nec, dapibus tincidunt ligula. Quisque vel dui venenatis, consequat nisl ut, lacinia ipsum. Phasellus vitae magna pellentesque, lobortis est id, faucibus quam. Nam eleifend faucibus dui vel pellentesque. + +Etiam ut est non lacus tincidunt interdum. Maecenas sed massa urna. Quisque ut nibh tortor. Pellentesque felis ipsum, tempor finibus ipsum et, euismod pretium metus. Donec sit amet est ipsum. Quisque rhoncus justo non finibus elementum. Nulla nec lectus ac tortor placerat fringilla. Phasellus ac ultrices nunc, eu efficitur nisl. Nulla rhoncus nunc vitae ante dictum tincidunt. Nunc ultrices, massa sit amet malesuada dignissim, lectus lacus consequat sapien, non eleifend metus sem in eros. Phasellus mauris ante, dictum sit amet suscipit ac, rhoncus eget nisi. Phasellus at orci mollis, imperdiet neque eget, faucibus nulla. In at purus massa. Pellentesque quis rutrum lectus. + +Integer eu faucibus turpis, sit amet mollis massa. Vestibulum id nulla commodo, rutrum ipsum sed, semper ante. Phasellus condimentum orci nec nibh convallis, ac maximus orci ullamcorper. Maecenas vitae sollicitudin mi. Integer et finibus lectus, et condimentum ligula. Donec elementum tristique quam vitae dapibus. Morbi euismod ipsum in tristique ullamcorper. + +Duis fermentum non enim eu auctor. Quisque lacinia nibh vehicula nibh posuere, eu volutpat turpis facilisis. Ut ac faucibus nulla. Sed eleifend quis ex et pellentesque. Vestibulum sollicitudin in libero id fringilla. Phasellus dignissim purus consequat, condimentum dui sit amet, condimentum ante. Pellentesque ac consectetur massa, quis sagittis est. Nulla maximus tristique risus accumsan convallis. Curabitur imperdiet ac lacus a ultrices. Nulla facilisi. Sed quis quam quis lectus placerat lobortis vel sed turpis. In mollis dui id neque iaculis, ut aliquet tellus malesuada. Proin at luctus odio, vel blandit sapien. Praesent dignissim tortor vehicula libero fringilla, nec ultrices erat suscipit. Maecenas scelerisque purus in dapibus fermentum. + +Curabitur magna odio, mattis in tortor ut, porttitor congue est. Vestibulum mollis lacinia elementum. Fusce maximus erat vitae nunc rutrum lobortis. Integer ligula eros, auctor vel elit non, posuere luctus lacus. Maecenas quis auctor massa. Ut ipsum lacus, efficitur posuere euismod et, hendrerit efficitur est. Phasellus fringilla, quam id tincidunt pretium, nunc dui sollicitudin orci, eu dignissim nisi metus ut magna. Integer lobortis interdum dolor, non bibendum purus posuere et. Donec non lectus aliquet, pretium dolor eu, cursus massa. Sed ut dui sapien. In sed vestibulum massa. Pellentesque blandit, dui non sodales vehicula, orci metus mollis nunc, non pharetra ex tellus ac est. Mauris sagittis metus et fermentum pretium. Nulla facilisi. Quisque quis ante ut nulla placerat mattis ut quis nisi. + +Sed quis nulla ligula. Quisque dignissim ligula urna, sed aliquam purus semper at. Suspendisse potenti. Nunc massa lectus, pharetra vehicula arcu bibendum, imperdiet sodales ipsum. Nam ac sapien diam. Mauris iaculis fringilla mattis. Pellentesque tempus eros sit amet justo volutpat mollis. Phasellus ac turpis ipsum. Morbi vel ante elit. Aenean posuere quam consequat velit varius suscipit. Donec tempor quam ut nibh cursus efficitur. + +Morbi molestie dolor nec sem egestas suscipit. Etiam placerat pharetra lectus, et ullamcorper risus tristique in. Sed faucibus ullamcorper lectus eget fringilla. Maecenas malesuada hendrerit congue. Sed eget neque a erat placerat tincidunt. Aliquam vitae dignissim turpis. Fusce at placerat magna, a laoreet lectus. Maecenas a purus nec diam gravida fringilla. Nam malesuada euismod ante non vehicula. In faucibus bibendum leo, faucibus posuere nisl pretium quis. Fusce finibus bibendum finibus. Vestibulum eu justo maximus, hendrerit diam nec, dignissim sapien. Aenean dolor lacus, malesuada quis vestibulum ac, venenatis ac ipsum. Cras a est id nunc finibus facilisis. Cras lacinia neque et interdum vehicula. Suspendisse vulputate tellus elit, eget tempor dui finibus vel. + +Cras sed pretium odio. Proin hendrerit elementum felis in tincidunt. Nam sed turpis vel justo molestie accumsan condimentum eu nunc. Praesent lobortis euismod rhoncus. Nulla vitae euismod nibh, quis mattis mi. Fusce ultrices placerat porttitor. Duis sem ipsum, pellentesque sit amet odio a, molestie vulputate mauris. + +Duis blandit mollis ligula, sit amet mattis ligula finibus sit amet. Nunc a leo molestie, placerat diam et, vestibulum leo. Suspendisse facilisis neque purus, nec pellentesque ligula fermentum nec. Aenean malesuada mauris lorem, eu blandit arcu pulvinar quis. Duis laoreet urna lacus, non maximus arcu rutrum ultricies. Nulla augue dolor, suscipit eu mollis eu, aliquam condimentum diam. Ut semper orci luctus, pharetra turpis at, euismod mi. Nulla leo diam, finibus sit amet purus sed, maximus dictum lorem. Integer eu mi id turpis laoreet rhoncus. + +Integer a mauris tincidunt, finibus orci ut, pretium mauris. Nulla molestie nunc mi, id finibus lorem elementum sed. Proin quis laoreet ante. Integer nulla augue, commodo id molestie quis, rutrum ut turpis. Suspendisse et tortor turpis. Sed ut pharetra massa. Pellentesque elementum blandit sem, ut elementum tellus egestas a. Fusce eu purus nibh. + +Cras dignissim ligula scelerisque magna faucibus ullamcorper. Proin at condimentum risus, auctor malesuada quam. Nullam interdum interdum egestas. Nulla aliquam nisi vitae felis mollis dictum. Suspendisse dapibus consectetur tortor. Ut ut nisi non sem bibendum tincidunt. Vivamus suscipit leo quis gravida dignissim. + +Aliquam interdum, leo id vehicula mollis, eros eros rhoncus diam, non mollis ligula mi eu mauris. Sed ultrices vel velit sollicitudin tincidunt. Nunc auctor metus at ligula gravida elementum. Praesent interdum eu elit et mollis. Duis egestas quam sit amet velit dignissim consequat. Aliquam ac turpis nec nunc convallis sagittis. Fusce blandit, erat ac fringilla consectetur, dolor eros sodales leo, vel aliquet risus nisl et diam. Aliquam luctus felis vitae est eleifend euismod facilisis et lacus. Sed leo tellus, auctor eu arcu in, volutpat sagittis nisl. Pellentesque nisl ligula, placerat vel ullamcorper at, vulputate ac odio. Morbi ac faucibus orci, et tempus nulla. Proin rhoncus rutrum dolor, in venenatis mauris. Suspendisse a fermentum augue, non semper mi. Nunc eget pretium neque. Phasellus augue erat, feugiat ac aliquam congue, rutrum non sapien. Pellentesque ac diam gravida, consectetur felis at, ornare neque. + +Nullam interdum mattis sapien quis porttitor. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus aliquet rutrum ipsum id euismod. Maecenas consectetur massa et mi porta viverra. Nunc quam nibh, dignissim vitae maximus et, ullamcorper nec lorem. Nunc vitae justo dapibus, luctus lacus vitae, pretium elit. Maecenas et efficitur leo. Curabitur mauris lectus, placerat quis vehicula vitae, auctor ut urna. Quisque rhoncus pharetra luctus. In hac habitasse platea dictumst. Integer sit amet metus nec eros malesuada aliquam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi hendrerit mi ac leo aliquam, sit amet ultricies libero commodo. Mauris dapibus purus metus, sit amet viverra nibh imperdiet et. Nullam porta nulla tellus, quis vehicula diam imperdiet non. Vivamus enim massa, bibendum in fermentum in, ultrices at ex. + +Suspendisse fermentum id nibh eget accumsan. Duis dapibus bibendum erat ut sollicitudin. Aliquam nec felis risus. Pellentesque rhoncus ligula id sem maximus mollis sed nec massa. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ipsum ipsum, sodales sed enim id, convallis faucibus eros. Donec ultricies dictum tincidunt. Cras vitae nibh arcu. Pellentesque cursus, sapien nec consequat fermentum, ipsum ante suscipit dui, imperdiet hendrerit est nisl eu massa. Quisque vitae sem ligula. Aenean iaculis metus ut mauris interdum laoreet. Vivamus sed gravida dolor. + +Morbi nulla metus, porttitor sed eros sit amet, efficitur efficitur est. In vel nisl urna. Ut aliquet tellus at congue convallis. Phasellus imperdiet lobortis sollicitudin. Integer sodales, sem eu ultricies pharetra, erat erat porttitor odio, eget dapibus libero ipsum eget velit. Phasellus gravida nulla nisl, eu pharetra mi auctor vel. Sed blandit pharetra velit, ut egestas libero placerat non. Aliquam a interdum quam. Proin at tortor nec dui sollicitudin tempus sed vestibulum elit. Nunc non sollicitudin velit. + +Aenean consequat diam velit, sed rutrum tortor faucibus dictum. Quisque at semper augue. Duis ut est eget mi ornare bibendum id et ligula. Phasellus consequat tortor non leo pulvinar posuere. Proin vestibulum eleifend felis, in hendrerit tortor sollicitudin eu. Phasellus hendrerit, lacus vel laoreet interdum, dui tortor consequat justo, commodo ultricies arcu felis vitae enim. Vivamus eu sapien at leo suscipit rutrum eu at justo. Aenean et dolor a libero ullamcorper posuere. Integer laoreet placerat nisi in vulputate. Mauris laoreet eget risus sed cursus. Donec scelerisque neque a libero eleifend hendrerit. Nulla varius condimentum nunc sit amet fermentum. Aliquam lorem ex, varius nec mollis ut, ultrices in neque. Morbi sit amet porta leo. Integer iaculis fermentum lacus in vestibulum. + +Ut gravida, tellus ut maximus ultrices, erat est venenatis nisl, vitae pretium massa ex ac magna. Sed non purus eget ligula aliquet volutpat non quis arcu. Nam aliquam tincidunt risus, sit amet fringilla sapien vulputate ut. Mauris luctus suscipit pellentesque. Nunc porttitor dapibus ex quis tempus. Ut ullamcorper metus a eros vulputate, vitae viverra lectus convallis. Mauris semper imperdiet augue quis tincidunt. Integer porta pretium magna, sed cursus sem scelerisque sollicitudin. Nam efficitur, nibh pretium eleifend vestibulum, purus diam posuere sem, in egestas mauris augue sit amet urna. + +Vestibulum tincidunt euismod massa in congue. Duis interdum metus non laoreet fringilla. Donec at ligula congue, tincidunt nunc non, scelerisque nunc. Donec bibendum magna non est scelerisque feugiat at nec neque. Ut orci tortor, tempus eget massa non, dignissim faucibus dolor. Nam odio risus, accumsan pretium neque eget, accumsan dignissim dui. In ut neque auctor, scelerisque tellus sed, ullamcorper nisi. Suspendisse varius cursus quam at hendrerit. Vivamus elit libero, sagittis vitae sem ac, vulputate iaculis ligula. + +Sed lobortis laoreet purus sit amet rutrum. Pellentesque feugiat non leo vel lacinia. Quisque feugiat nisl a orci bibendum vestibulum. In et sollicitudin urna. Morbi a arcu ac metus faucibus tempus. Nam eu imperdiet sapien, suscipit mattis tortor. Aenean blandit ipsum nisi, a eleifend ligula euismod at. Integer tincidunt pharetra felis, mollis placerat mauris hendrerit at. Curabitur convallis, est sit amet luctus volutpat, massa lacus cursus augue, sed eleifend magna quam et risus. Aliquam lobortis tincidunt metus vitae porttitor. Suspendisse potenti. Aenean ullamcorper, neque id commodo luctus, nulla nunc lobortis quam, id dapibus neque dui nec mauris. Etiam quis lorem quis elit commodo ornare. Ut pharetra purus ultricies enim ultrices efficitur. Proin vehicula tincidunt molestie. Mauris et placerat sem. + +Aliquam erat volutpat. Suspendisse velit turpis, posuere ac lacus eu, lacinia laoreet velit. Sed interdum felis neque, id blandit sem malesuada sit amet. Ut sagittis justo erat, efficitur semper orci tempor sed. Donec enim massa, posuere varius lectus egestas, pellentesque posuere mi. Cras tincidunt ut libero sed mattis. Suspendisse quis magna et tellus posuere interdum vel at purus. Pellentesque fringilla tristique neque, id aliquet tellus ultricies non. Duis ut tellus vel odio lobortis vulputate. + +Integer at magna ac erat convallis vestibulum. Sed lobortis porttitor mauris. Fusce varius lorem et volutpat pulvinar. Aenean ac vulputate lectus, vitae consequat velit. Suspendisse ex dui, varius ut risus ut, dictum scelerisque sem. Vivamus urna orci, volutpat ut convallis ac, venenatis vitae urna. In hac habitasse platea dictumst. Etiam eu purus arcu. Aenean vulputate leo urna, vel tristique dui sagittis euismod. Suspendisse non tellus efficitur ante rhoncus volutpat at et sapien. + +Sed dapibus accumsan porttitor. Phasellus facilisis lectus finibus ligula dignissim, id pulvinar lectus feugiat. Nullam egestas commodo nisi posuere aliquet. Morbi sit amet tortor sagittis, rutrum dui nec, dapibus sapien. Sed posuere tortor tortor, interdum auctor magna varius vitae. Vestibulum id sagittis augue. Curabitur fermentum arcu sem, eu condimentum quam rutrum non. Phasellus rutrum nibh quis lectus rhoncus pretium. Curabitur dictum interdum elit. Vestibulum maximus sodales imperdiet. Mauris auctor nec purus sed venenatis. In in urna purus. + +Duis placerat molestie suscipit. Morbi a elit id purus efficitur consequat. Nunc ac commodo turpis. Etiam sit amet lacus a ipsum tempus venenatis sed vel nibh. Duis elementum aliquam mi sed tristique. Morbi ligula tortor, semper ac est vel, lobortis maximus erat. Curabitur ipsum felis, laoreet vel condimentum eget, ullamcorper sit amet mauris. Nulla facilisi. Nam at purus sed mi egestas placerat vitae vel magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse at dignissim diam. Phasellus consectetur eget neque vel viverra. Donec sollicitudin mattis dolor vel malesuada. Vivamus vehicula leo neque, vitae fermentum leo posuere et. Praesent dui est, finibus sit amet tristique quis, pharetra vel nibh. + +Duis nulla leo, accumsan eu odio eget, sagittis semper orci. Quisque ullamcorper ligula quam, commodo porttitor mauris ullamcorper eu. Cras varius sagittis felis in aliquam. Duis sodales risus ac justo vehicula, nec mattis diam lacinia. Cras eget lectus ipsum. Ut commodo, enim vitae malesuada hendrerit, ex dolor egestas lectus, sit amet hendrerit metus diam nec est. Vestibulum tortor metus, lobortis sit amet ante eget, tempor molestie lacus. In molestie et urna et semper. Mauris mollis, sem non hendrerit condimentum, sapien nisi cursus est, non suscipit quam justo non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam enim est, porta ac feugiat vitae, rutrum in lorem. Duis vehicula tortor ut posuere maximus. + +Nullam vestibulum non tellus sed commodo. Quisque mattis elit sit amet sapien sollicitudin, ut condimentum nisl congue. Aenean sagittis massa vel elit faucibus fermentum. Donec tincidunt nisi nec nisl sodales pellentesque. Mauris congue congue ligula ut suscipit. Vivamus velit tortor, tempor et gravida eget, fermentum sit amet ante. Nullam fringilla, lorem at ultrices cursus, urna neque ornare dolor, eu lacinia orci enim sed nibh. Ut a ullamcorper lectus, id mattis purus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean maximus sollicitudin posuere. Nunc at augue lacus. Aenean efficitur leo sit amet lacinia efficitur. + +Quisque venenatis quam mi, in pharetra odio vulputate eu. In vel nisl pulvinar, pulvinar ligula ut, sodales risus. Sed efficitur lectus at vestibulum tincidunt. Vestibulum eu ullamcorper elit. Fusce vestibulum magna enim, et tempor lacus posuere vitae. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer leo elit, luctus nec mattis sit amet, sollicitudin in turpis. + +Proin convallis venenatis leo, vitae tristique erat iaculis nec. Nulla facilisi. Duis porttitor, sapien et bibendum vulputate, sem libero sodales lacus, non malesuada felis erat ut libero. Nam non felis semper, finibus est a, mattis mauris. Praesent nec eros quam. Nulla hendrerit, augue consectetur eleifend ultricies, purus mi condimentum nulla, eget dapibus est nunc sed libero. Nullam elementum dui erat, vitae luctus libero sollicitudin et. Nulla odio magna, placerat in augue eu, dapibus imperdiet odio. Suspendisse imperdiet metus sit amet rhoncus dapibus. Cras at enim et urna vehicula cursus eu a mauris. Integer magna ante, eleifend ac placerat vitae, porta at nisi. Cras eget malesuada orci. Curabitur nunc est, vulputate id viverra et, dignissim sed odio. Curabitur non mattis sem. Sed bibendum, turpis vitae vehicula faucibus, nunc quam ultricies lectus, vitae viverra felis turpis at libero. + +Nullam ut egestas ligula. Proin hendrerit justo a lectus commodo venenatis. Nulla facilisi. Ut cursus lorem quis est bibendum condimentum. Aenean in tristique odio. Fusce tempor hendrerit ipsum. Curabitur mollis felis justo, quis dapibus erat auctor vel. Sed augue lectus, finibus ut urna quis, ullamcorper vestibulum dui. Etiam molestie aliquam tempor. Integer mattis sollicitudin erat, et tristique elit varius vel. Mauris a ex justo. + +Nam eros est, imperdiet non volutpat rutrum, pellentesque accumsan ligula. Duis sit amet turpis metus. Aenean in rhoncus metus, ac fringilla ex. Suspendisse condimentum egestas purus, ut pharetra odio vulputate vel. Duis tincidunt massa a placerat ultrices. Mauris ultricies nibh sit amet condimentum malesuada. Duis tincidunt id ipsum sed congue. + +Praesent eu ex augue. Nullam in porta ligula. In tincidunt accumsan arcu, in pellentesque magna tristique in. Mauris eleifend libero ac nisl viverra faucibus. Nam sollicitudin dolor in commodo hendrerit. Cras at orci metus. Ut quis laoreet orci. Vivamus ultrices leo pellentesque tempor aliquet. Maecenas ut eros vitae purus placerat vestibulum. Etiam vitae gravida dolor, quis rhoncus diam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. + +Suspendisse fringilla lacinia sagittis. Integer tincidunt consectetur tristique. Morbi non orci convallis, congue sapien quis, vulputate nunc. Donec a libero vel magna elementum facilisis non quis mi. Mauris posuere tellus non ipsum ultrices elementum. Vivamus massa velit, facilisis quis placerat aliquet, aliquet nec leo. Praesent a maximus sem. Sed neque elit, feugiat vel quam non, molestie sagittis nunc. Etiam luctus nunc ac mauris scelerisque, nec rhoncus lacus convallis. Nunc pharetra, nunc ac pulvinar aliquam, ex ipsum euismod augue, nec porttitor lacus turpis vitae neque. Fusce bibendum odio id tortor faucibus pellentesque. Sed ac porta nibh, eu gravida erat. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam quis ullamcorper felis. Nulla mattis sagittis ante ac tincidunt. Integer ac felis efficitur, viverra libero et, facilisis ligula. Suspendisse a metus a massa rhoncus posuere. Phasellus suscipit ligula ut lacus facilisis, ac pellentesque ex tempor. Quisque consectetur massa mi, ac molestie libero dictum quis. Proin porttitor ligula quis erat tincidunt venenatis. Proin congue nunc sed elit gravida, nec consectetur lectus sodales. Etiam tincidunt convallis ipsum at vestibulum. Quisque maximus enim et mauris porttitor, et molestie magna tristique. Morbi vitae metus elit. Maecenas sed volutpat turpis. Aliquam vitae dolor vestibulum, elementum purus eget, dapibus nibh. Nullam egestas dui ac rutrum semper. + +Etiam hendrerit est metus, et condimentum metus aliquam ac. Pellentesque id neque id ipsum rhoncus vulputate. Aliquam erat nisl, posuere sit amet ligula ac, fermentum blandit felis. Vivamus fermentum mi risus, non lacinia purus viverra id. Aenean ac sapien consequat, finibus mauris nec, porta sem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed quis consectetur ex, dignissim bibendum nulla. Phasellus ac libero at quam vehicula euismod non eu leo. Phasellus a sapien augue. + +Maecenas ligula dui, bibendum vitae mauris et, auctor laoreet felis. Duis non libero a mi semper mattis. Quisque consequat luctus massa, quis tristique eros auctor feugiat. Maecenas sodales euismod neque vitae facilisis. Nullam laoreet imperdiet velit at pellentesque. Etiam massa odio, facilisis a consequat vitae, placerat vel magna. Nunc sagittis eros nec urna fringilla, pulvinar vestibulum nibh scelerisque. Sed magna metus, cursus eu consequat et, pharetra a est. Suspendisse elementum neque a dui malesuada lacinia. Donec sed ipsum volutpat, cursus urna id, ullamcorper arcu. Maecenas laoreet nisl eget velit egestas sollicitudin. Etiam nisl turpis, mollis id dignissim vitae, tristique vehicula ante. Maecenas eget placerat est, at rutrum augue. Vivamus faucibus lacinia ullamcorper. Sed pulvinar urna sodales ante sodales, at gravida leo dictum. + +Morbi maximus, quam a lobortis bibendum, enim felis varius elit, ac vehicula elit nisl ut lacus. Quisque ut arcu augue. Praesent id turpis quam. Sed sed arcu eros. Maecenas at cursus lorem, ac eleifend nisi. Fusce mattis felis at commodo pharetra. Praesent ac commodo ipsum. Quisque finibus et eros vitae tincidunt. In hac habitasse platea dictumst. Praesent purus ipsum, luctus lobortis ornare quis, auctor eget justo. Nam vel enim sollicitudin, faucibus tortor eu, sagittis eros. Ut nec consectetur erat. Donec ultricies malesuada ligula, a hendrerit sapien volutpat in. Maecenas sed enim vitae sapien pulvinar faucibus. + +Proin semper nunc nibh, non consequat neque ullamcorper vel. Maecenas lobortis sagittis blandit. Aenean et arcu ultricies turpis malesuada malesuada. Ut quam ex, laoreet ut blandit cursus, feugiat vitae dolor. Etiam ex lacus, scelerisque vel erat vel, efficitur tincidunt magna. Morbi tristique lacinia dolor, in egestas magna ultrices vitae. Integer ultrices leo ac tempus venenatis. Praesent ac porta tortor. Vivamus ornare blandit tristique. Nulla rutrum finibus pellentesque. In non dui elementum, fermentum ipsum vel, varius magna. Pellentesque euismod tortor risus, ac pellentesque nisl faucibus eget. + +Vivamus eu enim purus. Cras ultrices rutrum egestas. Sed mollis erat nibh, at posuere nisl luctus nec. Nunc vulputate, sapien id auctor molestie, nisi diam tristique ante, non convallis tellus nibh at orci. Morbi a posuere purus, in ullamcorper ligula. Etiam elementum sit amet dui imperdiet iaculis. Proin vitae tincidunt ipsum, sit amet placerat lectus. Curabitur commodo sapien quam, et accumsan lectus fringilla non. Nullam eget accumsan enim, ac pharetra mauris. Sed quis tristique velit, vitae commodo nisi. Duis turpis dui, maximus ut risus at, finibus consequat nunc. Maecenas sed est accumsan, aliquet diam in, facilisis risus. Curabitur vehicula rutrum auctor. Nam iaculis risus pulvinar maximus viverra. Nulla vel augue et ex sagittis blandit. + +Ut sem nulla, porta ac ante ac, posuere laoreet eros. Donec sodales posuere justo a auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras mollis at orci hendrerit porta. Nullam sodales tortor tortor, non lacinia diam finibus id. Duis libero orci, suscipit ac odio et, dictum consequat ipsum. Pellentesque eu ligula sagittis, volutpat eros at, lacinia lorem. Cras euismod tellus in iaculis tempor. Quisque accumsan, magna a congue venenatis, ante ipsum aliquam lectus, at egestas enim nunc at justo. Quisque sem purus, viverra ut tristique ut, maximus id enim. Etiam quis placerat sem. In sollicitudin, lacus eu rutrum mollis, nulla eros luctus elit, vel dapibus urna purus nec urna. Phasellus egestas massa quam, ac molestie erat hendrerit a. Praesent ultrices neque ut turpis molestie auctor. Etiam molestie placerat purus, et euismod erat aliquam in. Morbi id suscipit justo. + +Proin est ante, consequat at varius a, mattis quis felis. Sed accumsan nibh sit amet ipsum elementum posuere. Vestibulum bibendum id diam sit amet gravida. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi nec dolor vel ipsum dignissim hendrerit vel non ipsum. Praesent facilisis orci quis elit auctor lobortis. Phasellus cursus risus lectus, vel lobortis libero dapibus in. Quisque tristique tempus leo a pulvinar. Pellentesque a magna tincidunt, pellentesque massa nec, laoreet orci. Morbi congue ornare dolor quis commodo. Phasellus massa nisi, tincidunt at eros dictum, hendrerit lobortis urna. Maecenas porta, magna id mattis molestie, nibh tellus lobortis sem, eget tincidunt ipsum quam eu turpis. + +Ut gravida orci risus, vel rutrum mauris vehicula id. Etiam bibendum, neque a placerat condimentum, ex orci imperdiet lectus, quis dapibus arcu lacus eget lectus. Sed consequat non mi sit amet venenatis. Fusce vestibulum erat libero, eget hendrerit risus vulputate sollicitudin. Integer sed eleifend felis. Donec commodo, sem eu mattis placerat, urna odio aliquam tellus, et laoreet justo tellus eget erat. Fusce sed suscipit tortor. Nam hendrerit nibh ac nunc auctor lacinia. Pellentesque placerat condimentum ipsum, eget semper tortor hendrerit vel. Nullam non urna eu lacus pellentesque congue ut id eros. + +Nunc finibus leo in rhoncus tristique. Sed eu ipsum nec nisl egestas faucibus eget a felis. Pellentesque vitae nisi in nulla accumsan fermentum. Sed venenatis feugiat eleifend. Fusce porttitor varius placerat. Aliquam aliquet lacus sit amet mattis mollis. Sed vel nulla quis dolor suscipit vehicula ac viverra lorem. Duis viverra ipsum eget nulla ullamcorper fermentum. Mauris tincidunt arcu quis quam fringilla ornare. Donec et iaculis tortor. Nam ultricies libero vel ipsum aliquet efficitur. Morbi eget dolor aliquam, tempus sapien eget, viverra ante. Donec varius mollis ex, sed efficitur purus euismod interdum. Quisque vel sapien non neque tincidunt semper. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Suspendisse sit amet purus leo. Fusce lectus lorem, aliquam ac nulla eget, imperdiet ornare eros. Nullam sem augue, varius in nisi non, sollicitudin pellentesque ante. Etiam eu odio condimentum, tempor libero et, egestas arcu. Cras pellentesque eleifend aliquet. Pellentesque non blandit ligula. Ut congue viverra rhoncus. Phasellus mattis mi ac eros placerat, eu feugiat tellus ultrices. Aenean mollis laoreet libero eu imperdiet. Cras sed pulvinar mi, ac vehicula ligula. Vestibulum sit amet ex massa. In a egestas eros. + +Mauris pretium ipsum risus, venenatis cursus ante imperdiet id. Praesent eu turpis nec risus feugiat maximus ullamcorper ac lectus. Integer placerat at mi vel dapibus. Vestibulum fermentum turpis sit amet turpis viverra, id aliquet diam suscipit. Nam nec ex sed ante ullamcorper pharetra quis sit amet risus. Sed ac faucibus velit, id feugiat nibh. Nullam eget ipsum ex. Vivamus tincidunt non nunc non faucibus. Quisque bibendum viverra facilisis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at nisi hendrerit quam suscipit egestas. Curabitur laoreet maximus ultricies. Duis ut tellus ac augue molestie dictum. + +Suspendisse rhoncus iaculis erat, ut ullamcorper est tristique eget. Donec auctor nec risus at gravida. Vivamus volutpat vulputate tellus, vel ultricies eros suscipit eget. Ut pulvinar id mi eu tempus. Morbi malesuada augue in dui varius, nec blandit neque vehicula. Donec ornare nec nisl in mollis. Morbi enim nisi, rhoncus nec est id, dapibus tempus urna. Ut id elit a felis vestibulum consectetur. Duis lectus quam, pharetra sit amet diam sed, posuere vestibulum erat. Fusce vitae maximus massa. Nullam id metus tempus, iaculis risus eu, lobortis urna. Quisque in congue urna. Pellentesque placerat neque in augue dapibus, non varius ex malesuada. Curabitur ut eleifend libero. Fusce vitae ligula luctus, fermentum enim vitae, ultrices erat. + +Sed viverra augue turpis, scelerisque egestas sapien mattis eu. Duis laoreet magna at ex pharetra dapibus. Praesent eget odio vel quam venenatis dictum. Nulla in sollicitudin dolor. Mauris lobortis nec eros vel rhoncus. Vestibulum porta viverra venenatis. Curabitur vel scelerisque quam, a egestas velit. Praesent volutpat tincidunt magna at laoreet. + +Cras nec lorem odio. Pellentesque quis dui urna. Praesent at tellus ac lectus scelerisque placerat nec eu risus. Vestibulum sit amet mattis ligula. Vivamus sed nisi at leo elementum accumsan at sit amet arcu. Aenean mattis tellus nec leo gravida, eget hendrerit nisl faucibus. Mauris pellentesque luctus condimentum. Maecenas pretium sapien nunc, eget commodo dolor maximus id. Mauris vestibulum accumsan massa a dictum. Phasellus interdum quam ligula, ut maximus diam blandit aliquam. Nunc vitae ex eu erat condimentum consectetur. Maecenas interdum condimentum volutpat. + +Donec et enim a libero rutrum laoreet. Praesent a condimentum sem, at tincidunt quam. In vel molestie risus. Sed urna dui, molestie vitae mollis laoreet, tempor quis lectus. Praesent vitae auctor est, et aliquet nunc. Curabitur vulputate blandit nulla, at gravida metus. Maecenas gravida dui eu iaculis tristique. Pellentesque posuere turpis nec auctor eleifend. Suspendisse bibendum diam eu tellus lobortis, et laoreet quam congue. In hac habitasse platea dictumst. Morbi dictum neque velit, eget rutrum eros ultrices sit amet. + +Phasellus fermentum risus pharetra consectetur bibendum. Donec magna tortor, lacinia vitae nibh quis, aliquet pretium lorem. Donec turpis nisi, pretium eu enim volutpat, mattis malesuada augue. Nullam vel tellus iaculis, sollicitudin elit eget, tincidunt lacus. Fusce elementum elementum felis et iaculis. Suspendisse porta eros nec neque malesuada, in malesuada ante sollicitudin. Vivamus bibendum viverra molestie. + +Integer feugiat, erat nec convallis aliquam, velit felis congue erat, molestie eleifend tellus erat in tellus. Nunc et justo purus. Donec egestas fermentum dui non feugiat. Quisque in sapien sagittis, gravida quam id, iaculis lectus. Cras sagittis rhoncus bibendum. Fusce quis metus in velit scelerisque tincidunt at non ipsum. Vivamus efficitur ante eu odio vulputate, vitae ultricies risus vehicula. Proin eget odio eu sem tincidunt feugiat vel id lorem. + +Vestibulum sit amet nulla dignissim, euismod mi in, fermentum tortor. Donec ut aliquet libero, lacinia accumsan velit. Donec et nulla quam. Nullam laoreet odio nec nunc imperdiet, a congue eros venenatis. Quisque nec tellus sit amet neque interdum posuere. Duis quis mi gravida, tincidunt diam convallis, ultricies augue. Mauris consequat risus non porttitor congue. Ut in ligula consequat, viverra nunc a, eleifend enim. Duis ligula urna, imperdiet nec facilisis et, ornare eu ex. Proin lobortis lectus a lobortis porttitor. Nulla leo metus, egestas eu libero sed, pretium faucibus felis. Vestibulum non sem tortor. Nam cursus est leo. Vivamus luctus enim odio, non interdum sem dapibus a. Aenean accumsan consequat lectus in imperdiet. + +Donec vehicula laoreet ipsum in posuere. Quisque vel quam imperdiet, sollicitudin nisi quis, suscipit velit. Morbi id sodales mauris. Curabitur tellus arcu, feugiat sed dui sit amet, sodales sagittis libero. Aenean vel suscipit metus, non placerat leo. Vestibulum quis nulla elit. Proin scelerisque non ante ut commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. + +Sed non urna dolor. Suspendisse convallis mi porta pulvinar ultrices. Suspendisse quam ipsum, hendrerit non scelerisque molestie, interdum dictum nunc. Morbi condimentum condimentum turpis eu luctus. Pellentesque sagittis sollicitudin odio, sed ultricies felis ornare sit amet. Sed ultrices ex leo, a tincidunt nisl gravida sed. Nullam ornare accumsan porta. Praesent consectetur id est nec sollicitudin. + +In hac habitasse platea dictumst. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed sed ultrices nibh. Duis accumsan suscipit eros, a dictum odio tempus sit amet. Aenean imperdiet erat ac lacus finibus, scelerisque cursus massa imperdiet. Mauris molestie risus ut lacinia posuere. Nulla et sodales purus. Maecenas orci erat, placerat in tristique quis, placerat in mi. + +Donec sollicitudin pellentesque odio in feugiat. Morbi eu dolor ut mauris congue sollicitudin. Aliquam erat volutpat. Nulla id varius dui. Curabitur finibus urna ante, consectetur interdum nisi volutpat a. Quisque quis mi tristique, consequat tellus eget, rutrum sapien. Vivamus vitae tellus vulputate, rutrum ex eu, vulputate sem. Suspendisse viverra lorem tellus, vel interdum orci gravida quis. Ut laoreet arcu at mi ullamcorper finibus. Duis porta sagittis vestibulum. Sed commodo nisl vitae urna sollicitudin, nec lacinia est sodales. Curabitur imperdiet sodales dui sed iaculis. Sed ac tellus maximus, eleifend quam sit amet, feugiat elit. Aenean viverra, dui at mattis varius, est odio vestibulum sapien, sit amet mollis libero massa nec velit. Etiam quis sodales justo. + +Ut ultricies, sem eget sodales feugiat, nunc arcu congue elit, ac tempor justo massa nec purus. Maecenas enim nunc, pharetra eget dictum sit amet, tempus pellentesque velit. Suspendisse venenatis ligula in nulla mattis, et imperdiet ex tincidunt. Etiam vulputate, tellus et ultrices suscipit, enim velit laoreet massa, vitae congue odio enim ac urna. Morbi quam lorem, iaculis ac varius sagittis, euismod quis dolor. In ut dui eu purus feugiat consectetur. Vestibulum cursus velit quis lacus pellentesque iaculis. Cras in risus sed mauris porta rutrum. Nulla facilisi. Nullam eu bibendum est, non pellentesque lectus. Sed imperdiet feugiat lorem, quis convallis ante auctor in. Maecenas justo magna, scelerisque sit amet tellus eget, varius elementum risus. Duis placerat et quam sed varius. + +Duis nec nibh vitae nibh dignissim mollis quis sed felis. Curabitur vitae quam placerat, venenatis purus ut, euismod nisl. Curabitur porttitor nibh eu pulvinar ullamcorper. Suspendisse posuere nec ipsum ac dapibus. Cras convallis consectetur urna. Phasellus a nibh in dolor lacinia posuere id eget augue. In eu pharetra lorem, vitae cursus lacus. Aliquam tincidunt nibh lectus. Aenean facilisis ultricies posuere. Sed ut placerat orci. Curabitur scelerisque gravida blandit. Maecenas placerat ligula eget suscipit fringilla. Mauris a tortor justo. Aliquam hendrerit semper mollis. Phasellus et tincidunt libero. Etiam vel quam libero. + +Quisque aliquet tempor ex. Ut ante sem, vehicula at enim vel, gravida porta elit. Etiam vitae lacus a neque lobortis consectetur. Mauris sed interdum odio. Mauris elementum ex blandit tempor cursus. Integer in enim in leo viverra elementum. Fusce consectetur metus et sem rutrum, mattis euismod diam semper. Nunc sed ipsum vel urna consequat vehicula. Donec cursus pretium lorem, vestibulum pretium felis commodo sit amet. Nam blandit felis enim, eget gravida ex faucibus a. In nec neque massa. Etiam laoreet posuere ipsum. Praesent volutpat nunc dolor, ac vulputate magna facilisis non. Aenean congue turpis vel lectus sollicitudin tristique. Sed nec consequat purus, non vehicula quam. Etiam ultricies, est ac dictum tincidunt, turpis turpis pretium massa, a vulputate libero justo at nibh. + +Aliquam erat volutpat. Cras ultrices augue ac sollicitudin lobortis. Curabitur et aliquet purus. Duis feugiat semper facilisis. Phasellus lobortis cursus velit, a sollicitudin tortor. Nam feugiat sapien non dapibus condimentum. Morbi at mi bibendum, commodo quam at, laoreet enim. Integer eu ultrices enim. Sed vestibulum eu urna ut dictum. Curabitur at mattis leo, sed cursus massa. Aliquam porttitor, felis quis fermentum porttitor, justo velit feugiat nulla, eget condimentum sem dui ut sapien. + +In fringilla elit eu orci aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut eget fringilla tellus. Curabitur fermentum, mi et condimentum suscipit, elit neque bibendum dui, et hendrerit nunc metus id ipsum. Morbi placerat mi in hendrerit congue. Ut feugiat mauris eget scelerisque viverra. Vivamus sit amet erat dictum, sagittis lectus nec, pulvinar lorem. Sed non enim ac dui sollicitudin aliquet. Quisque ut lacus dolor. Fusce hendrerit malesuada euismod. Nulla faucibus vel mauris eu mollis. Mauris est diam, fringilla ac arcu feugiat, efficitur volutpat turpis. Aliquam venenatis cursus massa sed porttitor. Ut ac finibus enim, in tincidunt sapien. + +Nunc faucibus semper turpis a lacinia. Phasellus gravida, libero vel pulvinar ornare, ex sem tincidunt lectus, sit amet convallis augue risus at tortor. Quisque sit amet ipsum id nulla posuere vestibulum. Pellentesque scelerisque mauris vel leo viverra sodales. Nulla viverra aliquam ex, ut rutrum enim fermentum venenatis. Aenean eget dapibus ex, eget faucibus metus. Vestibulum volutpat leo in diam semper, eget porta magna suscipit. Sed sit amet nulla blandit, aliquam dolor ac, gravida velit. Sed vel velit viverra, maximus est id, convallis justo. + +Curabitur nulla ante, vulputate at libero vel, ullamcorper rutrum nibh. Pellentesque porttitor eu mauris id mattis. Duis vulputate augue elit, eget interdum justo pretium vel. Maecenas eu vulputate arcu, eget posuere purus. Suspendisse viverra a velit dictum eleifend. Suspendisse vitae dapibus diam. Donec vehicula justo in ante interdum, eu luctus diam placerat. Vivamus convallis ipsum eu orci suscipit, sed fermentum enim euismod. Maecenas faucibus elit vitae ex ornare tristique. Donec vestibulum nec elit sit amet porttitor. Aenean tempor lectus eget tortor hendrerit luctus. Nullam interdum vitae lectus vel feugiat. Cras in risus non magna consectetur lobortis. Sed faucibus enim quis gravida convallis. + +Phasellus eget massa sit amet libero ultrices suscipit. Vivamus at risus sapien. Nam mollis nunc eget velit dictum maximus. Sed pellentesque, nunc ac fringilla lacinia, quam enim mattis ex, sed euismod tortor metus eu neque. Ut mattis nisl ut lectus rhoncus, sodales bibendum eros porta. Nulla porttitor enim nec diam sagittis, eget porta velit efficitur. Vestibulum ultricies eros neque. Phasellus rutrum suscipit enim, in interdum ante gravida vitae. Sed in sagittis diam, non commodo velit. + +Morbi hendrerit odio orci, nec tincidunt odio rhoncus nec. Mauris neque velit, vehicula a lorem at, suscipit tristique dui. Sed finibus, nisl in mattis convallis, turpis neque sodales lacus, eu porta enim magna non diam. Nam commodo sodales risus consectetur malesuada. In eget elementum justo. Phasellus sit amet massa imperdiet, dapibus nunc sit amet, suscipit orci. Fusce condimentum laoreet feugiat. Ut ut viverra ante. Praesent bibendum interdum commodo. Nulla mollis nisi a est ornare volutpat. Sed at ligula eu nisi dapibus tempus. Proin cursus vestibulum justo, nec efficitur justo dignissim vel. Nunc quis maximus eros. + +Cras viverra, diam a tristique mattis, libero felis vulputate tellus, a ornare felis leo a dui. Nulla ante nulla, finibus ut tellus ut, blandit pharetra nibh. Proin eleifend fermentum ex, eget auctor libero vulputate in. Nullam ultricies, mauris placerat pretium placerat, leo urna lobortis leo, vel placerat arcu libero sed mauris. Aliquam mauris ligula, ornare at urna at, eleifend gravida ligula. Vestibulum consectetur ut nulla non scelerisque. Donec ornare, sem nec elementum aliquam, urna nulla bibendum metus, eu euismod dui ligula ac est. Fusce laoreet erat eu ex lobortis, quis bibendum ligula interdum. Sed vel mi erat. Vivamus id lacus ac enim mattis tempor. Nunc ultricies pellentesque enim sed euismod. Fusce tincidunt convallis elit quis aliquam. Mauris nulla ipsum, sollicitudin quis diam ac, feugiat volutpat tellus. In nibh nibh, vulputate quis tincidunt quis, pulvinar eget magna. Pellentesque quis finibus dolor. Suspendisse viverra vitae lectus non eleifend. + +Nunc ut orci et sapien maximus semper. Nulla dignissim sem urna, ac varius lectus ultricies id. Quisque aliquet pulvinar pretium. In ultricies molestie tellus vehicula porta. Nam enim lorem, aliquam eget ex et, hendrerit volutpat quam. Maecenas diam lacus, pellentesque eget tempus ac, pharetra eu elit. Donec vel eros a sem facilisis vulputate. Nullam ac nisi vulputate, laoreet nisl ac, eleifend sem. Nullam mi massa, rhoncus sed pharetra interdum, tincidunt eget nunc. Aliquam viverra mattis posuere. Mauris et dui sed nisl sollicitudin fermentum quis ut arcu. Nam placerat eget orci at tincidunt. Curabitur vel turpis metus. Phasellus nibh nulla, fermentum scelerisque sem vel, gravida tincidunt velit. Pellentesque vel quam tempor, finibus massa pellentesque, condimentum dui. + +Donec at mattis neque. Etiam velit diam, consequat auctor mauris id, hendrerit faucibus metus. Maecenas ullamcorper eros a est sodales, ac consectetur odio scelerisque. Donec leo metus, imperdiet at pellentesque vel, feugiat id erat. Suspendisse at magna enim. Vestibulum placerat sodales lorem id sollicitudin. Aenean at euismod ligula, eget mollis diam. Phasellus pulvinar, orci nec pretium condimentum, est erat facilisis purus, quis feugiat augue elit aliquam nulla. Aenean vitae tortor id risus congue tincidunt. Sed dolor enim, mattis a ullamcorper id, volutpat ac leo. + +Proin vehicula feugiat augue, id feugiat quam sodales quis. Donec et ultricies massa, a lacinia nulla. Duis aliquam augue ornare euismod viverra. Ut lectus risus, rutrum sit amet efficitur a, luctus nec nisl. Cras volutpat ullamcorper congue. Sed vitae odio metus. Phasellus aliquet euismod varius. + +Nullam sem ex, malesuada ut magna ut, pretium mollis arcu. Nam porttitor eros cursus mi lacinia faucibus. Suspendisse aliquet eleifend iaculis. Maecenas sit amet viverra tortor. Nunc a mollis risus. Etiam tempus dolor in tortor malesuada mattis. Ut tincidunt venenatis est sit amet dignissim. Vestibulum massa enim, tristique sed scelerisque eu, fringilla ac velit. Donec efficitur quis urna sit amet malesuada. Vestibulum consequat ac ligula in dapibus. Maecenas massa massa, molestie non posuere nec, elementum ut magna. In nisi erat, mollis non venenatis eu, faucibus in justo. Morbi gravida non ex non egestas. Pellentesque finibus laoreet diam, eu commodo augue congue vitae. + +Aenean sem mi, ullamcorper dapibus lobortis vitae, interdum tincidunt tortor. Vivamus eget vulputate libero. Ut bibendum posuere lectus, vel tincidunt tortor aliquet at. Phasellus malesuada orci et bibendum accumsan. Aliquam quis libero vel leo mollis porta. Sed sagittis leo ac lacus dictum, ac malesuada elit finibus. Suspendisse pharetra luctus commodo. Vivamus ultricies a odio non interdum. Vivamus scelerisque tincidunt turpis quis tempor. Pellentesque tortor ligula, varius non nunc eu, blandit sollicitudin neque. Nunc imperdiet, diam et tristique luctus, ipsum ex condimentum nunc, sit amet aliquam justo velit sed libero. Duis vel suscipit ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed tincidunt neque vel massa ultricies, id dictum leo consequat. Curabitur lobortis ultricies tellus, eget mattis nisl aliquam sit amet. + +Proin at suscipit justo. Vivamus ut vestibulum nisl. Pellentesque enim odio, pharetra non magna sed, efficitur auctor magna. Praesent tincidunt ante quis ante hendrerit viverra. Pellentesque vel ipsum id magna vulputate efficitur. Sed nec neque accumsan, pulvinar sapien quis, euismod mauris. Donec condimentum laoreet sapien quis gravida. Quisque sed mattis purus. Vestibulum placerat vel neque maximus scelerisque. + +Vestibulum mattis quam quis efficitur elementum. Duis dictum dolor ac scelerisque commodo. Fusce sollicitudin nisi sit amet dictum placerat. Suspendisse euismod pharetra eleifend. In eros nisl, porttitor sed mauris at, consectetur aliquet mauris. Donec euismod viverra neque sed fermentum. Phasellus libero magna, accumsan ut ultricies vitae, dignissim eget metus. Donec tellus turpis, interdum eget maximus nec, hendrerit eget massa. Curabitur auctor ligula in iaculis auctor. In ultrices quam suscipit cursus finibus. Aenean id mi at dolor interdum iaculis vitae ut lorem. Nullam sed nibh fringilla, lacinia odio nec, placerat erat. In dui libero, viverra ac viverra ac, pellentesque sit amet turpis. + +Nulla in enim ex. Sed feugiat est et consectetur venenatis. Cras varius facilisis dui vel convallis. Vestibulum et elit eget tellus feugiat pellentesque. In ut ante eu purus aliquet posuere. Nulla nec ornare sem, sed luctus lorem. Nam varius iaculis odio, eget faucibus nisl ullamcorper in. Sed eget cursus felis, nec efficitur nisi. + +Vivamus commodo et sem quis pulvinar. Pellentesque libero ante, venenatis vitae ligula sit amet, ornare sollicitudin nulla. Mauris eget tellus hendrerit, pulvinar metus quis, tempor nisi. Proin magna ex, laoreet sed tortor quis, varius fermentum enim. Integer eu dolor dictum, vulputate tortor et, aliquet ligula. Vestibulum vitae justo id mauris luctus sollicitudin. Suspendisse eget auctor neque, sodales egestas lorem. Vestibulum lacinia egestas metus vitae euismod. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus ex tellus, volutpat nec pulvinar sit amet, condimentum vitae dui. Curabitur vel felis sodales, lacinia nunc iaculis, ullamcorper augue. Pellentesque consequat dolor quis eros efficitur malesuada. Nulla ut malesuada lectus. + +Morbi et tristique ante. Aliquam erat volutpat. Vivamus vitae dui nec turpis pellentesque fermentum. Quisque eget velit massa. Pellentesque tristique aliquam nisl, eu sollicitudin justo venenatis sed. Duis eleifend sem eros, ut aliquam libero porttitor id. Sed non nunc consequat, rhoncus diam eu, commodo erat. Praesent fermentum in lectus id blandit. Donec quis ipsum at justo volutpat finibus. Nulla blandit justo nulla, at mollis lacus consequat eget. Aenean sollicitudin quis eros ut ullamcorper. + +Pellentesque venenatis nulla ut mi aliquet feugiat. Cras semper vel magna nec pharetra. Integer mattis felis et sapien commodo imperdiet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis quis luctus felis. Vestibulum justo nibh, aliquam non lectus vitae, molestie placerat justo. Donec lorem nibh, gravida sit amet hendrerit ac, maximus id ipsum. Nunc ac libero sodales risus eleifend sagittis. Phasellus est massa, lobortis elementum ex sed, scelerisque consectetur neque. Nunc faucibus neque id lorem malesuada, eget convallis ex mattis. + +Sed turpis tortor, fermentum non turpis id, posuere varius nibh. Donec iaculis lorem dui. Etiam eros ante, sodales eget venenatis at, consectetur eget risus. Curabitur non aliquam ante, a pretium justo. Maecenas tempor nisl tortor, vitae dictum nisi ultrices eu. Duis eget dui ultrices, porttitor lacus sed, lobortis purus. Quisque mattis elit nec neque sagittis, sed commodo leo blandit. Mauris sodales interdum eleifend. Vestibulum condimentum consectetur augue, id luctus diam convallis et. + +Nunc suscipit risus in justo accumsan, a placerat magna tincidunt. Proin a nisl ipsum. Sed libero dui, tristique in augue quis, auctor tristique risus. Sed porttitor ex augue, eu porta augue molestie a. Duis rhoncus purus libero, eu tempus turpis condimentum at. Sed mollis nisi id lectus placerat tincidunt. Maecenas non scelerisque elit, quis rutrum orci. Donec in tellus pharetra urna ornare lobortis. Phasellus id risus at nisi varius rutrum eu ut turpis. + +Duis dictum justo quis nisl porta, eget tincidunt magna suscipit. Sed velit massa, ullamcorper eu sodales ac, pretium a massa. Duis et rutrum tortor. Nulla accumsan hendrerit sapien, cursus volutpat eros egestas eget. Donec sollicitudin at ante quis sollicitudin. Aenean blandit feugiat diam, id feugiat eros faucibus eget. Donec viverra dolor vel justo scelerisque dignissim. Nulla semper sem nunc, rhoncus semper tellus ultricies sed. Duis in ornare diam. Donec vehicula feugiat varius. Maecenas ut suscipit est. Vivamus sem sem, finibus at dolor sit amet, euismod dapibus ligula. Vestibulum fringilla odio dapibus, congue massa eget, congue sem. Donec feugiat magna eget tortor lacinia scelerisque non et ipsum. + +Suspendisse potenti. Nunc convallis sollicitudin ex eget venenatis. Sed iaculis nibh ex, vel ornare ligula congue dignissim. Quisque sollicitudin dolor ac dui vestibulum, sit amet molestie nisi aliquet. Donec at risus felis. Aenean sollicitudin metus a feugiat porta. Aenean a tortor ut dolor cursus sagittis. Vivamus consectetur porttitor nunc in facilisis. Proin sit amet mi vel lectus consectetur ultrices. + +Sed cursus lectus vitae nunc tristique, nec commodo turpis dapibus. Pellentesque luctus ex id facilisis ornare. Morbi quis placerat dolor. Donec in lectus in arcu mattis porttitor ac sit amet metus. Cras congue mauris non risus sodales, vitae feugiat ipsum bibendum. Nulla venenatis urna sed libero elementum, a cursus lorem commodo. Mauris faucibus lobortis eros nec commodo. + +Nullam suscipit ligula ullamcorper lorem commodo blandit. Nulla porta nibh quis pulvinar placerat. Vivamus eu arcu justo. Vestibulum imperdiet est ut fermentum porttitor. Pellentesque consectetur libero in sapien efficitur scelerisque. Curabitur ac erat sit amet odio aliquet dignissim. Pellentesque mi sem, rhoncus et luctus at, porttitor rutrum lectus. Vestibulum sollicitudin sollicitudin suscipit. Aenean efficitur dolor non ultrices imperdiet. Donec vel sem ex. + +Sed convallis mauris aliquam rutrum cursus. Ut tempor porttitor sodales. Etiam eu risus ac augue gravida egestas et eu dolor. Proin id magna ex. Suspendisse quis lectus quis lorem ultricies tempus. Donec porttitor velit vitae tincidunt faucibus. Aliquam vitae semper nisi. Morbi ultrices, leo non pretium dapibus, dui libero pellentesque ex, vel placerat enim ante vitae dui. Nunc varius, sem sit amet sagittis lobortis, lectus odio scelerisque mauris, ut vestibulum orci magna quis neque. Sed id congue justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris congue nisi est, malesuada mollis elit tincidunt sed. Curabitur sed ex sit amet felis tristique elementum vitae vel nibh. + +Etiam mollis pretium lobortis. Mauris augue lacus, efficitur at lacus sed, mollis tincidunt lectus. Aliquam erat volutpat. Donec at euismod elit, et mattis felis. Sed id lobortis urna. Morbi imperdiet vestibulum leo, sed maximus leo blandit eu. Aliquam semper lorem neque, nec euismod turpis mattis mollis. Quisque lobortis urna ultrices odio pretium, ac venenatis orci faucibus. Suspendisse bibendum odio ligula, sed lobortis massa pharetra nec. Donec turpis justo, iaculis at dictum ac, finibus eu libero. Maecenas quis porttitor mi, sit amet aliquet neque. + +Vivamus auctor vulputate ante, at egestas lorem. Donec eu risus in nulla mollis ultricies at et urna. Duis accumsan porta egestas. Ut vel euismod augue. Fusce convallis nulla ante, nec fringilla velit aliquet at. Nam malesuada dapibus ligula, a aliquam nibh scelerisque ac. Praesent malesuada neque et pellentesque interdum. Curabitur volutpat at turpis vitae tristique. Vivamus porttitor semper congue. Quisque suscipit lacus mi, rhoncus ultrices tortor auctor quis. Maecenas neque neque, molestie ac facilisis eget, luctus ac lorem. In ut odio ut lacus suscipit pulvinar vitae sed elit. Nulla imperdiet, sem quis euismod sagittis, dui erat luctus dolor, faucibus faucibus erat sem eget nunc. Nam accumsan placerat malesuada. Maecenas convallis finibus pulvinar. + +Cras at placerat tortor. Morbi facilisis auctor felis sit amet molestie. Donec sodales sed lorem vitae suscipit. Etiam fermentum pharetra ipsum, nec luctus orci gravida eu. Pellentesque gravida, est non condimentum tempus, mauris ligula molestie est, in congue dolor nisl vel sapien. Duis congue tempor augue, id rutrum eros porta dapibus. Etiam rutrum eget est eget vestibulum. Aenean mollis arcu vel consequat varius. Praesent at condimentum felis. Duis nec interdum nisl. Donec commodo lorem sed sapien scelerisque malesuada non eu urna. In blandit non ipsum at porta. Nam lobortis leo vitae dui auctor, non feugiat quam bibendum. Donec auctor lectus sagittis laoreet maximus. Maecenas rhoncus laoreet porttitor. Vestibulum porttitor augue ut lectus hendrerit, eget posuere mi gravida. + +Sed mattis ex in erat pulvinar, eu imperdiet magna dapibus. Etiam nisi nibh, tempus non tellus sit amet, mattis tempor odio. Quisque nec lorem feugiat, lobortis odio et, commodo nunc. Maecenas semper purus nisi, nec vehicula nibh eleifend vitae. Nulla fermentum a lectus at maximus. Phasellus finibus metus non euismod ultrices. Etiam a pulvinar ante. Quisque convallis nec metus sit amet facilisis. Praesent laoreet massa et sollicitudin laoreet. Vestibulum in mauris aliquet, convallis mi ut, elementum purus. Nulla purus nulla, sodales at hendrerit quis, tempus sed lectus. + +Nam ut laoreet neque, ut maximus nibh. Maecenas quis justo pellentesque, sollicitudin elit at, venenatis velit. Aenean nunc velit, vehicula scelerisque odio at, consectetur laoreet purus. Duis dui purus, malesuada quis ipsum sit amet, tempor interdum libero. Curabitur porta scelerisque sapien, vitae cursus diam condimentum eu. Phasellus sed orci quam. Nullam vitae dui quis purus tincidunt vestibulum. Curabitur quis nulla porta, cursus arcu non, auctor enim. Etiam sollicitudin ex id sem vehicula mollis. Morbi viverra laoreet tincidunt. Praesent ut semper dui. Nam sit amet pretium neque. Mauris vitae luctus diam, in lacinia purus. Maecenas ut placerat justo, ut porta felis. Integer eu mauris ante. + +Aenean porttitor tellus diam, tempor consequat metus efficitur id. Suspendisse ut felis at erat tempor dictum at nec sapien. Sed vestibulum interdum felis, ac mattis mauris porta in. Nunc et condimentum massa. Sed cursus dictum justo et luctus. Integer convallis enim nisl, a rutrum lectus ultricies in. Donec dapibus lacus at nulla dapibus, id sollicitudin velit hendrerit. Fusce a magna at orci mollis rutrum ac a dolor. Aliquam erat volutpat. Morbi varius porta nunc, sit amet sodales ex hendrerit commodo. Donec tincidunt tortor sapien, vitae egestas sapien vehicula eget. + +Suspendisse potenti. Donec pulvinar felis nec leo malesuada interdum. Integer posuere placerat maximus. Donec nibh ipsum, tincidunt vitae luctus vitae, bibendum at leo. Sed cursus nisl ut ex faucibus aliquet sed nec eros. Curabitur molestie posuere felis. Integer faucibus velit eget consequat iaculis. Mauris sed vulputate odio. Phasellus maximus, elit a pharetra egestas, lorem magna semper tellus, vestibulum semper diam felis at sapien. Suspendisse facilisis, nisl sit amet euismod vehicula, libero nulla vehicula dolor, quis fermentum nibh elit sit amet diam. + +Morbi lorem enim, euismod eu varius ut, scelerisque quis odio. Nam tempus vitae eros id molestie. Nunc pretium in nulla eget accumsan. Quisque mattis est ut semper aliquet. Maecenas eget diam elementum, fermentum ipsum a, euismod sapien. Duis quam ligula, cursus et velit nec, ullamcorper tincidunt magna. Donec vulputate nisl est, et ullamcorper urna tempor sit amet. + +Proin lacinia dui non turpis congue pretium. Morbi posuere metus vel purus imperdiet interdum. Morbi venenatis vel eros non ultricies. Nulla vel semper elit. Ut quis purus tincidunt, auctor justo ut, faucibus turpis. Proin quis mattis erat, at faucibus ligula. Mauris in mauris enim. Donec facilisis enim at est feugiat hendrerit. Nam vel nisi lorem. Fusce ultricies convallis diam, in feugiat tortor luctus quis. Donec tempor, leo vitae volutpat aliquam, magna elit feugiat leo, quis placerat sapien felis eget arcu. Donec ornare fermentum eleifend. Integer a est orci. + +Proin rhoncus egestas leo. Nulla ultricies porta elit quis ornare. Nunc fermentum interdum vehicula. In in ligula lorem. Donec nec arcu sit amet orci lobortis iaculis. Mauris at mollis erat, sit amet mollis tortor. Mauris laoreet justo ullamcorper porttitor auctor. Aenean sit amet aliquam lectus, id fermentum eros. Praesent urna sem, vehicula ac fermentum id, dapibus ut purus. Vestibulum vitae tempus nunc. Donec at nunc ornare metus volutpat porta at eget magna. Donec varius aliquet metus, eu lobortis risus aliquam sed. Ut dapibus fermentum velit, ac tincidunt libero faucibus at. + +In in purus auctor, feugiat massa quis, facilisis nisi. Donec dolor purus, gravida eget dolor ac, porttitor imperdiet urna. Donec faucibus placerat erat, a sagittis ante finibus ac. Sed venenatis dignissim elit, in iaculis felis posuere faucibus. Praesent sed viverra dolor. Mauris sed nulla consectetur nunc laoreet molestie in ut metus. Proin ac ex sit amet magna vulputate hendrerit ac condimentum urna. Proin ligula metus, gravida et sollicitudin facilisis, iaculis ut odio. Cras tincidunt urna et augue varius, ut facilisis urna consequat. Aenean vehicula finibus quam. Ut iaculis eu diam ac mollis. Nam mi lorem, tristique eget varius at, sodales at urna. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin vitae dictum erat, et auctor ipsum. Nullam nunc nunc, sollicitudin quis magna a, vestibulum fermentum mauris. Praesent at erat dolor. Proin laoreet tristique nulla vel efficitur. Nam sed ultrices nibh, id rutrum nunc. Curabitur eleifend a erat sit amet sollicitudin. Nullam metus quam, laoreet vitae dapibus id, placerat sed leo. Aliquam erat volutpat. Donec turpis nisl, cursus eu ex sit amet, lacinia pellentesque nisl. Sed id ipsum massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec interdum scelerisque lorem eu mattis. + +Vivamus ac tristique massa, nec facilisis nisl. Nam ipsum neque, tincidunt vel urna in, cursus imperdiet enim. Nam pellentesque egestas tempus. Morbi facilisis imperdiet libero vitae fringilla. Nam lacinia ligula at sapien facilisis malesuada. Nullam accumsan pulvinar sem, et cursus libero porta sit amet. Curabitur vulputate erat elit, ut pulvinar erat maximus vel. + +Cras aliquet metus ut purus sagittis, vel venenatis ante consectetur. Pellentesque nulla lacus, viverra viverra mattis non, placerat vitae nibh. Donec enim turpis, accumsan sit amet tincidunt eu, imperdiet non metus. Morbi ipsum eros, tincidunt vel est ac, tristique porttitor nibh. Praesent ut ullamcorper mauris. Sed laoreet sit amet diam congue venenatis. Integer porta purus nec orci sagittis posuere. + +Donec vehicula mauris eget lacus mollis venenatis et sed nibh. Nam sodales ligula ipsum, scelerisque lacinia ligula sagittis in. Nam sit amet ipsum at erat malesuada congue. Aenean ut sollicitudin sapien. Etiam at tempor odio. Mauris vitae purus ut magna suscipit consequat. Vivamus quis sapien neque. Nulla vulputate sem sit amet massa pellentesque, eleifend tristique ligula egestas. Suspendisse tincidunt gravida mi, in pulvinar lectus egestas non. Aenean imperdiet ex sit amet nunc sollicitudin porta. Integer justo odio, ultricies at interdum in, rhoncus vitae sem. Sed porttitor arcu quis purus aliquet hendrerit. Praesent tempor tortor at dolor dictum pulvinar. Nulla aliquet nunc non ligula scelerisque accumsan. Donec nulla justo, congue vitae massa in, faucibus hendrerit magna. Donec non egestas purus. + +Vivamus iaculis, lacus efficitur faucibus porta, dui nulla facilisis ligula, ut sodales odio nunc id sapien. Cras viverra auctor ipsum, dapibus mattis neque dictum sed. Sed convallis fermentum molestie. Nulla facilisi turpis duis. diff --git a/src/vs/platform/history/common/history.ts b/src/vs/platform/history/common/history.ts deleted file mode 100644 index e2c725ab6cb..00000000000 --- a/src/vs/platform/history/common/history.ts +++ /dev/null @@ -1,41 +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 { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { URI } from 'vs/base/common/uri'; - -export interface IRecentlyOpened { - workspaces: Array; - files: IRecentFile[]; -} - -export type IRecent = IRecentWorkspace | IRecentFolder | IRecentFile; - -export interface IRecentWorkspace { - workspace: IWorkspaceIdentifier; - label?: string; -} - -export interface IRecentFolder { - folderUri: ISingleFolderWorkspaceIdentifier; - label?: string; -} - -export interface IRecentFile { - fileUri: URI; - label?: string; -} - -export function isRecentWorkspace(curr: IRecent): curr is IRecentWorkspace { - return curr.hasOwnProperty('workspace'); -} - -export function isRecentFolder(curr: IRecent): curr is IRecentFolder { - return curr.hasOwnProperty('folderUri'); -} - -export function isRecentFile(curr: IRecent): curr is IRecentFile { - return curr.hasOwnProperty('fileUri'); -} diff --git a/src/vs/platform/history/common/historyStorage.ts b/src/vs/platform/history/common/historyStorage.ts deleted file mode 100644 index b026460963d..00000000000 --- a/src/vs/platform/history/common/historyStorage.ts +++ /dev/null @@ -1,129 +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 { UriComponents, URI } from 'vs/base/common/uri'; -import { IRecentlyOpened, isRecentFolder } from 'vs/platform/history/common/history'; -import { ILogService } from 'vs/platform/log/common/log'; - -interface ISerializedRecentlyOpened { - workspaces3: Array; // workspace or URI.toString() // added in 1.32 - workspaceLabels?: Array; // added in 1.33 - files2: string[]; // files as URI.toString() // added in 1.32 - fileLabels?: Array; // added in 1.33 -} - -interface ILegacySerializedRecentlyOpened { - workspaces2: Array; // legacy, configPath as file path - workspaces: Array; // legacy (UriComponents was also supported for a few insider builds) - files: string[]; // files as paths -} - -interface ISerializedWorkspace { id: string; configURIPath: string; } -interface ILegacySerializedWorkspace { id: string; configPath: string; } - -function isLegacySerializedWorkspace(curr: any): curr is ILegacySerializedWorkspace { - return typeof curr === 'object' && typeof curr['id'] === 'string' && typeof curr['configPath'] === 'string'; -} - -function isUriComponents(curr: any): curr is UriComponents { - return curr && typeof curr['path'] === 'string' && typeof curr['scheme'] === 'string'; -} - -export type RecentlyOpenedStorageData = object; - -export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefined, logService: ILogService): IRecentlyOpened { - const result: IRecentlyOpened = { workspaces: [], files: [] }; - if (data) { - const restoreGracefully = function (entries: T[], func: (entry: T, index: number) => void) { - for (let i = 0; i < entries.length; i++) { - try { - func(entries[i], i); - } catch (e) { - logService.warn(`Error restoring recent entry ${JSON.stringify(entries[i])}: ${e.toString()}. Skip entry.`); - } - } - }; - - const storedRecents = data as ISerializedRecentlyOpened & ILegacySerializedRecentlyOpened; - if (Array.isArray(storedRecents.workspaces3)) { - restoreGracefully(storedRecents.workspaces3, (workspace, i) => { - const label: string | undefined = (Array.isArray(storedRecents.workspaceLabels) && storedRecents.workspaceLabels[i]) || undefined; - if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configURIPath === 'string') { - result.workspaces.push({ label, workspace: { id: workspace.id, configPath: URI.parse(workspace.configURIPath) } }); - } else if (typeof workspace === 'string') { - result.workspaces.push({ label, folderUri: URI.parse(workspace) }); - } - }); - } else if (Array.isArray(storedRecents.workspaces2)) { - restoreGracefully(storedRecents.workspaces2, workspace => { - if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configPath === 'string') { - result.workspaces.push({ workspace: { id: workspace.id, configPath: URI.file(workspace.configPath) } }); - } else if (typeof workspace === 'string') { - result.workspaces.push({ folderUri: URI.parse(workspace) }); - } - }); - } else if (Array.isArray(storedRecents.workspaces)) { - // TODO@martin legacy support can be removed at some point (6 month?) - // format of 1.25 and before - restoreGracefully(storedRecents.workspaces, workspace => { - if (typeof workspace === 'string') { - result.workspaces.push({ folderUri: URI.file(workspace) }); - } else if (isLegacySerializedWorkspace(workspace)) { - result.workspaces.push({ workspace: { id: workspace.id, configPath: URI.file(workspace.configPath) } }); - } else if (isUriComponents(workspace)) { - // added by 1.26-insiders - result.workspaces.push({ folderUri: URI.revive(workspace) }); - } - }); - } - if (Array.isArray(storedRecents.files2)) { - restoreGracefully(storedRecents.files2, (file, i) => { - const label: string | undefined = (Array.isArray(storedRecents.fileLabels) && storedRecents.fileLabels[i]) || undefined; - if (typeof file === 'string') { - result.files.push({ label, fileUri: URI.parse(file) }); - } - }); - } else if (Array.isArray(storedRecents.files)) { - restoreGracefully(storedRecents.files, file => { - if (typeof file === 'string') { - result.files.push({ fileUri: URI.file(file) }); - } - }); - } - } - - return result; -} - -export function toStoreData(recents: IRecentlyOpened): RecentlyOpenedStorageData { - const serialized: ISerializedRecentlyOpened = { workspaces3: [], files2: [] }; - - let hasLabel = false; - const workspaceLabels: (string | null)[] = []; - for (const recent of recents.workspaces) { - if (isRecentFolder(recent)) { - serialized.workspaces3.push(recent.folderUri.toString()); - } else { - serialized.workspaces3.push({ id: recent.workspace.id, configURIPath: recent.workspace.configPath.toString() }); - } - workspaceLabels.push(recent.label || null); - hasLabel = hasLabel || !!recent.label; - } - if (hasLabel) { - serialized.workspaceLabels = workspaceLabels; - } - - hasLabel = false; - const fileLabels: (string | null)[] = []; - for (const recent of recents.files) { - serialized.files2.push(recent.fileUri.toString()); - fileLabels.push(recent.label || null); - hasLabel = hasLabel || !!recent.label; - } - if (hasLabel) { - serialized.fileLabels = fileLabels; - } - - return serialized; -} diff --git a/src/vs/platform/instantiation/common/instantiation.ts b/src/vs/platform/instantiation/common/instantiation.ts index 735c035934c..926d3c4653f 100644 --- a/src/vs/platform/instantiation/common/instantiation.ts +++ b/src/vs/platform/instantiation/common/instantiation.ts @@ -22,40 +22,42 @@ export namespace _util { // --- interfaces ------ +type BrandedService = { _serviceBrand: undefined }; + export interface IConstructorSignature0 { - new(...services: { _serviceBrand: undefined; }[]): T; + new(...services: BrandedService[]): T; } export interface IConstructorSignature1 { - new(first: A1, ...services: { _serviceBrand: undefined; }[]): T; + new(first: A1, ...services: BrandedService[]): T; } export interface IConstructorSignature2 { - new(first: A1, second: A2, ...services: { _serviceBrand: undefined; }[]): T; + new(first: A1, second: A2, ...services: BrandedService[]): T; } export interface IConstructorSignature3 { - new(first: A1, second: A2, third: A3, ...services: { _serviceBrand: undefined; }[]): T; + new(first: A1, second: A2, third: A3, ...services: BrandedService[]): T; } export interface IConstructorSignature4 { - new(first: A1, second: A2, third: A3, fourth: A4, ...services: { _serviceBrand: undefined; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, ...services: BrandedService[]): T; } export interface IConstructorSignature5 { - new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, ...services: { _serviceBrand: undefined; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, ...services: BrandedService[]): T; } export interface IConstructorSignature6 { - new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, ...services: { _serviceBrand: undefined; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, ...services: BrandedService[]): T; } export interface IConstructorSignature7 { - new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, ...services: { _serviceBrand: undefined; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, ...services: BrandedService[]): T; } export interface IConstructorSignature8 { - new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8, ...services: { _serviceBrand: undefined; }[]): T; + new(first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8, ...services: BrandedService[]): T; } export interface ServicesAccessor { @@ -65,6 +67,22 @@ export interface ServicesAccessor { export const IInstantiationService = createDecorator('instantiationService'); +/** + * Given a list of arguments as a tuple, attempt to extract the leading, non-service arguments + * to their own tuple. + */ +type GetLeadingNonServiceArgs = + Args extends [...BrandedService[]] ? [] + : Args extends [infer A1, ...BrandedService[]] ? [A1] + : Args extends [infer A1, infer A2, ...BrandedService[]] ? [A1, A2] + : Args extends [infer A1, infer A2, infer A3, ...BrandedService[]] ? [A1, A2, A3] + : Args extends [infer A1, infer A2, infer A3, infer A4, ...BrandedService[]] ? [A1, A2, A3, A4] + : Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, ...BrandedService[]] ? [A1, A2, A3, A4, A5] + : Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, ...BrandedService[]] ? [A1, A2, A3, A4, A5, A6] + : Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, ...BrandedService[]] ? [A1, A2, A3, A4, A5, A6, A7] + : Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8, ...BrandedService[]] ? [A1, A2, A3, A4, A5, A6, A7, A8] + : never; + export interface IInstantiationService { _serviceBrand: undefined; @@ -83,15 +101,7 @@ export interface IInstantiationService { createInstance(descriptor: descriptors.SyncDescriptor7, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): T; createInstance(descriptor: descriptors.SyncDescriptor8, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): T; - createInstance(ctor: IConstructorSignature0): T; - createInstance(ctor: IConstructorSignature1, first: A1): T; - createInstance(ctor: IConstructorSignature2, first: A1, second: A2): T; - createInstance(ctor: IConstructorSignature3, first: A1, second: A2, third: A3): T; - createInstance(ctor: IConstructorSignature4, first: A1, second: A2, third: A3, fourth: A4): T; - createInstance(ctor: IConstructorSignature5, first: A1, second: A2, third: A3, fourth: A4, fifth: A5): T; - createInstance(ctor: IConstructorSignature6, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6): T; - createInstance(ctor: IConstructorSignature7, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7): T; - createInstance(ctor: IConstructorSignature8, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8): T; + createInstance any, R extends InstanceType>(t: Ctor, ...args: GetLeadingNonServiceArgs>): R; /** * diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index c817c55f700..44be0d24797 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -206,7 +206,7 @@ export class InstantiationService implements IInstantiationService { } else if (this._parent) { return this._parent._createServiceInstanceWithOwner(id, ctor, args, supportsDelayedInstantiation, _trace); } else { - throw new Error('illegalState - creating UNKNOWN service instance'); + throw new Error(`illegalState - creating UNKNOWN service instance ${ctor.name}`); } } @@ -219,13 +219,23 @@ export class InstantiationService implements IInstantiationService { // Return a proxy object that's backed by an idle value. That // strategy is to instantiate services in our idle time or when actually // needed but not when injected into a consumer - const idle = new IdleValue(() => this._createInstance(ctor, args, _trace)); + const idle = new IdleValue(() => this._createInstance(ctor, args, _trace)); return new Proxy(Object.create(null), { - get(_target: T, prop: PropertyKey): any { - return (idle.getValue() as any)[prop]; + get(target: any, key: PropertyKey): any { + if (key in target) { + return target[key]; + } + let obj = idle.getValue(); + let prop = obj[key]; + if (typeof prop !== 'function') { + return prop; + } + prop = prop.bind(obj); + target[key] = prop; + return prop; }, set(_target: T, p: PropertyKey, value: any): boolean { - (idle.getValue() as any)[p] = value; + idle.getValue()[p] = value; return true; } }); @@ -241,7 +251,7 @@ const enum TraceType { class Trace { - private static _None = new class extends Trace { + private static readonly _None = new class extends Trace { constructor() { super(-1, null); } stop() { } branch() { return this; } diff --git a/src/vs/platform/ipc/electron-browser/sharedProcessService.ts b/src/vs/platform/ipc/electron-browser/sharedProcessService.ts index bfeaf0ac653..d02e7d8e005 100644 --- a/src/vs/platform/ipc/electron-browser/sharedProcessService.ts +++ b/src/vs/platform/ipc/electron-browser/sharedProcessService.ts @@ -4,12 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { Client } from 'vs/base/parts/ipc/common/ipc.net'; -import { connect } from 'vs/base/parts/ipc/node/ipc.net'; -import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; export const ISharedProcessService = createDecorator('sharedProcessService'); @@ -23,38 +18,3 @@ export interface ISharedProcessService { whenSharedProcessReady(): Promise; toggleSharedProcessWindow(): Promise; } - -export class SharedProcessService implements ISharedProcessService { - - _serviceBrand: undefined; - - private withSharedProcessConnection: Promise>; - private sharedProcessMainChannel: IChannel; - - constructor( - @IMainProcessService mainProcessService: IMainProcessService, - @IWindowService windowService: IWindowService, - @IEnvironmentService environmentService: IEnvironmentService - ) { - this.sharedProcessMainChannel = mainProcessService.getChannel('sharedProcess'); - - this.withSharedProcessConnection = this.whenSharedProcessReady() - .then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.windowId}`)); - } - - whenSharedProcessReady(): Promise { - return this.sharedProcessMainChannel.call('whenSharedProcessReady'); - } - - getChannel(channelName: string): IChannel { - return getDelayedChannel(this.withSharedProcessConnection.then(connection => connection.getChannel(channelName))); - } - - registerChannel(channelName: string, channel: IServerChannel): void { - this.withSharedProcessConnection.then(connection => connection.registerChannel(channelName, channel)); - } - - toggleSharedProcessWindow(): Promise { - return this.sharedProcessMainChannel.call('toggleSharedProcessWindow'); - } -} diff --git a/src/vs/platform/ipc/electron-main/sharedProcessMainService.ts b/src/vs/platform/ipc/electron-main/sharedProcessMainService.ts index bab9a00f90d..4fb5318cc2b 100644 --- a/src/vs/platform/ipc/electron-main/sharedProcessMainService.ts +++ b/src/vs/platform/ipc/electron-main/sharedProcessMainService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { ISharedProcess } from 'vs/platform/windows/electron-main/windows'; export const ISharedProcessMainService = createDecorator('sharedProcessMainService'); @@ -15,6 +14,12 @@ export interface ISharedProcessMainService { whenSharedProcessReady(): Promise; toggleSharedProcessWindow(): Promise; } + +export interface ISharedProcess { + whenReady(): Promise; + toggle(): void; +} + export class SharedProcessMainService implements ISharedProcessMainService { _serviceBrand: undefined; diff --git a/src/vs/platform/ipc/node/simpleIpcProxy.ts b/src/vs/platform/ipc/node/simpleIpcProxy.ts deleted file mode 100644 index 84e9beee2a8..00000000000 --- a/src/vs/platform/ipc/node/simpleIpcProxy.ts +++ /dev/null @@ -1,101 +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 { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { revive } from 'vs/base/common/marshalling'; - -// -// Use both `SimpleServiceProxyChannel` and `createSimpleChannelProxy` -// for a very basic process <=> process communication over methods. -// - -export type AddContextToFunctions = { - // For every property: IF property is a FUNCTION ADD context as first parameter and original parameters afterwards with same return type, otherwise preserve as is - [K in keyof Target]: Target[K] extends (...args: any) => any ? (context: Context, ...args: Parameters) => ReturnType : Target[K] -}; - -interface ISimpleChannelProxyContext { - __$simpleIPCContextMarker: boolean; - proxyContext: unknown; -} - -function serializeContext(proxyContext?: unknown): ISimpleChannelProxyContext | undefined { - if (proxyContext) { - return { __$simpleIPCContextMarker: true, proxyContext }; - } - - return undefined; -} - -function deserializeContext(candidate?: ISimpleChannelProxyContext | undefined): unknown | undefined { - if (candidate && candidate.__$simpleIPCContextMarker === true) { - return candidate.proxyContext; - } - - return undefined; -} - -export class SimpleServiceProxyChannel implements IServerChannel { - - private service: { [key: string]: unknown }; - - constructor(service: unknown) { - this.service = service as { [key: string]: unknown }; - } - - listen(_: unknown, event: string): Event { - throw new Error(`Events are currently unsupported by SimpleServiceProxyChannel: ${event}`); - } - - call(_: unknown, command: string, args?: any[]): Promise { - const target = this.service[command]; - if (typeof target === 'function') { - if (Array.isArray(args)) { - - // Deserialize context if any - const context = deserializeContext(args[0]); - if (context) { - args[0] = context; - } - - // Revive: handles URIs and RegExp - for (let i = 0; i < args.length; i++) { - args[i] = revive(args[i]); - } - } - - return target.apply(this.service, args); - } - - throw new Error(`Method not found: ${command}`); - } -} - -export function createSimpleChannelProxy(channel: IChannel, context?: unknown): T { - const serializedContext = serializeContext(context); - - return new Proxy({}, { - get(_target, propKey, _receiver) { - if (typeof propKey === 'string') { - return async function (...args: any[]) { - - // Serialize context if any - let methodArgs: any[]; - if (serializedContext) { - methodArgs = [context, ...args]; - } else { - methodArgs = args; - } - - // Revive: handles URIs and RegExp - return revive(await channel.call(propKey, methodArgs)); - }; - } - - throw new Error(`Unable to provide main channel proxy implementation for: ${String(propKey)}`); - } - }) as T; -} diff --git a/src/vs/platform/issue/electron-main/issueMainService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts index 44a2a82e0bb..1307534e24a 100644 --- a/src/vs/platform/issue/electron-main/issueMainService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -7,15 +7,16 @@ import { localize } from 'vs/nls'; import * as objects from 'vs/base/common/objects'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/node/issue'; -import { BrowserWindow, ipcMain, screen, dialog, IpcMainEvent, Display } from 'electron'; +import { BrowserWindow, ipcMain, screen, IpcMainEvent, Display, shell } from 'electron'; import { ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService'; import { PerformanceInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; -import { IWindowState, IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; +import { IWindowState } from 'vs/platform/windows/electron-main/windows'; import { listProcesses } from 'vs/base/node/ps'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; const DEFAULT_BACKGROUND_COLOR = '#1E1E1E'; @@ -33,7 +34,7 @@ export class IssueMainService implements IIssueService { @ILaunchMainService private readonly launchMainService: ILaunchMainService, @ILogService private readonly logService: ILogService, @IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService, - @IWindowsMainService private readonly windowsMainService: IWindowsMainService + @IDialogMainService private readonly dialogMainService: IDialogMainService ) { this.registerListeners(); } @@ -80,16 +81,16 @@ export class IssueMainService implements IIssueService { ipcMain.on('vscode:issueReporterClipboard', (event: IpcMainEvent) => { const messageOptions = { - message: localize('issueReporterWriteToClipboard', "There is too much data to send to GitHub. Would you like to write the information to the clipboard so that it can be pasted?"), + message: localize('issueReporterWriteToClipboard', "There is too much data to send to GitHub directly. The data will be copied to the clipboard, please paste it into the GitHub issue page that is opened."), type: 'warning', buttons: [ - localize('yes', "Yes"), + localize('ok', "OK"), localize('cancel', "Cancel") ] }; if (this._issueWindow) { - dialog.showMessageBox(this._issueWindow, messageOptions) + this.dialogMainService.showMessageBox(messageOptions, this._issueWindow) .then(result => { event.sender.send('vscode:issueReporterClipboardResponse', result.response === 0); }); @@ -113,7 +114,7 @@ export class IssueMainService implements IIssueService { }; if (this._issueWindow) { - dialog.showMessageBox(this._issueWindow, messageOptions) + this.dialogMainService.showMessageBox(messageOptions, this._issueWindow) .then(result => { if (result.response === 0) { if (this._issueWindow) { @@ -146,7 +147,7 @@ export class IssueMainService implements IIssueService { }); ipcMain.on('vscode:openExternal', (_: unknown, arg: string) => { - this.windowsMainService.openExternal(arg); + shell.openExternal(arg); }); ipcMain.on('vscode:closeIssueReporter', (event: IpcMainEvent) => { @@ -155,6 +156,12 @@ export class IssueMainService implements IIssueService { } }); + ipcMain.on('vscode:closeProcessExplorer', (event: IpcMainEvent) => { + if (this._processExplorerWindow) { + this._processExplorerWindow.close(); + } + }); + ipcMain.on('windowsInfoRequest', (event: IpcMainEvent) => { this.launchMainService.getMainProcessInfo().then(info => { event.sender.send('vscode:windowsInfoResponse', info.windows); diff --git a/src/vs/platform/keybinding/common/keybindingsRegistry.ts b/src/vs/platform/keybinding/common/keybindingsRegistry.ts index 3c30daf3ab4..5c3de02794b 100644 --- a/src/vs/platform/keybinding/common/keybindingsRegistry.ts +++ b/src/vs/platform/keybinding/common/keybindingsRegistry.ts @@ -38,6 +38,7 @@ export interface IKeybindings { export interface IKeybindingRule extends IKeybindings { id: string; weight: number; + args?: any; when: ContextKeyExpr | null | undefined; } @@ -132,7 +133,7 @@ class KeybindingsRegistryImpl implements IKeybindingsRegistry { if (actualKb && actualKb.primary) { const kk = createKeybinding(actualKb.primary, OS); if (kk) { - this._registerDefaultKeybinding(kk, rule.id, undefined, rule.weight, 0, rule.when); + this._registerDefaultKeybinding(kk, rule.id, rule.args, rule.weight, 0, rule.when); } } @@ -141,7 +142,7 @@ class KeybindingsRegistryImpl implements IKeybindingsRegistry { const k = actualKb.secondary[i]; const kk = createKeybinding(k, OS); if (kk) { - this._registerDefaultKeybinding(kk, rule.id, undefined, rule.weight, -i - 1, rule.when); + this._registerDefaultKeybinding(kk, rule.id, rule.args, rule.weight, -i - 1, rule.when); } } } diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index 84a31d13438..73f80cb4f68 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -159,7 +159,8 @@ suite('AbstractKeybindingService', () => { statusMessageCallsDisposed!.push(message); } }; - } + }, + setFilter() { } }; let resolver = new KeybindingResolver(items, []); diff --git a/src/vs/platform/launch/electron-main/launchMainService.ts b/src/vs/platform/launch/electron-main/launchMainService.ts index b6f7fbbc094..9d52a59e7b8 100644 --- a/src/vs/platform/launch/electron-main/launchMainService.ts +++ b/src/vs/platform/launch/electron-main/launchMainService.ts @@ -3,7 +3,6 @@ * 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 { ILogService } from 'vs/platform/log/common/log'; import { IURLService } from 'vs/platform/url/common/url'; import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform'; @@ -16,7 +15,6 @@ import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/wor import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { URI } from 'vs/base/common/uri'; import { BrowserWindow, ipcMain, Event as IpcEvent, app } from 'electron'; -import { Event } from 'vs/base/common/event'; import { coalesce } from 'vs/base/common/arrays'; import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; import { IMainProcessInfo, IWindowInfo } from 'vs/platform/launch/common/launch'; @@ -60,64 +58,6 @@ export interface ILaunchMainService { getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]>; } -export class LaunchChannel implements IServerChannel { - - constructor(private service: ILaunchMainService) { } - - listen(_: unknown, event: string): Event { - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg: any): Promise { - switch (command) { - case 'start': - const { args, userEnv } = arg as IStartArguments; - return this.service.start(args, userEnv); - - case 'get-main-process-id': - return this.service.getMainProcessId(); - - case 'get-main-process-info': - return this.service.getMainProcessInfo(); - - case 'get-logs-path': - return this.service.getLogsPath(); - - case 'get-remote-diagnostics': - return this.service.getRemoteDiagnostics(arg); - } - - throw new Error(`Call not found: ${command}`); - } -} - -export class LaunchChannelClient implements ILaunchMainService { - - _serviceBrand: undefined; - - constructor(private channel: IChannel) { } - - start(args: ParsedArgs, userEnv: IProcessEnvironment): Promise { - return this.channel.call('start', { args, userEnv }); - } - - getMainProcessId(): Promise { - return this.channel.call('get-main-process-id', null); - } - - getMainProcessInfo(): Promise { - return this.channel.call('get-main-process-info', null); - } - - getLogsPath(): Promise { - return this.channel.call('get-logs-path', null); - } - - getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise { - return this.channel.call('get-remote-diagnostics', options); - } -} - export class LaunchMainService implements ILaunchMainService { _serviceBrand: undefined; @@ -188,7 +128,7 @@ export class LaunchMainService implements ILaunchMainService { // Otherwise check for settings else { const windowConfig = this.configurationService.getValue('window'); - const openWithoutArgumentsInNewWindowConfig = (windowConfig && windowConfig.openWithoutArgumentsInNewWindow) || 'default' /* default */; + const openWithoutArgumentsInNewWindowConfig = windowConfig?.openWithoutArgumentsInNewWindow || 'default' /* default */; switch (openWithoutArgumentsInNewWindowConfig) { case 'on': openNewWindow = true; @@ -201,6 +141,7 @@ export class LaunchMainService implements ILaunchMainService { } } + // Open new Window if (openNewWindow) { usedWindows = this.windowsMainService.open({ context, @@ -210,8 +151,18 @@ export class LaunchMainService implements ILaunchMainService { forceEmpty: true, waitMarkerFileURI }); - } else { - usedWindows = [this.windowsMainService.focusLastActive(args, context)]; + } + + // Focus existing window or open if none opened + else { + const lastActive = this.windowsMainService.getLastActiveWindow(); + if (lastActive) { + lastActive.focus(); + + usedWindows = [lastActive]; + } else { + usedWindows = this.windowsMainService.open({ context, cli: args, forceEmpty: true }); + } } } @@ -237,7 +188,7 @@ export class LaunchMainService implements ILaunchMainService { // In addition, we poll for the wait marker file to be deleted to return. if (waitMarkerFileURI && usedWindows.length === 1 && usedWindows[0]) { return Promise.race([ - this.windowsMainService.waitForWindowCloseOrLoad(usedWindows[0].id), + usedWindows[0].whenClosedOrLoaded, whenDeleted(waitMarkerFileURI.fsPath) ]).then(() => undefined, () => undefined); } @@ -283,7 +234,8 @@ export class LaunchMainService implements ILaunchMainService { const windows = this.windowsMainService.getWindows(); const promises: Promise[] = windows.map(window => { return new Promise((resolve, reject) => { - if (window.remoteAuthority) { + const remoteAuthority = window.remoteAuthority; + if (remoteAuthority) { const replyChannel = `vscode:getDiagnosticInfoResponse${window.id}`; const args: IDiagnosticInfoOptions = { includeProcesses: options.includeProcesses, @@ -295,14 +247,14 @@ export class LaunchMainService implements ILaunchMainService { ipcMain.once(replyChannel, (_: IpcEvent, data: IRemoteDiagnosticInfo) => { // No data is returned if getting the connection fails. if (!data) { - resolve({ hostName: window.remoteAuthority!, errorMessage: `Unable to resolve connection to '${window.remoteAuthority}'.` }); + resolve({ hostName: remoteAuthority, errorMessage: `Unable to resolve connection to '${remoteAuthority}'.` }); } resolve(data); }); setTimeout(() => { - resolve({ hostName: window.remoteAuthority!, errorMessage: `Fetching remote diagnostics for '${window.remoteAuthority}' timed out.` }); + resolve({ hostName: remoteAuthority, errorMessage: `Fetching remote diagnostics for '${remoteAuthority}' timed out.` }); }, 5000); } else { resolve(); diff --git a/src/vs/platform/lifecycle/common/lifecycleService.ts b/src/vs/platform/lifecycle/common/lifecycleService.ts index ea8b52b2492..1b2cb90c8af 100644 --- a/src/vs/platform/lifecycle/common/lifecycleService.ts +++ b/src/vs/platform/lifecycle/common/lifecycleService.ts @@ -23,7 +23,7 @@ export abstract class AbstractLifecycleService extends Disposable implements ILi protected readonly _onShutdown = this._register(new Emitter()); readonly onShutdown: Event = this._onShutdown.event; - protected _startupKind: StartupKind; + protected _startupKind: StartupKind = StartupKind.NewWindow; get startupKind(): StartupKind { return this._startupKind; } private _phase: LifecyclePhase = LifecyclePhase.Starting; diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts index dc31d3afab2..52c79607c22 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts @@ -5,7 +5,7 @@ import { ipcMain as ipc, app } from 'electron'; import { ILogService } from 'vs/platform/log/common/log'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { Event, Emitter } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; @@ -13,6 +13,7 @@ import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { Disposable } from 'vs/base/common/lifecycle'; import { Barrier } from 'vs/base/common/async'; +import { ParsedArgs } from 'vs/platform/environment/common/environment'; export const ILifecycleMainService = createDecorator('lifecycleMainService'); @@ -82,6 +83,11 @@ export interface ILifecycleMainService { */ readonly onBeforeWindowUnload: Event; + /** + * Reload a window. All lifecycle event handlers are triggered. + */ + reload(window: ICodeWindow, cli?: ParsedArgs): Promise; + /** * Unload a window for the provided reason. All lifecycle event handlers are triggered. */ @@ -360,6 +366,15 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe }); } + async reload(window: ICodeWindow, cli?: ParsedArgs): Promise { + + // Only reload when the window has not vetoed this + const veto = await this.unload(window, UnloadReason.RELOAD); + if (!veto) { + window.reload(undefined, cli); + } + } + async unload(window: ICodeWindow, reason: UnloadReason): Promise { // Always allow to unload a window that is not yet ready @@ -489,11 +504,11 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe this.logService.trace('Lifecycle#relaunch()'); const args = process.argv.slice(1); - if (options && options.addArgs) { + if (options?.addArgs) { args.push(...options.addArgs); } - if (options && options.removeArgs) { + if (options?.removeArgs) { for (const a of options.removeArgs) { const idx = args.indexOf(a); if (idx >= 0) { diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index e3c42e0b054..8401b843fef 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -430,7 +430,7 @@ export class WorkbenchTree extends Tree { constructor( container: HTMLElement, configuration: ITreeConfiguration, - options: ITreeOptions, + options: ITreeOptions | undefined, @IContextKeyService contextKeyService: IContextKeyService, @IListService listService: IListService, @IThemeService themeService: IThemeService, @@ -798,9 +798,9 @@ export class WorkbenchObjectTree, TFilterData = void> ) { const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService); super(user, container, delegate, renderers, treeOptions); - this.disposables.push(disposable); + this.disposables.add(disposable); this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService); - this.disposables.push(this.internals); + this.disposables.add(this.internals); } } @@ -825,9 +825,9 @@ export class WorkbenchCompressibleObjectTree, TFilter ) { const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService); super(user, container, delegate, renderers, treeOptions); - this.disposables.push(disposable); + this.disposables.add(disposable); this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService); - this.disposables.push(this.internals); + this.disposables.add(this.internals); } } @@ -853,9 +853,9 @@ export class WorkbenchDataTree extends DataTree extends Async ) { const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService); super(user, container, delegate, renderers, dataSource, treeOptions); - this.disposables.push(disposable); + this.disposables.add(disposable); this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService); - this.disposables.push(this.internals); + this.disposables.add(this.internals); } } @@ -910,9 +910,9 @@ export class WorkbenchCompressibleAsyncDataTree e ) { const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService); super(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions); - this.disposables.push(disposable); + this.disposables.add(disposable); this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService); - this.disposables.push(this.internals); + this.disposables.add(this.internals); } } @@ -954,6 +954,7 @@ function workbenchTreeDataPreamble { return this.channel.listen('onDidLanguagesChange'); } - - getLanguageIds(type?: LanguageType): Promise { - return this.channel.call('getLanguageIds', type); - } -} diff --git a/src/vs/platform/localizations/node/localizationsIpc.ts b/src/vs/platform/localizations/node/localizationsIpc.ts deleted file mode 100644 index 5b360321d39..00000000000 --- a/src/vs/platform/localizations/node/localizationsIpc.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 { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Event } from 'vs/base/common/event'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; - -export class LocalizationsChannel implements IServerChannel { - - onDidLanguagesChange: Event; - - constructor(private service: ILocalizationsService) { - this.onDidLanguagesChange = Event.buffer(service.onDidLanguagesChange, true); - } - - listen(_: unknown, event: string): Event { - switch (event) { - case 'onDidLanguagesChange': return this.onDidLanguagesChange; - } - - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'getLanguageIds': return this.service.getLanguageIds(arg); - } - - throw new Error(`Call not found: ${command}`); - } -} diff --git a/src/vs/platform/log/common/bufferLog.ts b/src/vs/platform/log/common/bufferLog.ts index bdf382bd1e1..aa34008245a 100644 --- a/src/vs/platform/log/common/bufferLog.ts +++ b/src/vs/platform/log/common/bufferLog.ts @@ -7,7 +7,7 @@ import { ILogService, LogLevel, AbstractLogService, DEFAULT_LOG_LEVEL } from 'vs interface ILog { level: LogLevel; - args: IArguments; + args: any[]; } function getLogFunction(logger: ILogService, level: LogLevel): Function { @@ -49,7 +49,7 @@ export class BufferLogService extends AbstractLogService implements ILogService this.buffer = []; } - private _log(level: LogLevel, args: IArguments): void { + private _log(level: LogLevel, ...args: any[]): void { if (this._logger) { const fn = getLogFunction(this._logger, level); fn.apply(this._logger, args); @@ -58,28 +58,28 @@ export class BufferLogService extends AbstractLogService implements ILogService } } - trace(): void { - this._log(LogLevel.Trace, arguments); + trace(message: string, ...args: any[]): void { + this._log(LogLevel.Trace, message, ...args); } - debug(): void { - this._log(LogLevel.Debug, arguments); + debug(message: string, ...args: any[]): void { + this._log(LogLevel.Debug, message, ...args); } - info(): void { - this._log(LogLevel.Info, arguments); + info(message: string, ...args: any[]): void { + this._log(LogLevel.Info, message, ...args); } - warn(): void { - this._log(LogLevel.Warning, arguments); + warn(message: string, ...args: any[]): void { + this._log(LogLevel.Warning, message, ...args); } - error(): void { - this._log(LogLevel.Error, arguments); + error(message: string | Error, ...args: any[]): void { + this._log(LogLevel.Error, message, ...args); } - critical(): void { - this._log(LogLevel.Critical, arguments); + critical(message: string | Error, ...args: any[]): void { + this._log(LogLevel.Critical, message, ...args); } dispose(): void { @@ -87,4 +87,10 @@ export class BufferLogService extends AbstractLogService implements ILogService this._logger.dispose(); } } + + flush(): void { + if (this._logger) { + this._logger.flush(); + } + } } diff --git a/src/vs/platform/log/common/fileLogService.ts b/src/vs/platform/log/common/fileLogService.ts index f9b600063bf..e8bc1ae9005 100644 --- a/src/vs/platform/log/common/fileLogService.ts +++ b/src/vs/platform/log/common/fileLogService.ts @@ -3,12 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log'; +import { ILogService, LogLevel, AbstractLogService, ILoggerService, ILogger } from 'vs/platform/log/common/log'; import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { Queue } from 'vs/base/common/async'; import { VSBuffer } from 'vs/base/common/buffer'; import { dirname, joinPath, basename } from 'vs/base/common/resources'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; const MAX_FILE_SIZE = 1024 * 1024 * 5; @@ -16,6 +18,7 @@ export class FileLogService extends AbstractLogService implements ILogService { _serviceBrand: undefined; + private readonly initializePromise: Promise; private readonly queue: Queue; private backupIndex: number = 1; @@ -28,6 +31,7 @@ export class FileLogService extends AbstractLogService implements ILogService { super(); this.setLevel(level); this.queue = this._register(new Queue()); + this.initializePromise = this.initialize(); } trace(): void { @@ -74,16 +78,20 @@ export class FileLogService extends AbstractLogService implements ILogService { } } - flush(): Promise { - return this.queue.queue(() => Promise.resolve()); + flush(): void { } log(level: LogLevel, args: any[]): void { this._log(level, this.format(args)); } + private async initialize(): Promise { + await this.fileService.createFile(this.resource); + } + private _log(level: LogLevel, message: string): void { this.queue.queue(async () => { + await this.initializePromise; let content = await this.loadContent(); if (content.length > MAX_FILE_SIZE) { await this.fileService.writeFile(this.getBackupResource(), VSBuffer.fromString(content)); @@ -145,3 +153,33 @@ export class FileLogService extends AbstractLogService implements ILogService { return result; } } + +export class FileLoggerService extends Disposable implements ILoggerService { + + _serviceBrand: undefined; + + private readonly loggers = new Map(); + + constructor( + @ILogService private logService: ILogService, + @IInstantiationService private instantiationService: IInstantiationService, + ) { + super(); + this._register(logService.onDidChangeLogLevel(level => this.loggers.forEach(logger => logger.setLevel(level)))); + } + + getLogger(resource: URI): ILogger { + let logger = this.loggers.get(resource.toString()); + if (!logger) { + logger = this.instantiationService.createInstance(FileLogService, basename(resource), resource, this.logService.getLevel()); + this.loggers.set(resource.toString(), logger); + } + return logger; + } + + dispose(): void { + this.loggers.forEach(logger => logger.dispose()); + this.loggers.clear(); + super.dispose(); + } +} diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 0009b304e53..24a06461d6b 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -9,8 +9,10 @@ import { isWindows } from 'vs/base/common/platform'; import { Event, Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; +import { URI } from 'vs/base/common/uri'; export const ILogService = createServiceDecorator('logService'); +export const ILoggerService = createServiceDecorator('loggerService'); function now(): string { return new Date().toISOString(); @@ -28,18 +30,32 @@ export enum LogLevel { export const DEFAULT_LOG_LEVEL: LogLevel = LogLevel.Info; -export interface ILogService extends IDisposable { - _serviceBrand: undefined; +export interface ILogger extends IDisposable { onDidChangeLogLevel: Event; - getLevel(): LogLevel; 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; + + /** + * An operation to flush the contents. Can be synchronous. + */ + flush(): void; +} + +export interface ILogService extends ILogger { + _serviceBrand: undefined; +} + +export interface ILoggerService { + _serviceBrand: undefined; + + getLogger(file: URI): ILogger; } export abstract class AbstractLogService extends Disposable { @@ -58,6 +74,7 @@ export abstract class AbstractLogService extends Disposable { getLevel(): LogLevel { return this.level; } + } export class ConsoleLogMainService extends AbstractLogService implements ILogService { @@ -134,6 +151,11 @@ export class ConsoleLogMainService extends AbstractLogService implements ILogSer dispose(): void { // noop } + + flush(): void { + // noop + } + } export class ConsoleLogService extends AbstractLogService implements ILogService { @@ -181,7 +203,13 @@ export class ConsoleLogService extends AbstractLogService implements ILogService } } - dispose(): void { } + dispose(): void { + // noop + } + + flush(): void { + // noop + } } export class ConsoleLogInMainService extends AbstractLogService implements ILogService { @@ -229,7 +257,13 @@ export class ConsoleLogInMainService extends AbstractLogService implements ILogS } } - dispose(): void { } + dispose(): void { + // noop + } + + flush(): void { + // noop + } } export class MultiplexLogService extends AbstractLogService implements ILogService { @@ -285,6 +319,12 @@ export class MultiplexLogService extends AbstractLogService implements ILogServi } } + flush(): void { + for (const logService of this.logServices) { + logService.flush(); + } + } + dispose(): void { for (const logService of this.logServices) { logService.dispose(); @@ -335,6 +375,10 @@ export class DelegatedLogService extends Disposable implements ILogService { critical(message: string | Error, ...args: any[]): void { this.logService.critical(message, ...args); } + + flush(): void { + this.logService.flush(); + } } export class NullLogService implements ILogService { @@ -349,6 +393,7 @@ export class NullLogService implements ILogService { error(message: string | Error, ...args: any[]): void { } critical(message: string | Error, ...args: any[]): void { } dispose(): void { } + flush(): void { } } export function getLogLevel(environmentService: IEnvironmentService): LogLevel { diff --git a/src/vs/platform/log/node/loggerService.ts b/src/vs/platform/log/node/loggerService.ts new file mode 100644 index 00000000000..fa5c621c264 --- /dev/null +++ b/src/vs/platform/log/node/loggerService.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ILogService, ILoggerService, ILogger } from 'vs/platform/log/common/log'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { basename, extname, dirname } from 'vs/base/common/resources'; +import { Schemas } from 'vs/base/common/network'; +import { FileLogService } from 'vs/platform/log/common/fileLogService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { SpdLogService } from 'vs/platform/log/node/spdlogService'; + +export class LoggerService extends Disposable implements ILoggerService { + + _serviceBrand: undefined; + + private readonly loggers = new Map(); + + constructor( + @ILogService private logService: ILogService, + @IInstantiationService private instantiationService: IInstantiationService, + ) { + super(); + this._register(logService.onDidChangeLogLevel(level => this.loggers.forEach(logger => logger.setLevel(level)))); + } + + getLogger(resource: URI): ILogger { + let logger = this.loggers.get(resource.toString()); + if (!logger) { + if (resource.scheme === Schemas.file) { + const baseName = basename(resource); + const ext = extname(resource); + logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).fsPath, this.logService.getLevel()); + } else { + logger = this.instantiationService.createInstance(FileLogService, basename(resource), resource, this.logService.getLevel()); + } + this.loggers.set(resource.toString(), logger); + } + return logger; + } + + dispose(): void { + this.loggers.forEach(logger => logger.dispose()); + this.loggers.clear(); + super.dispose(); + } +} + diff --git a/src/vs/platform/log/node/spdlogService.ts b/src/vs/platform/log/node/spdlogService.ts index cd482c70a83..ac8c8dc0a6f 100644 --- a/src/vs/platform/log/node/spdlogService.ts +++ b/src/vs/platform/log/node/spdlogService.ts @@ -32,12 +32,12 @@ interface ILog { function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): void { switch (level) { - case LogLevel.Trace: return logger.trace(message); - case LogLevel.Debug: return logger.debug(message); - case LogLevel.Info: return logger.info(message); - case LogLevel.Warning: return logger.warn(message); - case LogLevel.Error: return logger.error(message); - case LogLevel.Critical: return logger.critical(message); + case LogLevel.Trace: logger.trace(message); break; + case LogLevel.Debug: logger.debug(message); break; + case LogLevel.Info: logger.info(message); break; + case LogLevel.Warning: logger.warn(message); break; + case LogLevel.Error: logger.error(message); break; + case LogLevel.Critical: logger.critical(message); break; default: throw new Error('Invalid log level'); } } @@ -86,47 +86,54 @@ export class SpdLogService extends AbstractLogService implements ILogService { } } - trace(): void { + trace(message: string, ...args: any[]): void { if (this.getLevel() <= LogLevel.Trace) { - this._log(LogLevel.Trace, this.format(arguments)); + this._log(LogLevel.Trace, this.format([message, ...args])); } } - debug(): void { + debug(message: string, ...args: any[]): void { if (this.getLevel() <= LogLevel.Debug) { - this._log(LogLevel.Debug, this.format(arguments)); + this._log(LogLevel.Debug, this.format([message, ...args])); } } - info(): void { + info(message: string, ...args: any[]): void { if (this.getLevel() <= LogLevel.Info) { - this._log(LogLevel.Info, this.format(arguments)); + this._log(LogLevel.Info, this.format([message, ...args])); } } - warn(): void { + warn(message: string, ...args: any[]): void { if (this.getLevel() <= LogLevel.Warning) { - this._log(LogLevel.Warning, this.format(arguments)); + this._log(LogLevel.Warning, this.format([message, ...args])); } } - error(): void { + error(message: string | Error, ...args: any[]): void { if (this.getLevel() <= LogLevel.Error) { - const arg = arguments[0]; - if (arg instanceof Error) { + if (message instanceof Error) { const array = Array.prototype.slice.call(arguments) as any[]; - array[0] = arg.stack; + array[0] = message.stack; this._log(LogLevel.Error, this.format(array)); } else { - this._log(LogLevel.Error, this.format(arguments)); + this._log(LogLevel.Error, this.format([message, ...args])); } } } - critical(): void { + critical(message: string | Error, ...args: any[]): void { if (this.getLevel() <= LogLevel.Critical) { - this._log(LogLevel.Critical, this.format(arguments)); + this._log(LogLevel.Critical, this.format([message, ...args])); + } + } + + flush(): void { + if (this._logger) { + this._logger.flush(); + } else if (this._loggerCreationPromise) { + this._loggerCreationPromise.then(() => this.flush()); } } @@ -163,4 +170,4 @@ export class SpdLogService extends AbstractLogService implements ILogService { return result; } -} \ No newline at end of file +} diff --git a/src/vs/platform/markers/common/markerService.ts b/src/vs/platform/markers/common/markerService.ts index 9bd5e64f123..ae093ba4b89 100644 --- a/src/vs/platform/markers/common/markerService.ts +++ b/src/vs/platform/markers/common/markerService.ts @@ -123,8 +123,8 @@ export class MarkerService implements IMarkerService { _serviceBrand: undefined; - private readonly _onMarkerChanged = new Emitter(); - private _onMarkerChangedEvent: Event = Event.debounce(this._onMarkerChanged.event, MarkerService._debouncer, 0); + private readonly _onMarkerChanged = new Emitter(); + private _onMarkerChangedEvent: Event = Event.debounce(this._onMarkerChanged.event, MarkerService._debouncer, 0); private _byResource: MapMap = Object.create(null); private _byOwner: MapMap = Object.create(null); private _stats: MarkerStats; @@ -137,7 +137,7 @@ export class MarkerService implements IMarkerService { this._stats.dispose(); } - get onMarkerChanged(): Event { + get onMarkerChanged(): Event { return this._onMarkerChangedEvent; } diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index e0bfe097ef9..4b0f6095f1a 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -22,7 +22,7 @@ export interface IMarkerService { read(filter?: { owner?: string; resource?: URI; severities?: number, take?: number; }): IMarker[]; - onMarkerChanged: Event; + readonly onMarkerChanged: Event; } /** diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index d5e449cd854..71f92ef6faf 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -16,12 +16,13 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; import { mnemonicMenuLabel as baseMnemonicLabel } from 'vs/base/common/labels'; import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows'; -import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; +import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/node/menubar'; import { URI } from 'vs/base/common/uri'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; +import { IElectronMainService } from 'vs/platform/electron/electron-main/electronMainService'; const telemetryFrom = 'menu'; @@ -43,8 +44,8 @@ export class Menubar { private static readonly lastKnownMenubarStorageKey = 'lastKnownMenubarData'; - private willShutdown: boolean; - private appMenuInstalled: boolean; + private willShutdown: boolean | undefined; + private appMenuInstalled: boolean | undefined; private closedLastWindow: boolean; private menuUpdater: RunOnceScheduler; @@ -66,10 +67,11 @@ export class Menubar { @IWindowsMainService private readonly windowsMainService: IWindowsMainService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IHistoryMainService private readonly historyMainService: IHistoryMainService, + @IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService, @IStateService private readonly stateService: IStateService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IElectronMainService private readonly electronMainService: IElectronMainService ) { this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0); @@ -111,11 +113,11 @@ export class Menubar { // File Menu Items this.fallbackMenuHandlers['workbench.action.files.newUntitledFile'] = () => this.windowsMainService.openEmptyWindow(OpenContext.MENU); this.fallbackMenuHandlers['workbench.action.newWindow'] = () => this.windowsMainService.openEmptyWindow(OpenContext.MENU); - this.fallbackMenuHandlers['workbench.action.files.openFileFolder'] = (menuItem, win, event) => this.windowsMainService.pickFileFolderAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }); - this.fallbackMenuHandlers['workbench.action.openWorkspace'] = (menuItem, win, event) => this.windowsMainService.pickWorkspaceAndOpen({ forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }); + this.fallbackMenuHandlers['workbench.action.files.openFileFolder'] = (menuItem, win, event) => this.electronMainService.pickFileFolderAndOpen(undefined, { forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }); + this.fallbackMenuHandlers['workbench.action.openWorkspace'] = (menuItem, win, event) => this.electronMainService.pickWorkspaceAndOpen(undefined, { forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }); // Recent Menu Items - this.fallbackMenuHandlers['workbench.action.clearRecentFiles'] = () => this.historyMainService.clearRecentlyOpened(); + this.fallbackMenuHandlers['workbench.action.clearRecentFiles'] = () => this.workspacesHistoryMainService.clearRecentlyOpened(); // Help Menu Items const twitterUrl = product.twitterUrl; @@ -363,12 +365,13 @@ export class Menubar { const showAll = new MenuItem({ label: nls.localize('mShowAll', "Show All"), role: 'unhide' }); const quit = new MenuItem(this.likeAction('workbench.action.quit', { label: nls.localize('miQuit', "Quit {0}", product.nameLong), click: () => { + const lastActiveWindow = this.windowsMainService.getLastActiveWindow(); if ( - this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open - !!this.windowsMainService.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/Microsoft/vscode/issues/39191) - this.windowsMainService.getLastActiveWindow()!.isMinimized() // allow to quit when window has no focus but is minimized (https://github.com/Microsoft/vscode/issues/63000) + this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open + !!BrowserWindow.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/Microsoft/vscode/issues/39191) + lastActiveWindow?.isMinimized() // allow to quit when window has no focus but is minimized (https://github.com/Microsoft/vscode/issues/63000) ) { - this.windowsMainService.quit(); + this.electronMainService.quit(undefined); } } })); @@ -488,7 +491,7 @@ export class Menubar { }).length > 0; if (!success) { - this.historyMainService.removeFromRecentlyOpened([revivedUri]); + this.workspacesHistoryMainService.removeFromRecentlyOpened([revivedUri]); } } }, false)); @@ -548,8 +551,8 @@ export class Menubar { label: this.mnemonicLabel(nls.localize('miCheckForUpdates', "Check for &&Updates...")), click: () => setTimeout(() => { this.reportMenuActionTelemetry('CheckForUpdate'); - const focusedWindow = this.windowsMainService.getFocusedWindow(); - const context = focusedWindow ? { windowId: focusedWindow.id } : null; + const window = this.windowsMainService.getLastActiveWindow(); + const context = window && `window:${window.id}`; // sessionId this.updateService.checkForUpdates(context); }, 0) })]; @@ -688,15 +691,16 @@ export class Menubar { private makeContextAwareClickHandler(click: () => void, contextSpecificHandlers: IMenuItemClickHandler): () => void { return () => { + // No Active Window - const activeWindow = this.windowsMainService.getFocusedWindow(); + const activeWindow = BrowserWindow.getFocusedWindow(); if (!activeWindow) { return contextSpecificHandlers.inNoWindow(); } // DevTools focused - if (activeWindow.win.webContents.isDevToolsFocused()) { - return contextSpecificHandlers.inDevTools(activeWindow.win.webContents.devToolsWebContents); + if (activeWindow.webContents.isDevToolsFocused()) { + return contextSpecificHandlers.inDevTools(activeWindow.webContents.devToolsWebContents); } // Finally execute command in Window @@ -710,14 +714,15 @@ export class Menubar { // https://github.com/Microsoft/vscode/issues/11928 // Still allow to run when the last active window is minimized though for // https://github.com/Microsoft/vscode/issues/63000 - let activeWindow = this.windowsMainService.getFocusedWindow(); - if (!activeWindow) { + let activeBrowserWindow = BrowserWindow.getFocusedWindow(); + if (!activeBrowserWindow) { const lastActiveWindow = this.windowsMainService.getLastActiveWindow(); - if (lastActiveWindow && lastActiveWindow.isMinimized()) { - activeWindow = lastActiveWindow; + if (lastActiveWindow?.isMinimized()) { + activeBrowserWindow = lastActiveWindow.win; } } + const activeWindow = activeBrowserWindow ? this.windowsMainService.getWindowById(activeBrowserWindow.id) : undefined; if (activeWindow) { this.logService.trace('menubar#runActionInRenderer', invocation); @@ -744,7 +749,7 @@ export class Menubar { const binding = typeof commandId === 'string' ? this.keybindings[commandId] : undefined; // Apply binding if there is one - if (binding && binding.label) { + if (binding?.label) { // if the binding is native, we can just apply it if (binding.isNative !== false) { diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index b16fe281725..6f10b476dc8 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -227,6 +227,25 @@ export interface IStatusMessageOptions { hideAfter?: number; } +export enum NotificationsFilter { + + /** + * No filter is enabled. + */ + OFF, + + /** + * All notifications are configured as silent. See + * `INotificationProperties.silent` for more info. + */ + SILENT, + + /** + * All notifications are silent except error notifications. + */ + ERROR +} + /** * A service to bring up notifications and non-modal prompts. * @@ -286,6 +305,13 @@ export interface INotificationService { * @returns a disposable to hide the status message */ status(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable; + + /** + * Allows to configure a filter for notifications. + * + * @param filter the filter to use + */ + setFilter(filter: NotificationsFilter): void; } export class NoOpNotification implements INotificationHandle { diff --git a/src/vs/platform/notification/test/common/testNotificationService.ts b/src/vs/platform/notification/test/common/testNotificationService.ts index b4c4d4000fd..671339e55e9 100644 --- a/src/vs/platform/notification/test/common/testNotificationService.ts +++ b/src/vs/platform/notification/test/common/testNotificationService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INotificationService, INotificationHandle, NoOpNotification, Severity, INotification, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { INotificationService, INotificationHandle, NoOpNotification, Severity, INotification, IPromptChoice, IPromptOptions, IStatusMessageOptions, NotificationsFilter } from 'vs/platform/notification/common/notification'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; export class TestNotificationService implements INotificationService { @@ -35,4 +35,6 @@ export class TestNotificationService implements INotificationService { status(message: string | Error, options?: IStatusMessageOptions): IDisposable { return Disposable.None; } -} \ No newline at end of file + + setFilter(filter: NotificationsFilter): void { } +} diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index fa1ede46ab1..70377fcb3da 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -9,13 +9,27 @@ import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; export const IOpenerService = createDecorator('openerService'); -type OpenToSideOptions = { readonly openToSide?: boolean }; +type OpenInternalOptions = { + + /** + * Signals that the intent is to open an editor to the side + * of the currently active editor. + */ + readonly openToSide?: boolean; + + /** + * Signals that the editor to open was triggered through a user + * action, such as keyboard or mouse usage. + */ + readonly fromUserGesture?: boolean; +}; + type OpenExternalOptions = { readonly openExternal?: boolean; readonly allowTunneling?: boolean }; -export type OpenOptions = OpenToSideOptions & OpenExternalOptions; +export type OpenOptions = OpenInternalOptions & OpenExternalOptions; export interface IOpener { - open(resource: URI, options?: OpenToSideOptions): Promise; + open(resource: URI, options?: OpenInternalOptions): Promise; open(resource: URI, options?: OpenExternalOptions): Promise; } @@ -53,7 +67,7 @@ export interface IOpenerService { * @param resource A resource * @return A promise that resolves when the opening is done. */ - open(resource: URI, options?: OpenToSideOptions): Promise; + open(resource: URI, options?: OpenInternalOptions): Promise; open(resource: URI, options?: OpenExternalOptions): Promise; resolveExternalUri(resource: URI, options?: { readonly allowTunneling?: boolean }): Promise<{ resolved: URI, dispose(): void }>; diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 2de51e8d324..6f76dd1680f 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -23,7 +23,8 @@ if (isWeb) { assign(product, { version: '1.39.0-dev', nameLong: 'Visual Studio Code Web Dev', - nameShort: 'VSCode Web Dev' + nameShort: 'VSCode Web Dev', + urlProtocol: 'code-oss' }); } } diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts index f44dcee0455..e905ecfa297 100644 --- a/src/vs/platform/product/common/productService.ts +++ b/src/vs/platform/product/common/productService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ExtensionKind } from 'vs/platform/extensions/common/extensions'; export const IProductService = createDecorator('productService'); @@ -56,8 +57,6 @@ export interface IProductConfiguration { readonly productName: string; }; - readonly welcomePage?: string; - readonly enableTelemetry?: boolean; readonly aiConfig?: { readonly asimovKey: string; @@ -98,7 +97,7 @@ export interface IProductConfiguration { readonly portable?: string; - readonly uiExtensions?: readonly string[]; + readonly extensionKind?: { readonly [extensionId: string]: ExtensionKind | ExtensionKind[]; }; readonly extensionAllowedProposedApi?: readonly string[]; readonly msftInternalDomains?: string[]; diff --git a/src/vs/platform/progress/common/progress.ts b/src/vs/platform/progress/common/progress.ts index b629e2fe837..560ed3de651 100644 --- a/src/vs/platform/progress/common/progress.ts +++ b/src/vs/platform/progress/common/progress.ts @@ -17,7 +17,7 @@ export interface IProgressService { _serviceBrand: undefined; - withProgress(options: IProgressOptions | IProgressNotificationOptions | IProgressCompositeOptions, task: (progress: IProgress) => Promise, onDidCancel?: () => void): Promise; + withProgress(options: IProgressOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions, task: (progress: IProgress) => Promise, onDidCancel?: () => void): Promise; } export interface IProgressIndicator { @@ -59,6 +59,11 @@ export interface IProgressNotificationOptions extends IProgressOptions { readonly secondaryActions?: ReadonlyArray; } +export interface IProgressWindowOptions extends IProgressOptions { + readonly location: ProgressLocation.Window; + readonly command?: string; +} + export interface IProgressCompositeOptions extends IProgressOptions { location: ProgressLocation.Explorer | ProgressLocation.Extensions | ProgressLocation.Scm | string; delay?: number; diff --git a/src/vs/platform/quickinput/common/quickInput.ts b/src/vs/platform/quickinput/common/quickInput.ts index 80cad64b5dc..3b23b66bbad 100644 --- a/src/vs/platform/quickinput/common/quickInput.ts +++ b/src/vs/platform/quickinput/common/quickInput.ts @@ -168,9 +168,9 @@ export interface IQuickPick extends IQuickInput { customButton: boolean; - customLabel: string; + customLabel: string | undefined; - customHover: string; + customHover: string | undefined; buttons: ReadonlyArray; diff --git a/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts b/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts index 1f8b5fee33c..6abb9086c8d 100644 --- a/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts +++ b/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts @@ -8,10 +8,13 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle' import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { FileChangeType, FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, IFileChange, IFileSystemProvider, IStat, IWatchOptions, FileOpenOptions } from 'vs/platform/files/common/files'; +import { FileChangeType, FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, IFileChange, IStat, IWatchOptions, FileOpenOptions, IFileSystemProviderWithFileReadWriteCapability, FileWriteOptions, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileFolderCopyCapability, FileReadStreamOptions, IFileSystemProviderWithOpenReadWriteCloseCapability } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { OperatingSystem } from 'vs/base/common/platform'; +import { newWriteableStream, ReadableStreamEvents, ReadableStreamEventPayload } from 'vs/base/common/stream'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { canceled } from 'vs/base/common/errors'; export const REMOTE_FILE_SYSTEM_CHANNEL_NAME = 'remotefilesystem'; @@ -20,12 +23,16 @@ export interface IFileChangeDto { type: FileChangeType; } -export class RemoteExtensionsFileSystemProvider extends Disposable implements IFileSystemProvider { +export class RemoteFileSystemProvider extends Disposable implements + IFileSystemProviderWithFileReadWriteCapability, + IFileSystemProviderWithOpenReadWriteCloseCapability, + IFileSystemProviderWithFileReadStreamCapability, + IFileSystemProviderWithFileFolderCopyCapability { private readonly session: string = generateUuid(); - private readonly _onDidChange = this._register(new Emitter()); - readonly onDidChangeFile: Event = this._onDidChange.event; + private readonly _onDidChange = this._register(new Emitter()); + readonly onDidChangeFile: Event = this._onDidChange.event; private _onDidWatchErrorOccur: Emitter = this._register(new Emitter()); readonly onDidErrorOccur: Event = this._onDidWatchErrorOccur.event; @@ -46,7 +53,7 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF } private registerListeners(): void { - this._register(this.channel.listen('filechange', [this.session])((eventsOrError) => { + this._register(this.channel.listen('filechange', [this.session])(eventsOrError => { if (Array.isArray(eventsOrError)) { const events = eventsOrError; this._onDidChange.fire(events.map(event => ({ resource: URI.revive(event.resource), type: event.type }))); @@ -59,7 +66,9 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF setCaseSensitive(isCaseSensitive: boolean) { let capabilities = ( - FileSystemProviderCapabilities.FileOpenReadWriteClose + FileSystemProviderCapabilities.FileReadWrite + | FileSystemProviderCapabilities.FileOpenReadWriteClose + | FileSystemProviderCapabilities.FileReadStream | FileSystemProviderCapabilities.FileFolderCopy ); @@ -97,10 +106,57 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF return bytesRead; } + async readFile(resource: URI): Promise { + const buff = await this.channel.call('readFile', [resource]); + + return buff.buffer; + } + + readFileStream(resource: URI, opts: FileReadStreamOptions, token?: CancellationToken): ReadableStreamEvents { + const stream = newWriteableStream(data => VSBuffer.concat(data.map(data => VSBuffer.wrap(data))).buffer); + + // Reading as file stream goes through an event to the remote side + const listener = this.channel.listen>('readFileStream', [resource, opts])(dataOrErrorOrEnd => { + if (dataOrErrorOrEnd instanceof VSBuffer) { + + // data: forward into the stream + stream.write(dataOrErrorOrEnd.buffer); + } else { + + // error / end: always end the stream on errors too + stream.end(dataOrErrorOrEnd === 'end' ? undefined : dataOrErrorOrEnd); + + // Signal to the remote side that we no longer listen + listener.dispose(); + } + }); + + // Support cancellation + if (token) { + Event.once(token.onCancellationRequested)(() => { + + // Ensure to end the stream properly with an error + // to indicate the cancellation. + stream.end(canceled()); + + // Ensure to dispose the listener upon cancellation. This will + // bubble through the remote side as event and allows to stop + // reading the file. + listener.dispose(); + }); + } + + return stream; + } + write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { return this.channel.call('write', [fd, pos, VSBuffer.wrap(data), offset, length]); } + writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { + return this.channel.call('writeFile', [resource, VSBuffer.wrap(content), opts]); + } + delete(resource: URI, opts: FileDeleteOptions): Promise { return this.channel.call('delete', [resource, opts]); } diff --git a/src/vs/platform/remote/common/tunnel.ts b/src/vs/platform/remote/common/tunnel.ts index 72527124b7a..37847839298 100644 --- a/src/vs/platform/remote/common/tunnel.ts +++ b/src/vs/platform/remote/common/tunnel.ts @@ -27,7 +27,7 @@ export function extractLocalHostUriMetaDataForPortMapping(uri: URI): { address: if (uri.scheme !== 'http' && uri.scheme !== 'https') { return undefined; } - const localhostMatch = /^(localhost|127\.0\.0\.1):(\d+)$/.exec(uri.authority); + const localhostMatch = /^(localhost|127\.0\.0\.1|0\.0\.0\.0):(\d+)$/.exec(uri.authority); if (!localhostMatch) { return undefined; } diff --git a/src/vs/platform/request/common/request.ts b/src/vs/platform/request/common/request.ts index 2bd8f1d7706..81ec255e65b 100644 --- a/src/vs/platform/request/common/request.ts +++ b/src/vs/platform/request/common/request.ts @@ -21,7 +21,7 @@ export interface IRequestService { resolveProxy(url: string): Promise; } -function isSuccess(context: IRequestContext): boolean { +export function isSuccess(context: IRequestContext): boolean { return (context.res.statusCode && context.res.statusCode >= 200 && context.res.statusCode < 300) || context.res.statusCode === 1223; } @@ -69,7 +69,7 @@ Registry.as(Extensions.Configuration) properties: { 'http.proxy': { type: 'string', - pattern: '^https?://([^:]*(:[^@]*)?@)?([^:]+)(:\\d+)?/?$|^$', + pattern: '^https?://([^:]*(:[^@]*)?@)?([^:]+|\\[[:0-9a-fA-F]+\\])(:\\d+)?/?$|^$', markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables.") }, 'http.proxyStrictSSL': { diff --git a/src/vs/platform/request/node/proxy.ts b/src/vs/platform/request/node/proxy.ts index c5932a7d10b..116f7e0c428 100644 --- a/src/vs/platform/request/node/proxy.ts +++ b/src/vs/platform/request/node/proxy.ts @@ -44,9 +44,7 @@ export async function getProxyAgent(rawRequestURL: string, options: IOptions = { rejectUnauthorized: isBoolean(options.strictSSL) ? options.strictSSL : true }; - const Ctor = requestURL.protocol === 'http:' - ? await import('http-proxy-agent') - : await import('https-proxy-agent'); - - return new Ctor(opts); + return requestURL.protocol === 'http:' + ? new (await import('http-proxy-agent'))(opts) + : new (await import('https-proxy-agent'))(opts); } diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index a5a4c033268..ad44dcbc336 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -5,7 +5,7 @@ import * as https from 'https'; import * as http from 'http'; -import { Stream } from 'stream'; +import * as streams from 'vs/base/common/stream'; import { createGunzip } from 'zlib'; import { parse as parseUrl } from 'url'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -18,7 +18,7 @@ import { IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/r import { getProxyAgent, Agent } from 'vs/platform/request/node/proxy'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; -import { toVSBufferReadableStream } from 'vs/base/common/buffer'; +import { streamToBufferReadableStream } from 'vs/base/common/buffer'; export interface IRawRequestFunction { (options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest; @@ -112,13 +112,13 @@ export class RequestService extends Disposable implements IRequestService { followRedirects: followRedirects - 1 }), token).then(c, e); } else { - let stream: Stream = res; + let stream: streams.ReadableStream = res; if (res.headers['content-encoding'] === 'gzip') { - stream = stream.pipe(createGunzip()); + stream = res.pipe(createGunzip()); } - c({ res, stream: toVSBufferReadableStream(stream) } as IRequestContext); + c({ res, stream: streamToBufferReadableStream(stream) } as IRequestContext); } }); diff --git a/src/vs/platform/severityIcon/common/severityIcon.ts b/src/vs/platform/severityIcon/common/severityIcon.ts index 52eae1a08cc..946313a389e 100644 --- a/src/vs/platform/severityIcon/common/severityIcon.ts +++ b/src/vs/platform/severityIcon/common/severityIcon.ts @@ -4,70 +4,57 @@ *--------------------------------------------------------------------------------------------*/ import Severity from 'vs/base/common/severity'; -import { registerThemingParticipant, ITheme, LIGHT } from 'vs/platform/theme/common/themeService'; -import { Color } from 'vs/base/common/color'; - -const errorStart = encodeURIComponent(``); -const errorDarkStart = encodeURIComponent(``); - -const warningStart = encodeURIComponent(``); -const warningDarkStart = encodeURIComponent(``); - -const infoStart = encodeURIComponent(``); -const infoDarkStart = encodeURIComponent(``); +import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { problemsErrorIconForeground, problemsInfoIconForeground, problemsWarningIconForeground } from 'vs/platform/theme/common/colorRegistry'; export namespace SeverityIcon { - export function getSVGData(severity: Severity, theme: ITheme): string { - switch (severity) { - case Severity.Ignore: - const ignoreColor = theme.type === LIGHT ? Color.fromHex('#75BEFF') : Color.fromHex('#007ACC'); - return theme.type === LIGHT ? infoStart + encodeURIComponent(ignoreColor.toString()) + infoEnd - : infoDarkStart + encodeURIComponent(ignoreColor.toString()) + infoDarkEnd; - case Severity.Info: - const infoColor = theme.type === LIGHT ? Color.fromHex('#007ACC') : Color.fromHex('#75BEFF'); - return theme.type === LIGHT ? infoStart + encodeURIComponent(infoColor.toString()) + infoEnd - : infoDarkStart + encodeURIComponent(infoColor.toString()) + infoDarkEnd; - case Severity.Warning: - const warningColor = theme.type === LIGHT ? Color.fromHex('#DDB100') : Color.fromHex('#fc0'); - return theme.type === LIGHT ? warningStart + encodeURIComponent(warningColor.toString()) + warningEnd - : warningDarkStart + encodeURIComponent(warningColor.toString()) + warningDarkEnd; - case Severity.Error: - const errorColor = theme.type === LIGHT ? Color.fromHex('#A1260D') : Color.fromHex('#F48771'); - return theme.type === LIGHT ? errorStart + encodeURIComponent(errorColor.toString()) + errorEnd - : errorDarkStart + encodeURIComponent(errorColor.toString()) + errorDarkEnd; - } - return ''; - } - export function className(severity: Severity): string { switch (severity) { case Severity.Ignore: - return 'severity-icon severity-ignore'; + return 'severity-ignore codicon-info'; case Severity.Info: - return 'severity-icon severity-info'; + return 'codicon-info'; case Severity.Warning: - return 'severity-icon severity-warning'; + return 'codicon-warning'; case Severity.Error: - return 'severity-icon severity-error'; + return 'codicon-error'; } return ''; } } -function getCSSRule(severity: Severity, theme: ITheme): string { - return `.${SeverityIcon.className(severity).split(' ').join('.')} { background: url("data:image/svg+xml,${SeverityIcon.getSVGData(severity, theme)}") center center no-repeat; height: 16px; width: 16px; }`; -} - registerThemingParticipant((theme, collector) => { - collector.addRule(getCSSRule(Severity.Error, theme)); - collector.addRule(getCSSRule(Severity.Warning, theme)); - collector.addRule(getCSSRule(Severity.Info, theme)); - collector.addRule(getCSSRule(Severity.Ignore, theme)); -}); \ No newline at end of file + + const errorIconForeground = theme.getColor(problemsErrorIconForeground); + if (errorIconForeground) { + collector.addRule(` + .monaco-workbench .zone-widget .codicon-error, + .monaco-workbench .markers-panel .marker-icon.codicon-error, + .monaco-workbench .extensions-viewlet > .extensions .codicon-error { + color: ${errorIconForeground}; + } + `); + } + + const warningIconForeground = theme.getColor(problemsWarningIconForeground); + if (errorIconForeground) { + collector.addRule(` + .monaco-workbench .zone-widget .codicon-warning, + .monaco-workbench .markers-panel .marker-icon.codicon-warning, + .monaco-workbench .extensions-viewlet > .extensions .codicon-warning { + color: ${warningIconForeground}; + } + `); + } + + const infoIconForeground = theme.getColor(problemsInfoIconForeground); + if (errorIconForeground) { + collector.addRule(` + .monaco-workbench .zone-widget .codicon-info, + .monaco-workbench .markers-panel .marker-icon.codicon-info { + color: ${infoIconForeground}; + } + `); + } +}); diff --git a/src/vs/platform/state/common/state.ts b/src/vs/platform/state/node/state.ts similarity index 100% rename from src/vs/platform/state/common/state.ts rename to src/vs/platform/state/node/state.ts diff --git a/src/vs/platform/state/node/stateService.ts b/src/vs/platform/state/node/stateService.ts index 967cce50be3..d5146ec25ac 100644 --- a/src/vs/platform/state/node/stateService.ts +++ b/src/vs/platform/state/node/stateService.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { writeFileSync, readFile } from 'vs/base/node/pfs'; import { isUndefined, isUndefinedOrNull } from 'vs/base/common/types'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { ILogService } from 'vs/platform/log/common/log'; type StorageDatebase = { [key: string]: any; }; @@ -127,7 +127,7 @@ export class StateService implements IStateService { _serviceBrand: undefined; - private static STATE_FILE = 'storage.json'; + private static readonly STATE_FILE = 'storage.json'; private fileStorage: FileStorage; diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts index 67f3e6ac6d0..e1da1af90f8 100644 --- a/src/vs/platform/storage/browser/storageService.ts +++ b/src/vs/platform/storage/browser/storageService.ts @@ -15,6 +15,7 @@ import { joinPath } from 'vs/base/common/resources'; import { runWhenIdle, RunOnceScheduler } from 'vs/base/common/async'; import { serializableToMap, mapToSerializable } from 'vs/base/common/map'; import { VSBuffer } from 'vs/base/common/buffer'; +import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; export class BrowserStorageService extends Disposable implements IStorageService { @@ -26,20 +27,20 @@ export class BrowserStorageService extends Disposable implements IStorageService private readonly _onWillSaveState: Emitter = this._register(new Emitter()); readonly onWillSaveState: Event = this._onWillSaveState.event; - private globalStorage: IStorage; - private workspaceStorage: IStorage; + private globalStorage: IStorage | undefined; + private workspaceStorage: IStorage | undefined; - private globalStorageDatabase: FileStorageDatabase; - private workspaceStorageDatabase: FileStorageDatabase; + private globalStorageDatabase: FileStorageDatabase | undefined; + private workspaceStorageDatabase: FileStorageDatabase | undefined; - private globalStorageFile: URI; - private workspaceStorageFile: URI; + private globalStorageFile: URI | undefined; + private workspaceStorageFile: URI | undefined; - private initializePromise: Promise; + private initializePromise: Promise | undefined; private periodicSaveScheduler = this._register(new RunOnceScheduler(() => this.collectState(), 5000)); get hasPendingUpdate(): boolean { - return this.globalStorageDatabase.hasPendingUpdate || this.workspaceStorageDatabase.hasPendingUpdate; + return (!!this.globalStorageDatabase && this.globalStorageDatabase.hasPendingUpdate) || (!!this.workspaceStorageDatabase && this.workspaceStorageDatabase.hasPendingUpdate); } constructor( @@ -137,16 +138,18 @@ export class BrowserStorageService extends Disposable implements IStorageService } private getStorage(scope: StorageScope): IStorage { - return scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage; + return assertIsDefined(scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage); } async logStorage(): Promise { + const [globalStorage, workspaceStorage, globalStorageFile, workspaceStorageFile] = assertAllDefined(this.globalStorage, this.workspaceStorage, this.globalStorageFile, this.workspaceStorageFile); + const result = await Promise.all([ - this.globalStorage.items, - this.workspaceStorage.items + globalStorage.items, + workspaceStorage.items ]); - return logStorage(result[0], result[1], this.globalStorageFile.toString(), this.workspaceStorageFile.toString()); + return logStorage(result[0], result[1], globalStorageFile.toString(), workspaceStorageFile.toString()); } async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { diff --git a/src/vs/platform/storage/node/storageIpc.ts b/src/vs/platform/storage/node/storageIpc.ts index f74005b5ed4..b0a2b3752a5 100644 --- a/src/vs/platform/storage/node/storageIpc.ts +++ b/src/vs/platform/storage/node/storageIpc.ts @@ -29,7 +29,7 @@ interface ISerializableItemsChangeEvent { export class GlobalStorageDatabaseChannel extends Disposable implements IServerChannel { - private static STORAGE_CHANGE_DEBOUNCE_TIME = 100; + private static readonly STORAGE_CHANGE_DEBOUNCE_TIME = 100; private readonly _onDidChangeItems: Emitter = this._register(new Emitter()); readonly onDidChangeItems: Event = this._onDidChangeItems.event; diff --git a/src/vs/platform/storage/node/storageMainService.ts b/src/vs/platform/storage/node/storageMainService.ts index 70cdeef730d..81c9511a239 100644 --- a/src/vs/platform/storage/node/storageMainService.ts +++ b/src/vs/platform/storage/node/storageMainService.ts @@ -87,7 +87,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic _serviceBrand: undefined; - private static STORAGE_NAME = 'state.vscdb'; + private static readonly STORAGE_NAME = 'state.vscdb'; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts index 33e3cac1c81..bdd7b454af1 100644 --- a/src/vs/platform/storage/node/storageService.ts +++ b/src/vs/platform/storage/node/storageService.ts @@ -15,13 +15,14 @@ import { copy, exists, mkdirp, writeFile } from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceInitializationPayload, isWorkspaceIdentifier, isSingleFolderWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; -export class StorageService extends Disposable implements IStorageService { +export class NativeStorageService extends Disposable implements IStorageService { _serviceBrand: undefined; - private static WORKSPACE_STORAGE_NAME = 'state.vscdb'; - private static WORKSPACE_META_NAME = 'workspace.json'; + private static readonly WORKSPACE_STORAGE_NAME = 'state.vscdb'; + private static readonly WORKSPACE_META_NAME = 'workspace.json'; private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; @@ -31,11 +32,11 @@ export class StorageService extends Disposable implements IStorageService { private globalStorage: IStorage; - private workspaceStoragePath: string; - private workspaceStorage: IStorage; - private workspaceStorageListener: IDisposable; + private workspaceStoragePath: string | undefined; + private workspaceStorage: IStorage | undefined; + private workspaceStorageListener: IDisposable | undefined; - private initializePromise: Promise; + private initializePromise: Promise | undefined; constructor( globalStorageDatabase: IStorageDatabase, @@ -83,7 +84,7 @@ export class StorageService extends Disposable implements IStorageService { // Create workspace storage and initialize mark('willInitWorkspaceStorage'); try { - await this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init(); + await this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, NativeStorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init(); } finally { mark('didInitWorkspaceStorage'); } @@ -144,7 +145,7 @@ export class StorageService extends Disposable implements IStorageService { } if (meta) { - const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), StorageService.WORKSPACE_META_NAME); + const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), NativeStorageService.WORKSPACE_META_NAME); (async function () { try { const storageExists = await exists(workspaceStorageMetaPath); @@ -191,22 +192,24 @@ export class StorageService extends Disposable implements IStorageService { // Do it await Promise.all([ - this.globalStorage.close(), - this.workspaceStorage.close() + this.getStorage(StorageScope.GLOBAL).close(), + this.getStorage(StorageScope.WORKSPACE).close() ]); } private getStorage(scope: StorageScope): IStorage { - return scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage; + return assertIsDefined(scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage); } async logStorage(): Promise { + const [workspaceStorage, workspaceStoragePath] = assertAllDefined(this.workspaceStorage, this.workspaceStoragePath); + const result = await Promise.all([ this.globalStorage.items, - this.workspaceStorage.items + workspaceStorage.items ]); - logStorage(result[0], result[1], this.environmentService.globalStorageHome, this.workspaceStoragePath); + logStorage(result[0], result[1], this.environmentService.globalStorageHome, workspaceStoragePath); } async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise { @@ -215,15 +218,15 @@ export class StorageService extends Disposable implements IStorageService { } // Close workspace DB to be able to copy - await this.workspaceStorage.close(); + await this.getStorage(StorageScope.WORKSPACE).close(); // Prepare new workspace storage folder const result = await this.prepareWorkspaceStorageFolder(toWorkspace); - const newWorkspaceStoragePath = join(result.path, StorageService.WORKSPACE_STORAGE_NAME); + const newWorkspaceStoragePath = join(result.path, NativeStorageService.WORKSPACE_STORAGE_NAME); // Copy current storage over to new workspace storage - await copy(this.workspaceStoragePath, newWorkspaceStoragePath); + await copy(assertIsDefined(this.workspaceStoragePath), newWorkspaceStoragePath); // Recreate and init workspace storage return this.createWorkspaceStorage(newWorkspaceStoragePath).init(); diff --git a/src/vs/platform/storage/test/node/storageService.test.ts b/src/vs/platform/storage/test/node/storageService.test.ts index e2c984125b9..5f9271b43c5 100644 --- a/src/vs/platform/storage/test/node/storageService.test.ts +++ b/src/vs/platform/storage/test/node/storageService.test.ts @@ -5,7 +5,7 @@ import { strictEqual, ok, equal } from 'assert'; import { StorageScope, InMemoryStorageService } from 'vs/platform/storage/common/storage'; -import { StorageService } from 'vs/platform/storage/node/storageService'; +import { NativeStorageService } from 'vs/platform/storage/node/storageService'; import { generateUuid } from 'vs/base/common/uuid'; import { join } from 'vs/base/common/path'; import { tmpdir } from 'os'; @@ -101,7 +101,7 @@ suite('StorageService', () => { const storageDir = uniqueStorageDir(); await mkdirp(storageDir); - const storage = new StorageService(new InMemoryStorageDatabase(), new NullLogService(), new StorageTestEnvironmentService(storageDir, storageDir)); + const storage = new NativeStorageService(new InMemoryStorageDatabase(), new NullLogService(), new StorageTestEnvironmentService(storageDir, storageDir)); await storage.initialize({ id: String(Date.now()) }); storage.store('bar', 'foo', StorageScope.WORKSPACE); diff --git a/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts b/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts index ac0da4361f7..b798518500b 100644 --- a/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts +++ b/src/vs/platform/telemetry/browser/workbenchCommonProperties.ts @@ -9,16 +9,30 @@ export const instanceStorageKey = 'telemetry.instanceId'; export const currentSessionDateStorageKey = 'telemetry.currentSessionDate'; export const firstSessionDateStorageKey = 'telemetry.firstSessionDate'; export const lastSessionDateStorageKey = 'telemetry.lastSessionDate'; +export const machineIdKey = 'telemetry.machineId'; import * as Platform from 'vs/base/common/platform'; import * as uuid from 'vs/base/common/uuid'; import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils'; +import { mixin } from 'vs/base/common/objects'; -export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> { +export async function resolveWorkbenchCommonProperties( + storageService: IStorageService, + commit: string | undefined, + version: string | undefined, + remoteAuthority?: string, + resolveAdditionalProperties?: () => { [key: string]: any } +): Promise<{ [name: string]: string | undefined }> { const result: { [name: string]: string | undefined; } = Object.create(null); const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!; const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!; + let machineId = storageService.get(machineIdKey, StorageScope.GLOBAL); + if (!machineId) { + machineId = uuid.generateUuid(); + storageService.store(machineIdKey, machineId, StorageScope.GLOBAL); + } + /** * Note: In the web, session date information is fetched from browser storage, so these dates are tied to a specific * browser and not the machine overall. @@ -68,6 +82,10 @@ export async function resolveWorkbenchCommonProperties(storageService: IStorageS } }); + if (resolveAdditionalProperties) { + mixin(result, resolveAdditionalProperties()); + } + return result; } diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index 1e468a2018d..8e64e8e045a 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -24,8 +24,8 @@ export interface ITelemetryServiceConfig { export class TelemetryService implements ITelemetryService { - static IDLE_START_EVENT_NAME = 'UserIdleStart'; - static IDLE_STOP_EVENT_NAME = 'UserIdleStop'; + static readonly IDLE_START_EVENT_NAME = 'UserIdleStart'; + static readonly IDLE_STOP_EVENT_NAME = 'UserIdleStop'; _serviceBrand: undefined; diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index a8399a43946..520c211b51b 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -20,7 +20,7 @@ export const NullTelemetryService = new class implements ITelemetryService { return this.publicLog(eventName, data as ITelemetryData); } setEnabled() { } - isOptedIn: true; + isOptedIn = true; getTelemetryInfo(): Promise { return Promise.resolve({ instanceId: 'someValue.instanceId', diff --git a/src/vs/platform/telemetry/node/commonProperties.ts b/src/vs/platform/telemetry/node/commonProperties.ts index 1e943ade588..d681c0c7733 100644 --- a/src/vs/platform/telemetry/node/commonProperties.ts +++ b/src/vs/platform/telemetry/node/commonProperties.ts @@ -8,7 +8,14 @@ import * as os from 'os'; import * as uuid from 'vs/base/common/uuid'; import { readFile } from 'vs/base/node/pfs'; -export async function resolveCommonProperties(commit: string | undefined, version: string | undefined, machineId: string | undefined, msftInternalDomains: string[] | undefined, installSourcePath: string, product?: string): Promise<{ [name: string]: string | boolean | undefined; }> { +export async function resolveCommonProperties( + commit: string | undefined, + version: string | undefined, + machineId: string | undefined, + msftInternalDomains: string[] | undefined, + installSourcePath: string, + product?: string +): Promise<{ [name: string]: string | boolean | undefined; }> { const result: { [name: string]: string | boolean | undefined; } = Object.create(null); // __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } @@ -32,7 +39,7 @@ export async function resolveCommonProperties(commit: string | undefined, versio const msftInternal = verifyMicrosoftInternalDomain(msftInternalDomains || []); if (msftInternal) { - // __GDPR__COMMON__ "common.msftInternal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + // __GDPR__COMMON__ "common.msftInternal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } result['common.msftInternal'] = msftInternal; } @@ -74,17 +81,11 @@ export async function resolveCommonProperties(commit: string | undefined, versio return result; } -function verifyMicrosoftInternalDomain(domainList: string[]): boolean { +function verifyMicrosoftInternalDomain(domainList: readonly string[]): boolean { if (!process || !process.env || !process.env['USERDNSDOMAIN']) { return false; } const domain = process.env['USERDNSDOMAIN']!.toLowerCase(); - for (let msftDomain of domainList) { - if (domain === msftDomain) { - return true; - } - } - - return false; + return domainList.some(msftDomain => domain === msftDomain); } diff --git a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts index cf6f57836fe..41b8fffcfc4 100644 --- a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts +++ b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts @@ -8,8 +8,16 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils'; -export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, msftInternalDomains: string[] | undefined, installSourcePath: string, remoteAuthority?: string): Promise<{ [name: string]: string | boolean | undefined }> { - const result = await resolveCommonProperties(commit, version, machineId, msftInternalDomains, installSourcePath); +export async function resolveWorkbenchCommonProperties( + storageService: IStorageService, + commit: string | undefined, + version: string | undefined, + machineId: string, + msftInternalDomains: string[] | undefined, + installSourcePath: string, + remoteAuthority?: string +): Promise<{ [name: string]: string | boolean | undefined }> { + const result = await resolveCommonProperties(commit, version, machineId, msftInternalDomains, installSourcePath, undefined); const instanceId = storageService.get(instanceStorageKey, StorageScope.GLOBAL)!; const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!; const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!; diff --git a/src/vs/platform/telemetry/test/browser/commonProperties.test.ts b/src/vs/platform/telemetry/test/browser/commonProperties.test.ts new file mode 100644 index 00000000000..b20c3782758 --- /dev/null +++ b/src/vs/platform/telemetry/test/browser/commonProperties.test.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/browser/workbenchCommonProperties'; +import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage'; + +suite('Browser Telemetry - common properties', function () { + + const commit: string = (undefined)!; + const version: string = (undefined)!; + let testStorageService: IStorageService; + + setup(() => { + testStorageService = new InMemoryStorageService(); + }); + + test('mixes in additional properties', async function () { + const resolveCommonTelemetryProperties = () => { + return { + 'userId': '1' + }; + }; + + const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, undefined, resolveCommonTelemetryProperties); + + assert.ok('commitHash' in props); + assert.ok('sessionID' in props); + assert.ok('timestamp' in props); + assert.ok('common.platform' in props); + assert.ok('common.timesincesessionstart' in props); + assert.ok('common.sequence' in props); + assert.ok('version' in props); + assert.ok('common.firstSessionDate' in props, 'firstSessionDate'); + assert.ok('common.lastSessionDate' in props, 'lastSessionDate'); + assert.ok('common.isNewSession' in props, 'isNewSession'); + assert.ok('common.machineId' in props, 'machineId'); + + assert.equal(props['userId'], '1'); + }); + + test('mixes in additional dyanmic properties', async function () { + let i = 1; + const resolveCommonTelemetryProperties = () => { + return Object.defineProperties({}, { + 'userId': { + get: () => { + return i++; + }, + enumerable: true + } + }); + }; + + const props = await resolveWorkbenchCommonProperties(testStorageService, commit, version, undefined, resolveCommonTelemetryProperties); + assert.equal(props['userId'], '1'); + + const props2 = await resolveWorkbenchCommonProperties(testStorageService, commit, version, undefined, resolveCommonTelemetryProperties); + assert.equal(props2['userId'], '2'); + }); +}); diff --git a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts index 9376104b9c0..a78297b2e4d 100644 --- a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts @@ -70,6 +70,7 @@ class TestableLogService extends AbstractLogService implements ILogService { } dispose(): void { } + flush(): void { } } suite('AIAdapter', () => { @@ -198,4 +199,4 @@ suite('AIAdapter', () => { } }])); }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index e73b91f4277..89c695d2dee 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -103,7 +103,7 @@ class ColorRegistry implements IColorRegistry { public registerColor(id: string, defaults: ColorDefaults | null, description: string, needsTransparency = false, deprecationMessage?: string): ColorIdentifier { let colorContribution: ColorContribution = { id, description, defaults, needsTransparency, deprecationMessage }; this.colorsById[id] = colorContribution; - let propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', default: '#ff0000' }; + let propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', defaultSnippets: [{ body: '#ff0000' }] }; if (deprecationMessage) { propertySchema.deprecationMessage = deprecationMessage; } @@ -227,24 +227,6 @@ export const simpleCheckboxBackground = registerColor('checkbox.background', { d export const simpleCheckboxForeground = registerColor('checkbox.foreground', { dark: selectForeground, light: selectForeground, hc: selectForeground }, nls.localize('checkbox.foreground', "Foreground color of checkbox widget.")); export const simpleCheckboxBorder = registerColor('checkbox.border', { dark: selectBorder, light: selectBorder, hc: selectBorder }, nls.localize('checkbox.border', "Border color of checkbox widget.")); -export const listFocusBackground = registerColor('list.focusBackground', { dark: '#062F4A', light: '#D6EBFF', hc: null }, nls.localize('listFocusBackground', "List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); -export const listFocusForeground = registerColor('list.focusForeground', { dark: null, light: null, hc: null }, nls.localize('listFocusForeground', "List/Tree foreground color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); -export const listActiveSelectionBackground = registerColor('list.activeSelectionBackground', { dark: '#094771', light: '#0074E8', hc: null }, nls.localize('listActiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); -export const listActiveSelectionForeground = registerColor('list.activeSelectionForeground', { dark: Color.white, light: Color.white, hc: null }, nls.localize('listActiveSelectionForeground', "List/Tree foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); -export const listInactiveSelectionBackground = registerColor('list.inactiveSelectionBackground', { dark: '#37373D', light: '#E4E6F1', hc: null }, nls.localize('listInactiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); -export const listInactiveSelectionForeground = registerColor('list.inactiveSelectionForeground', { dark: null, light: null, hc: null }, nls.localize('listInactiveSelectionForeground', "List/Tree foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); -export const listInactiveFocusBackground = registerColor('list.inactiveFocusBackground', { dark: null, light: null, hc: null }, nls.localize('listInactiveFocusBackground', "List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); -export const listHoverBackground = registerColor('list.hoverBackground', { dark: '#2A2D2E', light: '#F0F0F0', hc: null }, nls.localize('listHoverBackground', "List/Tree background when hovering over items using the mouse.")); -export const listHoverForeground = registerColor('list.hoverForeground', { dark: null, light: null, hc: null }, nls.localize('listHoverForeground', "List/Tree foreground when hovering over items using the mouse.")); -export const listDropBackground = registerColor('list.dropBackground', { dark: listFocusBackground, light: listFocusBackground, hc: null }, nls.localize('listDropBackground', "List/Tree drag and drop background when moving items around using the mouse.")); -export const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#0097fb', light: '#0066BF', hc: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.')); -export const listInvalidItemForeground = registerColor('list.invalidItemForeground', { dark: '#B89500', light: '#B89500', hc: '#B89500' }, nls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.')); -export const listErrorForeground = registerColor('list.errorForeground', { dark: '#F88070', light: '#B01011', hc: null }, nls.localize('listErrorForeground', 'Foreground color of list items containing errors.')); -export const listWarningForeground = registerColor('list.warningForeground', { dark: '#CCA700', light: '#855F00', hc: null }, nls.localize('listWarningForeground', 'Foreground color of list items containing warnings.')); -export const listFilterWidgetBackground = registerColor('listFilterWidget.background', { light: '#efc1ad', dark: '#653723', hc: Color.black }, nls.localize('listFilterWidgetBackground', 'Background color of the type filter widget in lists and trees.')); -export const listFilterWidgetOutline = registerColor('listFilterWidget.outline', { dark: Color.transparent, light: Color.transparent, hc: '#f38518' }, nls.localize('listFilterWidgetOutline', 'Outline color of the type filter widget in lists and trees.')); -export const listFilterWidgetNoMatchesOutline = registerColor('listFilterWidget.noMatchesOutline', { dark: '#BE1100', light: '#BE1100', hc: contrastBorder }, nls.localize('listFilterWidgetNoMatchesOutline', 'Outline color of the type filter widget in lists and trees, when there are no matches.')); -export const treeIndentGuidesStroke = registerColor('tree.indentGuidesStroke', { dark: '#585858', light: '#a9a9a9', hc: '#a9a9a9' }, nls.localize('treeIndentGuidesStroke', "Tree stroke color for the indentation guides.")); export const pickerGroupForeground = registerColor('pickerGroup.foreground', { dark: '#3794FF', light: '#0066BF', hc: Color.white }, nls.localize('pickerGroupForeground', "Quick picker color for grouping labels.")); export const pickerGroupBorder = registerColor('pickerGroup.border', { dark: '#3F3F46', light: '#CCCEDB', hc: Color.white }, nls.localize('pickerGroupBorder', "Quick picker color for grouping borders.")); @@ -263,14 +245,6 @@ export const scrollbarSliderActiveBackground = registerColor('scrollbarSlider.ac export const progressBarBackground = registerColor('progressBar.background', { dark: Color.fromHex('#0E70C0'), light: Color.fromHex('#0E70C0'), hc: contrastBorder }, nls.localize('progressBarBackground', "Background color of the progress bar that can show for long running operations.")); -export const menuBorder = registerColor('menu.border', { dark: null, light: null, hc: contrastBorder }, nls.localize('menuBorder', "Border color of menus.")); -export const menuForeground = registerColor('menu.foreground', { dark: selectForeground, light: foreground, hc: selectForeground }, nls.localize('menuForeground', "Foreground color of menu items.")); -export const menuBackground = registerColor('menu.background', { dark: selectBackground, light: selectBackground, hc: selectBackground }, nls.localize('menuBackground', "Background color of menu items.")); -export const menuSelectionForeground = registerColor('menu.selectionForeground', { dark: listActiveSelectionForeground, light: listActiveSelectionForeground, hc: listActiveSelectionForeground }, nls.localize('menuSelectionForeground', "Foreground color of the selected menu item in menus.")); -export const menuSelectionBackground = registerColor('menu.selectionBackground', { dark: listActiveSelectionBackground, light: listActiveSelectionBackground, hc: listActiveSelectionBackground }, nls.localize('menuSelectionBackground', "Background color of the selected menu item in menus.")); -export const menuSelectionBorder = registerColor('menu.selectionBorder', { dark: null, light: null, hc: activeContrastBorder }, nls.localize('menuSelectionBorder', "Border color of the selected menu item in menus.")); -export const menuSeparatorBackground = registerColor('menu.separatorBackground', { dark: '#BBBBBB', light: '#888888', hc: contrastBorder }, nls.localize('menuSeparatorBackground', "Color of a separator menu item in menus.")); - export const editorErrorForeground = registerColor('editorError.foreground', { dark: '#F48771', light: '#E51400', hc: null }, nls.localize('editorError.foreground', '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 boxes in the editor.')); @@ -330,9 +304,9 @@ export const editorFindRangeHighlightBorder = registerColor('editor.findRangeHig */ export const editorHoverHighlight = registerColor('editor.hoverHighlightBackground', { light: '#ADD6FF26', dark: '#264f7840', hc: '#ADD6FF26' }, nls.localize('hoverHighlight', 'Highlight below the word for which a hover is shown. The color must not be opaque so as not to hide underlying decorations.'), true); export const editorHoverBackground = registerColor('editorHoverWidget.background', { light: editorWidgetBackground, dark: editorWidgetBackground, hc: editorWidgetBackground }, nls.localize('hoverBackground', 'Background color of the editor hover.')); +export const editorHoverForeground = registerColor('editorHoverWidget.foreground', { light: editorWidgetForeground, dark: editorWidgetForeground, hc: editorWidgetForeground }, nls.localize('hoverForeground', 'Foreground color of the editor hover.')); export const editorHoverBorder = registerColor('editorHoverWidget.border', { light: editorWidgetBorder, dark: editorWidgetBorder, hc: editorWidgetBorder }, nls.localize('hoverBorder', 'Border color of the editor hover.')); export const editorHoverStatusBarBackground = registerColor('editorHoverWidget.statusBarBackground', { dark: lighten(editorHoverBackground, 0.2), light: darken(editorHoverBackground, 0.05), hc: editorWidgetBackground }, nls.localize('statusBarBackground', "Background color of the editor hover status bar.")); - /** * Editor link colors */ @@ -358,6 +332,41 @@ export const diffRemovedOutline = registerColor('diffEditor.removedTextBorder', export const diffBorder = registerColor('diffEditor.border', { dark: null, light: null, hc: contrastBorder }, nls.localize('diffEditorBorder', 'Border color between the two text editors.')); +/** + * List and tree colors + */ +export const listFocusBackground = registerColor('list.focusBackground', { dark: '#062F4A', light: '#D6EBFF', hc: null }, nls.localize('listFocusBackground', "List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); +export const listFocusForeground = registerColor('list.focusForeground', { dark: null, light: null, hc: null }, nls.localize('listFocusForeground', "List/Tree foreground color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); +export const listActiveSelectionBackground = registerColor('list.activeSelectionBackground', { dark: '#094771', light: '#0074E8', hc: null }, nls.localize('listActiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); +export const listActiveSelectionForeground = registerColor('list.activeSelectionForeground', { dark: Color.white, light: Color.white, hc: null }, nls.localize('listActiveSelectionForeground', "List/Tree foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.")); +export const listInactiveSelectionBackground = registerColor('list.inactiveSelectionBackground', { dark: '#37373D', light: '#E4E6F1', hc: null }, nls.localize('listInactiveSelectionBackground', "List/Tree background color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); +export const listInactiveSelectionForeground = registerColor('list.inactiveSelectionForeground', { dark: null, light: null, hc: null }, nls.localize('listInactiveSelectionForeground', "List/Tree foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); +export const listInactiveFocusBackground = registerColor('list.inactiveFocusBackground', { dark: null, light: null, hc: null }, nls.localize('listInactiveFocusBackground', "List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.")); +export const listHoverBackground = registerColor('list.hoverBackground', { dark: '#2A2D2E', light: '#F0F0F0', hc: null }, nls.localize('listHoverBackground', "List/Tree background when hovering over items using the mouse.")); +export const listHoverForeground = registerColor('list.hoverForeground', { dark: null, light: null, hc: null }, nls.localize('listHoverForeground', "List/Tree foreground when hovering over items using the mouse.")); +export const listDropBackground = registerColor('list.dropBackground', { dark: listFocusBackground, light: listFocusBackground, hc: null }, nls.localize('listDropBackground', "List/Tree drag and drop background when moving items around using the mouse.")); +export const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#0097fb', light: '#0066BF', hc: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.')); +export const listInvalidItemForeground = registerColor('list.invalidItemForeground', { dark: '#B89500', light: '#B89500', hc: '#B89500' }, nls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.')); +export const listErrorForeground = registerColor('list.errorForeground', { dark: '#F88070', light: '#B01011', hc: null }, nls.localize('listErrorForeground', 'Foreground color of list items containing errors.')); +export const listWarningForeground = registerColor('list.warningForeground', { dark: '#CCA700', light: '#855F00', hc: null }, nls.localize('listWarningForeground', 'Foreground color of list items containing warnings.')); +export const listFilterWidgetBackground = registerColor('listFilterWidget.background', { light: '#efc1ad', dark: '#653723', hc: Color.black }, nls.localize('listFilterWidgetBackground', 'Background color of the type filter widget in lists and trees.')); +export const listFilterWidgetOutline = registerColor('listFilterWidget.outline', { dark: Color.transparent, light: Color.transparent, hc: '#f38518' }, nls.localize('listFilterWidgetOutline', 'Outline color of the type filter widget in lists and trees.')); +export const listFilterWidgetNoMatchesOutline = registerColor('listFilterWidget.noMatchesOutline', { dark: '#BE1100', light: '#BE1100', hc: contrastBorder }, nls.localize('listFilterWidgetNoMatchesOutline', 'Outline color of the type filter widget in lists and trees, when there are no matches.')); +export const listFilterMatchHighlight = registerColor('list.filterMatchBackground', { dark: editorFindMatchHighlight, light: editorFindMatchHighlight, hc: null }, nls.localize('listFilterMatchHighlight', 'Background color of the filtered match.')); +export const listFilterMatchHighlightBorder = registerColor('list.filterMatchBorder', { dark: editorFindMatchHighlightBorder, light: editorFindMatchHighlightBorder, hc: contrastBorder }, nls.localize('listFilterMatchHighlightBorder', 'Border color of the filtered match.')); +export const treeIndentGuidesStroke = registerColor('tree.indentGuidesStroke', { dark: '#585858', light: '#a9a9a9', hc: '#a9a9a9' }, nls.localize('treeIndentGuidesStroke', "Tree stroke color for the indentation guides.")); + +/** + * Menu colors + */ +export const menuBorder = registerColor('menu.border', { dark: null, light: null, hc: contrastBorder }, nls.localize('menuBorder', "Border color of menus.")); +export const menuForeground = registerColor('menu.foreground', { dark: selectForeground, light: foreground, hc: selectForeground }, nls.localize('menuForeground', "Foreground color of menu items.")); +export const menuBackground = registerColor('menu.background', { dark: selectBackground, light: selectBackground, hc: selectBackground }, nls.localize('menuBackground', "Background color of menu items.")); +export const menuSelectionForeground = registerColor('menu.selectionForeground', { dark: listActiveSelectionForeground, light: listActiveSelectionForeground, hc: listActiveSelectionForeground }, nls.localize('menuSelectionForeground', "Foreground color of the selected menu item in menus.")); +export const menuSelectionBackground = registerColor('menu.selectionBackground', { dark: listActiveSelectionBackground, light: listActiveSelectionBackground, hc: listActiveSelectionBackground }, nls.localize('menuSelectionBackground', "Background color of the selected menu item in menus.")); +export const menuSelectionBorder = registerColor('menu.selectionBorder', { dark: null, light: null, hc: activeContrastBorder }, nls.localize('menuSelectionBorder', "Border color of the selected menu item in menus.")); +export const menuSeparatorBackground = registerColor('menu.separatorBackground', { dark: '#BBBBBB', light: '#888888', hc: contrastBorder }, nls.localize('menuSeparatorBackground', "Color of a separator menu item in menus.")); + /** * Snippet placeholder colors */ @@ -404,8 +413,11 @@ export const overviewRulerFindMatchForeground = registerColor('editorOverviewRul export const overviewRulerSelectionHighlightForeground = registerColor('editorOverviewRuler.selectionHighlightForeground', { dark: '#A0A0A0CC', light: '#A0A0A0CC', hc: '#A0A0A0CC' }, nls.localize('overviewRulerSelectionHighlightForeground', 'Overview ruler marker color for selection highlights. The color must not be opaque so as not to hide underlying decorations.'), true); export const minimapFindMatch = registerColor('minimap.findMatchHighlight', { light: '#d18616', dark: '#d18616', hc: '#AB5A00' }, nls.localize('minimapFindMatchHighlight', 'Minimap marker color for find matches.'), true); -export const minimapSelection = registerColor('minimap.selectionHighlight', { light: '#ADD6FF', dark: '#264F78', hc: '#f3f518' }, nls.localize('minimapSelectionHighlight', 'Minimap marker color for the current editor selection.'), true); +export const minimapSelection = registerColor('minimap.selectionHighlight', { light: '#ADD6FF', dark: '#264F78', hc: '#ffffff' }, nls.localize('minimapSelectionHighlight', 'Minimap marker color for the editor selection.'), true); +export const problemsErrorIconForeground = registerColor('problemsErrorIcon.foreground', { dark: editorErrorForeground, light: editorErrorForeground, hc: editorErrorForeground }, nls.localize('problemsErrorIconForeground', "The color used for the problems error icon.")); +export const problemsWarningIconForeground = registerColor('problemsWarningIcon.foreground', { dark: editorWarningForeground, light: editorWarningForeground, hc: editorWarningForeground }, nls.localize('problemsWarningIconForeground', "The color used for the problems warning icon.")); +export const problemsInfoIconForeground = registerColor('problemsInfoIcon.foreground', { dark: editorInfoForeground, light: editorInfoForeground, hc: editorInfoForeground }, nls.localize('problemsInfoIconForeground', "The color used for the problems info icon.")); // ----- color functions @@ -473,7 +485,7 @@ function lessProminent(colorValue: ColorValue, backgroundColorValue: ColorValue, /** * @param colorValue Resolve a color value in the context of a theme */ -function resolveColorValue(colorValue: ColorValue | null, theme: ITheme): Color | undefined { +export function resolveColorValue(colorValue: ColorValue | null, theme: ITheme): Color | undefined { if (colorValue === null) { return undefined; } else if (typeof colorValue === 'string') { diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index 8ce034bd94c..56f0deef229 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground } from 'vs/platform/theme/common/colorRegistry'; +import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; @@ -20,7 +20,7 @@ export interface IThemable { } export interface IColorMapping { - [optionsKey: string]: ColorIdentifier | ColorFunction | undefined; + [optionsKey: string]: ColorValue | undefined; } export interface IComputedStyles { @@ -30,11 +30,9 @@ export interface IComputedStyles { export function computeStyles(theme: ITheme, styleMap: IColorMapping): IComputedStyles { const styles = Object.create(null) as IComputedStyles; for (let key in styleMap) { - const value = styleMap[key as string]; - if (typeof value === 'string') { - styles[key] = theme.getColor(value); - } else if (typeof value === 'function') { - styles[key] = value(theme); + const value = styleMap[key]; + if (value) { + styles[key] = resolveColorValue(value, theme); } } diff --git a/src/vs/platform/theme/electron-main/themeMainService.ts b/src/vs/platform/theme/electron-main/themeMainService.ts index e9b43cea979..8cd6ecdcaa7 100644 --- a/src/vs/platform/theme/electron-main/themeMainService.ts +++ b/src/vs/platform/theme/electron-main/themeMainService.ts @@ -5,7 +5,7 @@ import { isWindows, isMacintosh } from 'vs/base/common/platform'; import { systemPreferences, ipcMain as ipc } from 'electron'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; const DEFAULT_BG_LIGHT = '#FFFFFF'; diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index cd73a5cd95a..d25c577b66e 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as electron from 'electron'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { memoize } from 'vs/base/common/decorators'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -20,7 +20,7 @@ export class DarwinUpdateService extends AbstractUpdateService { _serviceBrand: undefined; - private disposables: IDisposable[] = []; + private readonly disposables = new DisposableStore(); @memoize private get onRawError(): Event { return Event.fromNodeEventEmitter(electron.autoUpdater, 'error', (_, message) => message); } @memoize private get onRawUpdateNotAvailable(): Event { return Event.fromNodeEventEmitter(electron.autoUpdater, 'update-not-available'); } @@ -104,6 +104,6 @@ export class DarwinUpdateService extends AbstractUpdateService { } dispose(): void { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); } } diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts index 8b59c871d09..bdc5c591947 100644 --- a/src/vs/platform/update/electron-main/updateService.linux.ts +++ b/src/vs/platform/update/electron-main/updateService.linux.ts @@ -41,7 +41,7 @@ export class LinuxUpdateService extends AbstractUpdateService { this.setState(State.CheckingForUpdates(context)); this.requestService.request({ url: this.url }, CancellationToken.None) - .then(asJson) + .then(asJson) .then(update => { if (!update || !update.url || !update.version || !update.productVersion) { this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context }); diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index c053fda3904..8f87787b9e7 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -109,7 +109,7 @@ export class Win32UpdateService extends AbstractUpdateService { this.setState(State.CheckingForUpdates(context)); this.requestService.request({ url: this.url }, CancellationToken.None) - .then(asJson) + .then(asJson) .then(update => { const updateType = getUpdateType(); diff --git a/src/vs/platform/url/common/url.ts b/src/vs/platform/url/common/url.ts index 479bc0bca73..097a2398e9b 100644 --- a/src/vs/platform/url/common/url.ts +++ b/src/vs/platform/url/common/url.ts @@ -9,8 +9,19 @@ import { IDisposable } from 'vs/base/common/lifecycle'; export const IURLService = createDecorator('urlService'); +export interface IOpenURLOptions { + + /** + * If not provided or `false`, signals that the + * URL to open did not originate from the product + * but outside. As such, a confirmation dialog + * might be shown to the user. + */ + trusted?: boolean; +} + export interface IURLHandler { - handleURL(uri: URI): Promise; + handleURL(uri: URI, options?: IOpenURLOptions): Promise; } export interface IURLService { @@ -24,7 +35,7 @@ export interface IURLService { */ create(options?: Partial): URI; - open(url: URI): Promise; + open(url: URI, options?: IOpenURLOptions): Promise; registerHandler(handler: IURLHandler): IDisposable; } diff --git a/src/vs/platform/url/common/urlIpc.ts b/src/vs/platform/url/common/urlIpc.ts index b692e67dfd9..0a4c13faaff 100644 --- a/src/vs/platform/url/common/urlIpc.ts +++ b/src/vs/platform/url/common/urlIpc.ts @@ -4,49 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { IChannel, IServerChannel, IClientRouter, IConnectionHub, Client } from 'vs/base/parts/ipc/common/ipc'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; -import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; +import { IURLHandler, IOpenURLOptions } from 'vs/platform/url/common/url'; import { CancellationToken } from 'vs/base/common/cancellation'; import { first } from 'vs/base/common/arrays'; -export class URLServiceChannel implements IServerChannel { - - constructor(private service: IURLService) { } - - listen(_: unknown, event: string): Event { - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'open': return this.service.open(URI.revive(arg)); - } - - throw new Error(`Call not found: ${command}`); - } -} - -export class URLServiceChannelClient implements IURLService { - - _serviceBrand: undefined; - - constructor(private channel: IChannel) { } - - open(url: URI): Promise { - return this.channel.call('open', url.toJSON()); - } - - registerHandler(handler: IURLHandler): IDisposable { - throw new Error('Not implemented.'); - } - - create(_options?: Partial): URI { - throw new Error('Method not implemented.'); - } -} - export class URLHandlerChannel implements IServerChannel { constructor(private handler: IURLHandler) { } @@ -68,7 +31,7 @@ export class URLHandlerChannelClient implements IURLHandler { constructor(private channel: IChannel) { } - handleURL(uri: URI): Promise { + handleURL(uri: URI, options?: IOpenURLOptions): Promise { return this.channel.call('handleURL', uri.toJSON()); } } @@ -86,11 +49,12 @@ export class URLHandlerRouter implements IClientRouter { const uri = URI.revive(arg); if (uri && uri.query) { - const match = /\bwindowId=([^&]+)/.exec(uri.query); + const match = /\bwindowId=(\d+)/.exec(uri.query); if (match) { const windowId = match[1]; - const connection = first(hub.connections, c => c.ctx === windowId); + const regex = new RegExp(`window:${windowId}`); + const connection = first(hub.connections, c => regex.test(c.ctx)); if (connection) { return connection; diff --git a/src/vs/platform/url/common/urlService.ts b/src/vs/platform/url/common/urlService.ts index 322929c723d..030d52b587e 100644 --- a/src/vs/platform/url/common/urlService.ts +++ b/src/vs/platform/url/common/urlService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; +import { IURLService, IURLHandler, IOpenURLOptions } from 'vs/platform/url/common/url'; import { URI, UriComponents } from 'vs/base/common/uri'; import { values } from 'vs/base/common/map'; import { first } from 'vs/base/common/async'; @@ -17,9 +17,9 @@ export abstract class AbstractURLService extends Disposable implements IURLServi abstract create(options?: Partial): URI; - open(uri: URI): Promise { + open(uri: URI, options?: IOpenURLOptions): Promise { const handlers = values(this.handlers); - return first(handlers.map(h => () => h.handleURL(uri)), undefined, false).then(val => val || false); + return first(handlers.map(h => () => h.handleURL(uri, options)), undefined, false).then(val => val || false); } registerHandler(handler: IURLHandler): IDisposable { diff --git a/src/vs/platform/url/electron-main/electronUrlListener.ts b/src/vs/platform/url/electron-main/electronUrlListener.ts index 5a72da5d3ff..e202c4af199 100644 --- a/src/vs/platform/url/electron-main/electronUrlListener.ts +++ b/src/vs/platform/url/electron-main/electronUrlListener.ts @@ -8,10 +8,11 @@ import { IURLService } from 'vs/platform/url/common/url'; import product from 'vs/platform/product/common/product'; import { app, Event as ElectronEvent } from 'electron'; import { URI } from 'vs/base/common/uri'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; import { isWindows } from 'vs/base/common/platform'; import { coalesce } from 'vs/base/common/arrays'; +import { disposableTimeout } from 'vs/base/common/async'; function uriFromRawUrl(url: string): URI | null { try { @@ -23,7 +24,10 @@ function uriFromRawUrl(url: string): URI | null { export class ElectronURLListener { - private disposables: IDisposable[] = []; + private uris: URI[] = []; + private retryCount = 0; + private flushDisposable: IDisposable = Disposable.None; + private disposables = new DisposableStore(); constructor( initial: string | string[], @@ -36,12 +40,7 @@ export class ElectronURLListener { ...globalBuffer ]; - const buffer = coalesce(rawBuffer.map(uriFromRawUrl)); - const flush = () => buffer.forEach(uri => { - if (uri) { - urlService.open(uri); - } - }); + this.uris = coalesce(rawBuffer.map(uriFromRawUrl)); if (isWindows) { app.setAsDefaultProtocolClient(product.urlProtocol, process.execPath, ['--open-url', '--']); @@ -63,13 +62,37 @@ export class ElectronURLListener { .length > 0; if (isWindowReady) { - flush(); + this.flush(); } else { - Event.once(windowsMainService.onWindowReady)(flush); + Event.once(windowsMainService.onWindowReady)(this.flush, this, this.disposables); } } + private async flush(): Promise { + if (this.retryCount++ > 10) { + return; + } + + const uris: URI[] = []; + + for (const uri of this.uris) { + const handled = await this.urlService.open(uri); + + if (!handled) { + uris.push(uri); + } + } + + if (uris.length === 0) { + return; + } + + this.uris = uris; + this.flushDisposable = disposableTimeout(() => this.flush(), 500); + } + dispose(): void { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); + this.flushDisposable.dispose(); } } diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index 4d507e6dc5e..54fcb05a56c 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, IUserDataSyncStoreService, ISyncExtension } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { Emitter, Event } from 'vs/base/common/event'; -import { ILogService } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; @@ -47,7 +46,7 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser @IFileService private readonly fileService: IFileService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, - @ILogService private readonly logService: ILogService, + @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IConfigurationService private readonly configurationService: IConfigurationService, ) { @@ -70,14 +69,17 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser } async sync(): Promise { - if (!this.configurationService.getValue('userConfiguration.syncExtensions')) { + if (!this.configurationService.getValue('configurationSync.enableExtensions')) { + this.logService.trace('Extensions: Skipping synchronizing extensions as it is disabled.'); return false; } if (this.status !== SyncStatus.Idle) { + this.logService.trace('Extensions: Skipping synchronizing extensions as it is running already.'); return false; } + this.logService.trace('Extensions: Started synchronizing extensions...'); this.setStatus(SyncStatus.Syncing); try { @@ -86,30 +88,30 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser this.setStatus(SyncStatus.Idle); if (e instanceof UserDataSyncStoreError && e.code === UserDataSyncStoreErrorCode.Rejected) { // Rejected as there is a new remote version. Syncing again, - this.logService.info('Failed to Synchronise extensions as there is a new remote version available. Synchronising again...'); + this.logService.info('Extensions: Failed to synchronise extensions as there is a new remote version available. Synchronizing again...'); return this.sync(); } throw e; } + this.logService.trace('Extensions: Finised synchronizing extensions.'); this.setStatus(SyncStatus.Idle); return true; } - async getRemoteExtensions(): Promise { - const remoteData = await this.userDataSyncStoreService.read(ExtensionsSynchroniser.EXTERNAL_USER_DATA_EXTENSIONS_KEY, null); - return remoteData.content ? JSON.parse(remoteData.content) : []; - } + stop(): void { } removeExtension(identifier: IExtensionIdentifier): Promise { return this.replaceQueue.queue(async () => { const remoteData = await this.userDataSyncStoreService.read(ExtensionsSynchroniser.EXTERNAL_USER_DATA_EXTENSIONS_KEY, null); const remoteExtensions: ISyncExtension[] = remoteData.content ? JSON.parse(remoteData.content) : []; - const removedExtensions = remoteExtensions.filter(e => areSameExtensions(e.identifier, identifier)); + const ignoredExtensions = this.configurationService.getValue('configurationSync.extensionsToIgnore') || []; + const removedExtensions = remoteExtensions.filter(e => !ignoredExtensions.some(id => areSameExtensions({ id }, e.identifier)) && areSameExtensions(e.identifier, identifier)); if (removedExtensions.length) { for (const removedExtension of removedExtensions) { remoteExtensions.splice(remoteExtensions.indexOf(removedExtension), 1); } + this.logService.info(`Extensions: Removing extension '${identifier.id}' from remote.`); await this.writeToRemote(remoteExtensions, remoteData.ref); } }); @@ -123,18 +125,31 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser const remoteExtensions: ISyncExtension[] = remoteData.content ? JSON.parse(remoteData.content) : null; const localExtensions = await this.getLocalExtensions(); + this.logService.trace('Extensions: Merging remote extensions with local extensions...'); const { added, removed, updated, remote } = this.merge(localExtensions, remoteExtensions, lastSyncExtensions); - // update local - await this.updateLocalExtensions(added, removed, updated); + if (!added.length && !removed.length && !updated.length && !remote) { + this.logService.trace('Extensions: No changes found during synchronizing extensions.'); + } + + if (added.length || removed.length || updated.length) { + this.logService.info('Extensions: Updating local extensions...'); + await this.updateLocalExtensions(added, removed, updated); + } if (remote) { // update remote + this.logService.info('Extensions: Updating remote extensions...'); remoteData = await this.writeToRemote(remote, remoteData.ref); } - // update last sync - await this.updateLastSyncValue(remoteData); + if (remoteData.content + && (!lastSyncData || lastSyncData.ref !== remoteData.ref) + ) { + // update last sync + this.logService.info('Extensions: Updating last synchronised extensions...'); + await this.updateLastSyncValue(remoteData); + } } /** @@ -144,10 +159,11 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser * - Update remote with those local extension which are newly added or updated or removed and untouched in remote. */ private merge(localExtensions: ISyncExtension[], remoteExtensions: ISyncExtension[] | null, lastSyncExtensions: ISyncExtension[] | null): { added: ISyncExtension[], removed: IExtensionIdentifier[], updated: ISyncExtension[], remote: ISyncExtension[] | null } { - + const ignoredExtensions = this.configurationService.getValue('configurationSync.extensionsToIgnore') || []; // First time sync if (!remoteExtensions) { - return { added: [], removed: [], updated: [], remote: localExtensions }; + this.logService.info('Extensions: Remote extensions does not exist. Synchronizing extensions for the first time.'); + return { added: [], removed: [], updated: [], remote: localExtensions.filter(({ identifier }) => ignoredExtensions.some(id => id.toLowerCase() === identifier.id.toLowerCase())) }; } const uuids: Map = new Map(); @@ -168,8 +184,12 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser const remoteExtensionsMap = remoteExtensions.reduce(addExtensionToMap, new Map()); const newRemoteExtensionsMap = remoteExtensions.reduce(addExtensionToMap, new Map()); const lastSyncExtensionsMap = lastSyncExtensions ? lastSyncExtensions.reduce(addExtensionToMap, new Map()) : null; + const ignoredExtensionsSet = ignoredExtensions.reduce((set, id) => { + const uuid = uuids.get(id.toLowerCase()); + return set.add(uuid ? `uuid:${uuid}` : `id:${id.toLowerCase()}`); + }, new Set()); - const localToRemote = this.compare(localExtensionsMap, remoteExtensionsMap); + const localToRemote = this.compare(localExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet); if (localToRemote.added.size === 0 && localToRemote.removed.size === 0 && localToRemote.updated.size === 0) { // No changes found between local and remote. return { added: [], removed: [], updated: [], remote: null }; @@ -179,8 +199,8 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser const removed: IExtensionIdentifier[] = []; const updated: ISyncExtension[] = []; - const baseToLocal = lastSyncExtensionsMap ? this.compare(lastSyncExtensionsMap, localExtensionsMap) : { added: keys(localExtensionsMap).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; - const baseToRemote = lastSyncExtensionsMap ? this.compare(lastSyncExtensionsMap, remoteExtensionsMap) : { added: keys(remoteExtensionsMap).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; + const baseToLocal = lastSyncExtensionsMap ? this.compare(lastSyncExtensionsMap, localExtensionsMap, ignoredExtensionsSet) : { added: keys(localExtensionsMap).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; + const baseToRemote = lastSyncExtensionsMap ? this.compare(lastSyncExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet) : { added: keys(remoteExtensionsMap).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; const massageSyncExtension = (extension: ISyncExtension, key: string): ISyncExtension => { return { @@ -256,14 +276,14 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser } } - const remoteChanges = this.compare(remoteExtensionsMap, newRemoteExtensionsMap); + const remoteChanges = this.compare(remoteExtensionsMap, newRemoteExtensionsMap, new Set()); const remote = remoteChanges.added.size > 0 || remoteChanges.updated.size > 0 || remoteChanges.removed.size > 0 ? values(newRemoteExtensionsMap) : null; return { added, removed, updated, remote }; } - private compare(from: Map, to: Map): { added: Set, removed: Set, updated: Set } { - const fromKeys = keys(from); - const toKeys = keys(to); + private compare(from: Map, to: Map, ignoredExtensions: Set): { added: Set, removed: Set, updated: Set } { + const fromKeys = keys(from).filter(key => !ignoredExtensions.has(key)); + const toKeys = keys(to).filter(key => !ignoredExtensions.has(key)); const added = toKeys.filter(key => fromKeys.indexOf(key) === -1).reduce((r, key) => { r.add(key); return r; }, new Set()); const removed = fromKeys.filter(key => toKeys.indexOf(key) === -1).reduce((r, key) => { r.add(key); return r; }, new Set()); const updated: Set = new Set(); @@ -289,13 +309,17 @@ export class ExtensionsSynchroniser extends Disposable implements ISynchroniser if (removed.length) { const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User); const extensionsToRemove = installedExtensions.filter(({ identifier }) => removed.some(r => areSameExtensions(identifier, r))); - await Promise.all(extensionsToRemove.map(e => this.extensionManagementService.uninstall(e))); + await Promise.all(extensionsToRemove.map(e => { + this.logService.info('Extensions: Removing local extension.', e.identifier.id); + return this.extensionManagementService.uninstall(e); + })); } if (added.length || updated.length) { await Promise.all([...added, ...updated].map(async e => { const extension = await this.extensionGalleryService.getCompatibleExtension(e.identifier, e.version); if (extension) { + this.logService.info('Extensions: Installing local extension.', e.identifier.id, extension.version); await this.extensionManagementService.installFromGallery(extension); } })); diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index 17ef43624d1..03d97cc1418 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -5,18 +5,18 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files'; -import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, DEFAULT_IGNORED_SETTINGS, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse, ParseError } from 'vs/base/common/json'; import { localize } from 'vs/nls'; import { Emitter, Event } from 'vs/base/common/event'; -import { ILogService } from 'vs/platform/log/common/log'; import { CancelablePromise, createCancelablePromise, ThrottledDelayer } from 'vs/base/common/async'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; -import { IStringDictionary } from 'vs/base/common/collections'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { startsWith } from 'vs/base/common/strings'; +import { CancellationToken } from 'vs/base/common/cancellation'; interface ISyncPreviewResult { readonly fileContent: IFileContent | null; @@ -48,7 +48,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { @IEnvironmentService private readonly environmentService: IEnvironmentService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @ISettingsMergeService private readonly settingsMergeService: ISettingsMergeService, - @ILogService private readonly logService: ILogService, + @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IConfigurationService private readonly configurationService: IConfigurationService, ) { super(); @@ -80,20 +80,28 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { } async sync(_continue?: boolean): Promise { + if (!this.configurationService.getValue('configurationSync.enableSettings')) { + this.logService.trace('Settings: Skipping synchronizing settings as it is disabled.'); + return false; + } if (_continue) { + this.logService.info('Settings: Resumed synchronizing settings'); return this.continueSync(); } if (this.status !== SyncStatus.Idle) { + this.logService.trace('Settings: Skipping synchronizing settings as it is running already.'); return false; } + this.logService.trace('Settings: Started synchronizing settings...'); this.setStatus(SyncStatus.Syncing); try { const result = await this.getPreview(); if (result.hasConflicts) { + this.logService.info('Settings: Detected conflicts while synchronizing settings.'); this.setStatus(SyncStatus.HasConflicts); return false; } @@ -104,18 +112,28 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { this.setStatus(SyncStatus.Idle); if (e instanceof UserDataSyncStoreError && e.code === UserDataSyncStoreErrorCode.Rejected) { // Rejected as there is a new remote version. Syncing again, - this.logService.info('Failed to Synchronise settings as there is a new remote version available. Synchronising again...'); + this.logService.info('Settings: Failed to synchronise settings as there is a new remote version available. Synchronizing again...'); return this.sync(); } if (e instanceof FileSystemProviderError && e.code === FileSystemProviderErrorCode.FileExists) { // Rejected as there is a new local version. Syncing again. - this.logService.info('Failed to Synchronise settings as there is a new local version available. Synchronising again...'); + this.logService.info('Settings: Failed to synchronise settings as there is a new local version available. Synchronizing again...'); return this.sync(); } throw e; } } + stop(): void { + if (this.syncPreviewResultPromise) { + this.syncPreviewResultPromise.cancel(); + this.syncPreviewResultPromise = null; + this.logService.info('Settings: Stopped synchronizing settings.'); + } + this.fileService.del(this.environmentService.settingsSyncPreviewResource); + this.setStatus(SyncStatus.Idle); + } + private async continueSync(): Promise { if (this.status !== SyncStatus.HasConflicts) { return false; @@ -133,44 +151,55 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { const settingsPreivew = await this.fileService.readFile(this.environmentService.settingsSyncPreviewResource); const content = settingsPreivew.value.toString(); if (this.hasErrors(content)) { - return Promise.reject(localize('errorInvalidSettings', "Unable to sync settings. Please resolve conflicts without any errors/warnings and try again.")); + const error = new Error(localize('errorInvalidSettings', "Unable to sync settings. Please resolve conflicts without any errors/warnings and try again.")); + this.logService.error(error); + throw error; } let { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged } = await this.syncPreviewResultPromise; + if (!hasLocalChanged && !hasRemoteChanged) { + this.logService.trace('Settings: No changes found during synchronizing settings.'); + } + if (hasLocalChanged) { + this.logService.info('Settings: Updating local settings'); + await this.writeToLocal(content, fileContent); + } if (hasRemoteChanged) { - const remoteContent = remoteUserData.content ? await this.settingsMergeService.computeRemoteContent(content, remoteUserData.content, this.getIgnoredSettings()) : content; + const remoteContent = remoteUserData.content ? await this.settingsMergeService.computeRemoteContent(content, remoteUserData.content, this.getIgnoredSettings(content)) : content; + this.logService.info('Settings: Updating remote settings'); const ref = await this.writeToRemote(remoteContent, remoteUserData.ref); remoteUserData = { ref, content }; } - if (hasLocalChanged) { - await this.writeToLocal(content, fileContent); - } if (remoteUserData.content) { + this.logService.info('Settings: Updating last synchronised sttings'); await this.updateLastSyncValue(remoteUserData); } // Delete the preview await this.fileService.del(this.environmentService.settingsSyncPreviewResource); + } else { + this.logService.trace('Settings: No changes found during synchronizing settings.'); } + this.logService.trace('Settings: Finised synchronizing settings.'); this.syncPreviewResultPromise = null; this.setStatus(SyncStatus.Idle); } private hasErrors(content: string): boolean { const parseErrors: ParseError[] = []; - parse(content, parseErrors); + parse(content, parseErrors, { allowEmptyContent: true, allowTrailingComma: true }); return parseErrors.length > 0; } private getPreview(): Promise { if (!this.syncPreviewResultPromise) { - this.syncPreviewResultPromise = createCancelablePromise(token => this.generatePreview()); + this.syncPreviewResultPromise = createCancelablePromise(token => this.generatePreview(token)); } return this.syncPreviewResultPromise; } - private async generatePreview(): Promise { + private async generatePreview(token: CancellationToken): Promise { const lastSyncData = await this.getLastSyncUserData(); const remoteUserData = await this.userDataSyncStoreService.read(SettingsSynchroniser.EXTERNAL_USER_DATA_SETTINGS_KEY, lastSyncData); const remoteContent: string | null = remoteUserData.content; @@ -179,39 +208,66 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { let hasLocalChanged: boolean = false; let hasRemoteChanged: boolean = false; let hasConflicts: boolean = false; + let previewContent = null; if (remoteContent) { const localContent: string = fileContent ? fileContent.value.toString() : '{}'; + if (this.hasErrors(localContent)) { + this.logService.error('Settings: Unable to sync settings as there are errors/warning in settings file.'); + return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; + } + if (!lastSyncData // First time sync || lastSyncData.content !== localContent // Local has moved forwarded || lastSyncData.content !== remoteContent // Remote has moved forwarded ) { - this.logService.trace('Settings Sync: Merging remote contents with settings file.'); + this.logService.trace('Settings: Merging remote settings with local settings...'); const result = await this.settingsMergeService.merge(localContent, remoteContent, lastSyncData ? lastSyncData.content : null, this.getIgnoredSettings()); // Sync only if there are changes if (result.hasChanges) { hasLocalChanged = result.mergeContent !== localContent; hasRemoteChanged = result.mergeContent !== remoteContent; hasConflicts = result.hasConflicts; - await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(result.mergeContent)); + previewContent = result.mergeContent; } } - return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; } - // First time sync to remote - if (fileContent) { - this.logService.trace('Settings Sync: Remote contents does not exist. So sync with settings file.'); + // First time syncing to remote + else if (fileContent) { + this.logService.info('Settings: Remote settings does not exist. Synchronizing settings for the first time.'); hasRemoteChanged = true; - await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(fileContent.value.toString())); - return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; + previewContent = fileContent.value.toString(); + } + + if (previewContent && !token.isCancellationRequested) { + await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(previewContent)); } return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; } - private getIgnoredSettings(): IStringDictionary { - return this.configurationService.getValue>('userConfiguration.ignoreSettings'); + private getIgnoredSettings(settingsContent?: string): string[] { + let value: string[] = []; + if (settingsContent) { + const setting = parse(settingsContent); + if (setting) { + value = setting['configurationSync.settingsToIgnore']; + } + } else { + value = this.configurationService.getValue('configurationSync.settingsToIgnore'); + } + const added: string[] = [], removed: string[] = []; + if (Array.isArray(value)) { + for (const key of value) { + if (startsWith(key, '-')) { + removed.push(key.substring(1)); + } else { + added.push(key); + } + } + } + return [...DEFAULT_IGNORED_SETTINGS, ...added].filter(setting => removed.indexOf(setting) === -1); } private async getLastSyncUserData(): Promise { diff --git a/src/vs/platform/userDataSync/common/settingsSyncIpc.ts b/src/vs/platform/userDataSync/common/settingsSyncIpc.ts index 6f14928a58d..3f231e86454 100644 --- a/src/vs/platform/userDataSync/common/settingsSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/settingsSyncIpc.ts @@ -6,7 +6,6 @@ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; import { ISettingsMergeService } from 'vs/platform/userDataSync/common/userDataSync'; -import { IStringDictionary } from 'vs/base/common/collections'; export class SettingsMergeChannel implements IServerChannel { @@ -32,11 +31,11 @@ export class SettingsMergeChannelClient implements ISettingsMergeService { constructor(private readonly channel: IChannel) { } - merge(localContent: string, remoteContent: string, baseContent: string | null, ignoredSettings: IStringDictionary): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> { + merge(localContent: string, remoteContent: string, baseContent: string | null, ignoredSettings: string[]): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> { return this.channel.call('merge', [localContent, remoteContent, baseContent, ignoredSettings]); } - computeRemoteContent(localContent: string, remoteContent: string, ignoredSettings: IStringDictionary): Promise { + computeRemoteContent(localContent: string, remoteContent: string, ignoredSettings: string[]): Promise { return this.channel.call('computeRemoteContent', [localContent, remoteContent, ignoredSettings]); } diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 551664b00e6..18377cfac58 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -7,51 +7,82 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { Event } from 'vs/base/common/event'; import { IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IStringDictionary } from 'vs/base/common/collections'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope, allSettings } from 'vs/platform/configuration/common/configurationRegistry'; import { localize } from 'vs/nls'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { ILogService } from 'vs/platform/log/common/log'; -export function registerConfiguration() { - Registry.as(ConfigurationExtensions.Configuration) - .registerConfiguration({ - id: 'userConfiguration', - order: 30, - title: localize('userConfiguration', "User Configuration"), - type: 'object', - properties: { - 'userConfiguration.enableSync': { - type: 'boolean', - description: localize('userConfiguration.enableSync', "When enabled, synchronises User Configuration: Settings, Keybindings, Extensions & Snippets."), - default: true, - scope: ConfigurationScope.APPLICATION - }, - 'userConfiguration.syncExtensions': { - type: 'boolean', - description: localize('userConfiguration.syncExtensions', "When enabled extensions are synchronised while synchronising user configuration."), - default: true, - scope: ConfigurationScope.APPLICATION, - }, - 'userConfiguration.ignoreSettings': { - 'type': 'object', - description: localize('userConfiguration.ignoreSettings', "Configure settings to be ignored while syncing"), - 'default': { - 'userConfiguration.enableSync': true, - 'userConfiguration.syncExtensions': true, - 'userConfiguration.ignoreSettings': true - }, - 'scope': ConfigurationScope.APPLICATION, - 'additionalProperties': { - 'anyOf': [ - { - 'type': 'boolean', - 'description': localize('ignoredSetting', "Id of the stting to be ignored. Set to true or false to enable or disable."), - } - ] - } - } +export const DEFAULT_IGNORED_SETTINGS = [ + 'configurationSync.enable', + 'configurationSync.enableSettings', + 'configurationSync.enableExtensions', +]; + +export function registerConfiguration(): IDisposable { + const ignoredSettingsSchemaId = 'vscode://schemas/ignoredSettings'; + const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); + configurationRegistry.registerConfiguration({ + id: 'configurationSync', + order: 30, + title: localize('configurationSync', "Configuration Sync"), + type: 'object', + properties: { + 'configurationSync.enable': { + type: 'boolean', + description: localize('configurationSync.enable', "When enabled, synchronizes configuration that includes Settings and Extensions."), + default: true, + scope: ConfigurationScope.APPLICATION + }, + 'configurationSync.enableSettings': { + type: 'boolean', + description: localize('configurationSync.enableSettings', "When enabled settings are synchronized while synchronizing configuration."), + default: true, + scope: ConfigurationScope.APPLICATION, + }, + 'configurationSync.enableExtensions': { + type: 'boolean', + description: localize('configurationSync.enableExtensions', "When enabled extensions are synchronized while synchronizing configuration."), + default: true, + scope: ConfigurationScope.APPLICATION, + }, + 'configurationSync.extensionsToIgnore': { + 'type': 'array', + description: localize('configurationSync.extensionsToIgnore', "Configure extensions to be ignored while syncing."), + 'default': [], + 'scope': ConfigurationScope.APPLICATION, + uniqueItems: true + }, + 'configurationSync.settingsToIgnore': { + 'type': 'array', + description: localize('configurationSync.settingsToIgnore', "Configure settings to be ignored while syncing. \nDefault Ignored Settings:\n\n{0}", DEFAULT_IGNORED_SETTINGS.sort().map(setting => `- ${setting}`).join('\n')), + 'default': [], + 'scope': ConfigurationScope.APPLICATION, + $ref: ignoredSettingsSchemaId, + additionalProperties: true, + uniqueItems: true + }, + 'configurationSync.enableAuth': { + 'type': 'boolean', + description: localize('configurationSync.enableAuth', "Enables authentication and requires VS Code restart when changed"), + 'default': false, + 'scope': ConfigurationScope.APPLICATION } - }); + } + }); + const registerIgnoredSettingsSchema = () => { + const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); + const ignoredSettingsSchema: IJSONSchema = { + items: { + type: 'string', + enum: [...Object.keys(allSettings.properties).filter(setting => DEFAULT_IGNORED_SETTINGS.indexOf(setting) === -1), ...DEFAULT_IGNORED_SETTINGS.map(setting => `-${setting}`)] + } + }; + jsonRegistry.registerSchema(ignoredSettingsSchemaId, ignoredSettingsSchema); + }; + return configurationRegistry.onDidUpdateConfiguration(() => registerIgnoredSettingsSchema()); } export interface IUserData { @@ -60,6 +91,7 @@ export interface IUserData { } export enum UserDataSyncStoreErrorCode { + Unauthroized = 'Unauthroized', Rejected = 'Rejected', Unknown = 'Unknown' } @@ -79,11 +111,6 @@ export interface IUserDataSyncStoreService { readonly enabled: boolean; - readonly loggedIn: boolean; - readonly onDidChangeLoggedIn: Event; - login(): Promise; - logout(): Promise; - read(key: string, oldValue: IUserData | null): Promise; write(key: string, content: string, ref: string | null): Promise; } @@ -113,6 +140,7 @@ export interface ISynchroniser { readonly onDidChangeLocal: Event; sync(_continue?: boolean): Promise; + stop(): void; } export const IUserDataSyncService = createDecorator('IUserDataSyncService'); @@ -121,7 +149,6 @@ export interface IUserDataSyncService extends ISynchroniser { _serviceBrand: any; readonly conflictsSource: SyncSource | null; - getRemoteExtensions(): Promise; removeExtension(identifier: IExtensionIdentifier): Promise; } @@ -131,9 +158,15 @@ export interface ISettingsMergeService { _serviceBrand: undefined; - merge(localContent: string, remoteContent: string, baseContent: string | null, ignoredSettings: IStringDictionary): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }>; + merge(localContent: string, remoteContent: string, baseContent: string | null, ignoredSettings: string[]): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }>; - computeRemoteContent(localContent: string, remoteContent: string, ignoredSettings: IStringDictionary): Promise; + computeRemoteContent(localContent: string, remoteContent: string, ignoredSettings: string[]): Promise; + +} + +export const IUserDataSyncLogService = createDecorator('IUserDataSyncLogService'); + +export interface IUserDataSyncLogService extends ILogService { } diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index 84c2bdb24b2..d772cbe47cb 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -24,8 +24,8 @@ export class UserDataSyncChannel implements IServerChannel { case 'sync': return this.service.sync(args[0]); case '_getInitialStatus': return Promise.resolve(this.service.status); case 'getConflictsSource': return Promise.resolve(this.service.conflictsSource); - case 'getRemoteExtensions': return this.service.getRemoteExtensions(); case 'removeExtension': return this.service.removeExtension(args[0]); + case 'stop': this.service.stop(); return Promise.resolve(); } throw new Error('Invalid call'); } diff --git a/src/vs/platform/userDataSync/common/userDataSyncLog.ts b/src/vs/platform/userDataSync/common/userDataSyncLog.ts new file mode 100644 index 00000000000..df1251ca3af --- /dev/null +++ b/src/vs/platform/userDataSync/common/userDataSyncLog.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync'; +import { AbstractLogService, ILoggerService, ILogger } from 'vs/platform/log/common/log'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; + +export class UserDataSyncLogService extends AbstractLogService implements IUserDataSyncLogService { + + _serviceBrand: undefined; + private readonly logger: ILogger; + + constructor( + @ILoggerService loggerService: ILoggerService, + @IEnvironmentService environmentService: IEnvironmentService + ) { + super(); + this.logger = this._register(loggerService.getLogger(environmentService.userDataSyncLogResource)); + } + + trace(message: string, ...args: any[]): void { + this.logger.trace(message, ...args); + } + + debug(message: string, ...args: any[]): void { + this.logger.debug(message, ...args); + } + + info(message: string, ...args: any[]): void { + this.logger.info(message, ...args); + } + + warn(message: string, ...args: any[]): void { + this.logger.warn(message, ...args); + } + + error(message: string | Error, ...args: any[]): void { + this.logger.error(message, ...args); + } + + critical(message: string | Error, ...args: any[]): void { + this.logger.critical(message, ...args); + } + + flush(): void { + this.logger.flush(); + } + +} diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 4db123c4a02..a4908dabe22 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, SyncStatus, ISynchroniser, IUserDataSyncStoreService, SyncSource, ISyncExtension } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, ISynchroniser, IUserDataSyncStoreService, SyncSource, IUserDataSyncLogService, UserDataSyncStoreError, UserDataSyncStoreErrorCode } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync'; @@ -12,6 +12,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { timeout } from 'vs/base/common/async'; import { ExtensionsSynchroniser } from 'vs/platform/userDataSync/common/extensionsSync'; import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; export class UserDataSyncService extends Disposable implements IUserDataSyncService { @@ -35,6 +36,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ constructor( @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @IInstantiationService private readonly instantiationService: IInstantiationService, + @IAuthTokenService private readonly authTokenService: IAuthTokenService, ) { super(); this.settingsSynchroniser = this._register(this.instantiationService.createInstance(SettingsSynchroniser)); @@ -43,12 +45,16 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ this.updateStatus(); this._register(Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeStatus, () => undefined)))(() => this.updateStatus())); this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal)); + this._register(authTokenService.onDidChangeStatus(() => this.onDidChangeAuthTokenStatus())); } async sync(_continue?: boolean): Promise { if (!this.userDataSyncStoreService.enabled) { throw new Error('Not enabled'); } + if (this.authTokenService.status === AuthTokenStatus.Inactive) { + throw new Error('Not Authenticated. Please sign in to start sync.'); + } for (const synchroniser of this.synchronisers) { if (!await synchroniser.sync(_continue)) { return false; @@ -57,8 +63,13 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return true; } - getRemoteExtensions(): Promise { - return this.extensionsSynchroniser.getRemoteExtensions(); + stop(): void { + if (!this.userDataSyncStoreService.enabled) { + throw new Error('Not enabled'); + } + for (const synchroniser of this.synchronisers) { + synchroniser.stop(); + } } removeExtension(identifier: IExtensionIdentifier): Promise { @@ -100,31 +111,67 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return null; } + private onDidChangeAuthTokenStatus(): void { + if (this.authTokenService.status === AuthTokenStatus.Inactive) { + this.stop(); + } + } + } export class UserDataAutoSync extends Disposable { + private enabled: boolean = false; + constructor( @IConfigurationService private readonly configurationService: IConfigurationService, @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, + @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, + @IAuthTokenService private readonly authTokenService: IAuthTokenService, ) { super(); - if (userDataSyncStoreService.enabled) { - this.sync(true); - this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('userConfiguration.enableSync'))(() => this.sync(true))); + this.updateEnablement(false); + this._register(Event.any(authTokenService.onDidChangeStatus, userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true))); + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateEnablement(true))); - // Sync immediately if there is a local change. - this._register(Event.debounce(this.userDataSyncService.onDidChangeLocal, () => undefined, 500)(() => this.sync(false))); + // Sync immediately if there is a local change. + this._register(Event.debounce(this.userDataSyncService.onDidChangeLocal, () => undefined, 500)(() => this.sync(false))); + } + + private updateEnablement(stopIfDisabled: boolean): void { + const enabled = this.isSyncEnabled(); + if (this.enabled === enabled) { + return; } + + this.enabled = enabled; + if (this.enabled) { + this.logService.info('Syncing configuration started'); + this.sync(true); + return; + } else { + if (stopIfDisabled) { + this.userDataSyncService.stop(); + this.logService.info('Syncing configuration stopped.'); + } + } + } private async sync(loop: boolean): Promise { - if (this.isSyncEnabled()) { + if (this.enabled) { try { await this.userDataSyncService.sync(); } catch (e) { - // Ignore errors + if (e instanceof UserDataSyncStoreError && e.code === UserDataSyncStoreErrorCode.Unauthroized) { + if (e instanceof UserDataSyncStoreError && e.code === UserDataSyncStoreErrorCode.Unauthroized && this.authTokenService.status === AuthTokenStatus.Disabled) { + this.logService.error('Sync failed because the server requires authorization. Please enable authorization.'); + } else { + this.logService.error(e); + } + } + this.logService.error(e); } if (loop) { await timeout(1000 * 5); // Loop sync for every 5s. @@ -134,7 +181,9 @@ export class UserDataAutoSync extends Disposable { } private isSyncEnabled(): boolean { - return this.configurationService.getValue('userConfiguration.enableSync'); + return this.configurationService.getValue('configurationSync.enable') + && this.userDataSyncService.status !== SyncStatus.Uninitialized + && this.authTokenService.status !== AuthTokenStatus.Inactive; } } diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index d48da9d36cb..5910b86817c 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -6,12 +6,12 @@ import { Disposable, } from 'vs/base/common/lifecycle'; import { IUserData, IUserDataSyncStoreService, UserDataSyncStoreErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { IProductService } from 'vs/platform/product/common/productService'; -import { Emitter, Event } from 'vs/base/common/event'; -import { IRequestService, asText } from 'vs/platform/request/common/request'; +import { IRequestService, asText, isSuccess } from 'vs/platform/request/common/request'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { IHeaders } from 'vs/base/parts/request/common/request'; +import { IHeaders, IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/request'; +import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService { @@ -19,27 +19,17 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn get enabled(): boolean { return !!this.productService.settingsSyncStoreUrl; } - private _loggedIn: boolean = false; - get loggedIn(): boolean { return this._loggedIn; } - private readonly _onDidChangeLoggedIn: Emitter = this._register(new Emitter()); - readonly onDidChangeLoggedIn: Event = this._onDidChangeLoggedIn.event; - constructor( @IProductService private readonly productService: IProductService, @IRequestService private readonly requestService: IRequestService, + @IAuthTokenService private readonly authTokenService: IAuthTokenService, ) { super(); } - async login(): Promise { - } - - async logout(): Promise { - } - async read(key: string, oldValue: IUserData | null): Promise { if (!this.enabled) { - return Promise.reject(new Error('No settings sync store url configured.')); + throw new Error('No settings sync store url configured.'); } const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), 'resource', key, 'latest').toString(); @@ -48,13 +38,17 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn headers['If-None-Match'] = oldValue.ref; } - const context = await this.requestService.request({ type: 'GET', url, headers }, CancellationToken.None); + const context = await this.request({ type: 'GET', url, headers }, CancellationToken.None); if (context.res.statusCode === 304) { // There is no new value. Hence return the old value. return oldValue!; } + if (!isSuccess(context)) { + throw new Error('Server returned ' + context.res.statusCode); + } + const ref = context.res.headers['etag']; if (!ref) { throw new Error('Server did not return the ref'); @@ -65,7 +59,7 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn async write(key: string, data: string, ref: string | null): Promise { if (!this.enabled) { - return Promise.reject(new Error('No settings sync store url configured.')); + throw new Error('No settings sync store url configured.'); } const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), 'resource', key).toString(); @@ -74,13 +68,17 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn headers['If-Match'] = ref; } - const context = await this.requestService.request({ type: 'POST', url, data, headers }, CancellationToken.None); + const context = await this.request({ type: 'POST', url, data, headers }, CancellationToken.None); if (context.res.statusCode === 412) { // There is a new value. Throw Rejected Error throw new UserDataSyncStoreError('New data exists', UserDataSyncStoreErrorCode.Rejected); } + if (!isSuccess(context)) { + throw new Error('Server returned ' + context.res.statusCode); + } + const newRef = context.res.headers['etag']; if (!newRef) { throw new Error('Server did not return the ref'); @@ -88,4 +86,28 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn return newRef; } + private async request(options: IRequestOptions, token: CancellationToken): Promise { + if (this.authTokenService.status !== AuthTokenStatus.Disabled) { + const authToken = await this.authTokenService.getToken(); + if (!authToken) { + throw new Error('No Auth Token Available.'); + } + options.headers = options.headers || {}; + options.headers['authorization'] = `Bearer ${authToken}`; + } + + const context = await this.requestService.request(options, token); + + if (context.res.statusCode === 401) { + if (this.authTokenService.status !== AuthTokenStatus.Disabled) { + this.authTokenService.refreshToken(); + } + // Throw Unauthorized Error + throw new UserDataSyncStoreError('Unauthorized', UserDataSyncStoreErrorCode.Unauthroized); + } + + return context; + + } + } diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 8b6bde598b1..442167fb954 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -3,49 +3,14 @@ * 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'; -import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IProcessEnvironment, isMacintosh, isLinux, isWeb } from 'vs/base/common/platform'; import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; import { ExportData } from 'vs/base/common/performance'; import { LogLevel } from 'vs/platform/log/common/log'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -export const IWindowsService = createDecorator('windowsService'); - -export interface INativeOpenDialogOptions { - forceNewWindow?: boolean; - - defaultPath?: string; - - telemetryEventName?: string; - telemetryExtraData?: ITelemetryData; -} - -export interface IWindowsService { - - _serviceBrand: undefined; - - readonly onWindowOpen: Event; - readonly onWindowFocus: Event; - readonly onWindowBlur: Event; - readonly onWindowMaximize: Event; - readonly onWindowUnmaximize: Event; - readonly onRecentlyOpenedChange: Event; - - addRecentlyOpened(recents: IRecent[]): Promise; - removeFromRecentlyOpened(paths: URI[]): Promise; - clearRecentlyOpened(): Promise; - getRecentlyOpened(windowId: number): Promise; - isFocused(windowId: number): Promise; -} - -export const IWindowService = createDecorator('windowService'); - export interface IOpenedWindow { id: number; workspace?: IWorkspaceIdentifier; @@ -54,18 +19,17 @@ export interface IOpenedWindow { filename?: string; } -export interface IOpenInWindowOptions { - forceNewWindow?: boolean; +export interface IBaseOpenWindowsOptions { forceReuseWindow?: boolean; - diffMode?: boolean; - addMode?: boolean; - gotoLineMode?: boolean; - noRecentEntry?: boolean; - waitMarkerFileURI?: URI; } -export interface IOpenEmptyWindowOptions { - reuse?: boolean; +export interface IOpenWindowOptions extends IBaseOpenWindowsOptions { + forceNewWindow?: boolean; + + noRecentEntry?: boolean; +} + +export interface IOpenEmptyWindowOptions extends IBaseOpenWindowsOptions { remoteAuthority?: string; } @@ -99,25 +63,19 @@ export function isFileToOpen(uriToOpen: IWindowOpenable): uriToOpen is IFileToOp return !!(uriToOpen as IFileToOpen).fileUri; } -export interface IWindowService { +export type MenuBarVisibility = 'default' | 'visible' | 'toggle' | 'hidden' | 'compact'; - _serviceBrand: undefined; +export function getMenuBarVisibility(configurationService: IConfigurationService, environment: IEnvironmentService, isExtensionDevelopment = environment.isExtensionDevelopment): MenuBarVisibility { + const titleBarStyle = getTitleBarStyle(configurationService, environment, isExtensionDevelopment); + const menuBarVisibility = configurationService.getValue('window.menuBarVisibility'); - readonly onDidChangeFocus: Event; - readonly onDidChangeMaximize: Event; - - readonly hasFocus: boolean; - - readonly windowId: number; - - getRecentlyOpened(): Promise; - addRecentlyOpened(recents: IRecent[]): Promise; - removeFromRecentlyOpened(paths: URI[]): Promise; - isFocused(): Promise; + if (titleBarStyle === 'native' && menuBarVisibility === 'compact') { + return 'default'; + } else { + return menuBarVisibility; + } } -export type MenuBarVisibility = 'default' | 'visible' | 'toggle' | 'hidden'; - export interface IWindowsConfiguration { window: IWindowSettings; } @@ -261,8 +219,9 @@ export interface IAddFoldersRequest { } export interface IWindowConfiguration extends ParsedArgs { - machineId: string; - windowId: number; + machineId?: string; // NOTE: This is undefined in the web, the telemetry service directly resolves this. + windowId: number; // TODO: should we deprecate this in favor of sessionId? + sessionId: string; logLevel: LogLevel; mainPid: number; @@ -287,19 +246,14 @@ export interface IWindowConfiguration extends ParsedArgs { 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 IRunActionInWindowRequest { diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts deleted file mode 100644 index 355f88fbf79..00000000000 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ /dev/null @@ -1,65 +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 { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { URI } from 'vs/base/common/uri'; -import { IRecent, isRecentFile, isRecentFolder } from 'vs/platform/history/common/history'; - -export class WindowsChannel implements IServerChannel { - - private readonly onWindowOpen: Event; - private readonly onWindowFocus: Event; - private readonly onWindowBlur: Event; - private readonly onWindowMaximize: Event; - private readonly onWindowUnmaximize: Event; - private readonly onRecentlyOpenedChange: Event; - - constructor(private readonly service: IWindowsService) { - this.onWindowOpen = Event.buffer(service.onWindowOpen, true); - this.onWindowFocus = Event.buffer(service.onWindowFocus, true); - this.onWindowBlur = Event.buffer(service.onWindowBlur, true); - this.onWindowMaximize = Event.buffer(service.onWindowMaximize, true); - this.onWindowUnmaximize = Event.buffer(service.onWindowUnmaximize, true); - this.onRecentlyOpenedChange = Event.buffer(service.onRecentlyOpenedChange, true); - } - - listen(_: unknown, event: string): Event { - switch (event) { - case 'onWindowOpen': return this.onWindowOpen; - case 'onWindowFocus': return this.onWindowFocus; - case 'onWindowBlur': return this.onWindowBlur; - case 'onWindowMaximize': return this.onWindowMaximize; - case 'onWindowUnmaximize': return this.onWindowUnmaximize; - case 'onRecentlyOpenedChange': return this.onRecentlyOpenedChange; - } - - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'addRecentlyOpened': return this.service.addRecentlyOpened(arg.map((recent: IRecent) => { - if (isRecentFile(recent)) { - recent.fileUri = URI.revive(recent.fileUri); - } else if (isRecentFolder(recent)) { - recent.folderUri = URI.revive(recent.folderUri); - } else { - recent.workspace = reviveWorkspaceIdentifier(recent.workspace); - } - return recent; - })); - case 'removeFromRecentlyOpened': return this.service.removeFromRecentlyOpened(arg.map(URI.revive)); - case 'clearRecentlyOpened': return this.service.clearRecentlyOpened(); - case 'getRecentlyOpened': return this.service.getRecentlyOpened(arg); - case 'isFocused': return this.service.isFocused(arg); - case 'openExtensionDevelopmentHostWindow': return (this.service as any).openExtensionDevelopmentHostWindow(arg[0], arg[1]); // TODO@Isidor move - } - - throw new Error(`Call not found: ${command}`); - } -} diff --git a/src/vs/platform/windows/electron-browser/windowsService.ts b/src/vs/platform/windows/electron-browser/windowsService.ts deleted file mode 100644 index 7ba22274581..00000000000 --- a/src/vs/platform/windows/electron-browser/windowsService.ts +++ /dev/null @@ -1,60 +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 { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { IRecentlyOpened, IRecent, isRecentWorkspace } from 'vs/platform/history/common/history'; -import { URI } from 'vs/base/common/uri'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; -import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { IProcessEnvironment } from 'vs/base/common/platform'; - -export class WindowsService implements IWindowsService { - - _serviceBrand: undefined; - - private channel: IChannel; - - get onWindowOpen(): Event { return this.channel.listen('onWindowOpen'); } - get onWindowFocus(): Event { return this.channel.listen('onWindowFocus'); } - get onWindowBlur(): Event { return this.channel.listen('onWindowBlur'); } - get onWindowMaximize(): Event { return this.channel.listen('onWindowMaximize'); } - get onWindowUnmaximize(): Event { return this.channel.listen('onWindowUnmaximize'); } - get onRecentlyOpenedChange(): Event { return this.channel.listen('onRecentlyOpenedChange'); } - - constructor(@IMainProcessService mainProcessService: IMainProcessService) { - this.channel = mainProcessService.getChannel('windows'); - } - - addRecentlyOpened(recent: IRecent[]): Promise { - return this.channel.call('addRecentlyOpened', recent); - } - - removeFromRecentlyOpened(paths: Array): Promise { - return this.channel.call('removeFromRecentlyOpened', paths); - } - - clearRecentlyOpened(): Promise { - return this.channel.call('clearRecentlyOpened'); - } - - async getRecentlyOpened(windowId: number): Promise { - const recentlyOpened: IRecentlyOpened = await this.channel.call('getRecentlyOpened', windowId); - recentlyOpened.workspaces.forEach(recent => isRecentWorkspace(recent) ? recent.workspace = reviveWorkspaceIdentifier(recent.workspace) : recent.folderUri = URI.revive(recent.folderUri)); - recentlyOpened.files.forEach(recent => recent.fileUri = URI.revive(recent.fileUri)); - - return recentlyOpened; - } - - isFocused(windowId: number): Promise { - return this.channel.call('isFocused', windowId); - } - - openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { - return this.channel.call('openExtensionDevelopmentHostWindow', [args, env]); - } -} diff --git a/src/vs/platform/windows/electron-main/legacyWindowsMainService.ts b/src/vs/platform/windows/electron-main/legacyWindowsMainService.ts deleted file mode 100644 index 7f8c9ace3c2..00000000000 --- a/src/vs/platform/windows/electron-main/legacyWindowsMainService.ts +++ /dev/null @@ -1,121 +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 { Disposable } from 'vs/base/common/lifecycle'; -import { assign } from 'vs/base/common/objects'; -import { URI } from 'vs/base/common/uri'; -import { IWindowsService, OpenContext } from 'vs/platform/windows/common/windows'; -import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; -import { app, BrowserWindow } from 'electron'; -import { Event } from 'vs/base/common/event'; -import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; -import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; -import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; -import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; -import { Schemas } from 'vs/base/common/network'; -import { IProcessEnvironment } from 'vs/base/common/platform'; -import { ILogService } from 'vs/platform/log/common/log'; - -// @deprecated this should eventually go away and be implemented by host & electron service -export class LegacyWindowsMainService extends Disposable implements IWindowsService, IURLHandler { - - _serviceBrand: undefined; - - readonly onWindowOpen: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-created', (_, w: BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id)); - readonly onWindowBlur: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-blur', (_, w: BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id)); - readonly onWindowMaximize: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-maximize', (_, w: BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id)); - readonly onWindowUnmaximize: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-unmaximize', (_, w: BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id)); - readonly onWindowFocus: Event = Event.any( - Event.map(Event.filter(Event.map(this.windowsMainService.onWindowsCountChanged, () => this.windowsMainService.getLastActiveWindow()), w => !!w), w => w!.id), - Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (_, w: BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id)) - ); - - readonly onRecentlyOpenedChange: Event = this.historyMainService.onRecentlyOpenedChange; - - constructor( - @IWindowsMainService private readonly windowsMainService: IWindowsMainService, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IURLService urlService: IURLService, - @IHistoryMainService private readonly historyMainService: IHistoryMainService, - @ILogService private readonly logService: ILogService - ) { - super(); - - urlService.registerHandler(this); - } - - async addRecentlyOpened(recents: IRecent[]): Promise { - this.logService.trace('windowsService#addRecentlyOpened'); - this.historyMainService.addRecentlyOpened(recents); - } - - async removeFromRecentlyOpened(paths: URI[]): Promise { - this.logService.trace('windowsService#removeFromRecentlyOpened'); - - this.historyMainService.removeFromRecentlyOpened(paths); - } - - async clearRecentlyOpened(): Promise { - this.logService.trace('windowsService#clearRecentlyOpened'); - - this.historyMainService.clearRecentlyOpened(); - } - - async getRecentlyOpened(windowId: number): Promise { - this.logService.trace('windowsService#getRecentlyOpened', windowId); - - return this.withWindow(windowId, codeWindow => this.historyMainService.getRecentlyOpened(codeWindow.config.workspace, codeWindow.config.folderUri, codeWindow.config.filesToOpenOrCreate), () => this.historyMainService.getRecentlyOpened())!; - } - - async isFocused(windowId: number): Promise { - this.logService.trace('windowsService#isFocused', windowId); - - return this.withWindow(windowId, codeWindow => codeWindow.win.isFocused(), () => false)!; - } - - async openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { - this.logService.trace('windowsService#openExtensionDevelopmentHostWindow ' + JSON.stringify(args)); - - const extDevPaths = args.extensionDevelopmentPath; - if (extDevPaths) { - this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, { - context: OpenContext.API, - cli: args, - userEnv: Object.keys(env).length > 0 ? env : undefined - }); - } - } - - async handleURL(uri: URI): Promise { - - // Catch file URLs - if (uri.authority === Schemas.file && !!uri.path) { - this.openFileForURI(URI.file(uri.fsPath)); // using fsPath on a non-file URI... - return true; - } - - return false; - } - - private openFileForURI(uri: URI): void { - const cli = assign(Object.create(null), this.environmentService.args); - const urisToOpen = [{ fileUri: uri }]; - - this.windowsMainService.open({ context: OpenContext.API, cli, urisToOpen, gotoLineMode: true }); - } - - private withWindow(windowId: number, fn: (window: ICodeWindow) => T, fallback?: () => T): T | undefined { - const codeWindow = this.windowsMainService.getWindowById(windowId); - if (codeWindow) { - return fn(codeWindow); - } - - if (fallback) { - return fallback(); - } - - return undefined; - } -} diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 4eab25d137e..9d519473683 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -3,15 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { OpenContext, IWindowConfiguration, INativeOpenDialogOptions, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { OpenContext, IWindowConfiguration, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment } from 'vs/base/common/platform'; -import { IWorkspaceIdentifier, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { URI } from 'vs/base/common/uri'; -import { MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue, Rectangle, BrowserWindow, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions } from 'electron'; +import { Rectangle, BrowserWindow } from 'electron'; +import { IDisposable } from 'vs/base/common/lifecycle'; export interface IWindowState { width?: number; @@ -29,10 +30,16 @@ export const enum WindowMode { Fullscreen } -export interface ICodeWindow { +export interface ICodeWindow extends IDisposable { + + readonly onClose: Event; + readonly onDestroy: Event; + + readonly whenClosedOrLoaded: Promise; + readonly id: number; readonly win: BrowserWindow; - readonly config: IWindowConfiguration; + readonly config: IWindowConfiguration | undefined; readonly openedFolderUri?: URI; readonly openedWorkspace?: IWorkspaceIdentifier; @@ -47,6 +54,9 @@ export interface ICodeWindow { readonly isReady: boolean; ready(): Promise; + setReady(): void; + + readonly hasHiddenTitleBarStyle: boolean; addTabbedWindow(window: ICodeWindow): void; @@ -61,20 +71,19 @@ export interface ICodeWindow { send(channel: string, ...args: any[]): void; sendWhenReady(channel: string, ...args: any[]): void; + readonly isFullScreen: boolean; toggleFullScreen(): void; - isFullScreen(): boolean; + isMinimized(): boolean; - hasHiddenTitleBarStyle(): boolean; + setRepresentedFilename(name: string): void; - getRepresentedFilename(): string; + getRepresentedFilename(): string | undefined; + handleTitleDoubleClick(): void; updateTouchBar(items: ISerializableCommandAction[][]): void; - setReady(): void; serializeWindowState(): IWindowState; - - dispose(): void; } export const IWindowsMainService = createDecorator('windowsMainService'); @@ -85,39 +94,24 @@ export interface IWindowsCountChangedEvent { } export interface IWindowsMainService { + _serviceBrand: undefined; - // events readonly onWindowReady: Event; readonly onWindowsCountChanged: Event; - readonly onWindowClose: Event; - // methods - reload(win: ICodeWindow, cli?: ParsedArgs): void; - enterWorkspace(win: ICodeWindow, path: URI): Promise; - closeWorkspace(win: ICodeWindow): void; open(openConfig: IOpenConfiguration): ICodeWindow[]; - openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void; - pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise; - pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise; - pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise; - pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise; - showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise; - showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise; - showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise; - focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow; - getLastActiveWindow(): ICodeWindow | undefined; - waitForWindowCloseOrLoad(windowId: number): Promise; openEmptyWindow(context: OpenContext, options?: IOpenEmptyWindowOptions): ICodeWindow[]; - openNewTabbedWindow(context: OpenContext): ICodeWindow[]; - openExternal(url: string): Promise; + openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[]; + sendToFocused(channel: string, ...args: any[]): void; sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void; - getFocusedWindow(): ICodeWindow | undefined; + + getLastActiveWindow(): ICodeWindow | undefined; + getWindowById(windowId: number): ICodeWindow | undefined; getWindows(): ICodeWindow[]; getWindowCount(): number; - quit(): void; } export interface IOpenConfiguration { @@ -138,8 +132,3 @@ export interface IOpenConfiguration { readonly initialStartup?: boolean; readonly noRecentEntry?: boolean; } - -export interface ISharedProcess { - whenReady(): Promise; - toggle(): void; -} diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts similarity index 69% rename from src/vs/code/electron-main/windows.ts rename to src/vs/platform/windows/electron-main/windowsMainService.ts index ded45e47860..d0b62c048bd 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -4,48 +4,41 @@ *--------------------------------------------------------------------------------------------*/ import * as fs from 'fs'; -import { basename, normalize, join, dirname } from 'vs/base/common/path'; +import { basename, normalize, join, } from 'vs/base/common/path'; import { localize } from 'vs/nls'; import * as arrays from 'vs/base/common/arrays'; import { assign, mixin } from 'vs/base/common/objects'; import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; -import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter, shell, MessageBoxReturnValue, MessageBoxOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, Display } from 'electron'; +import { ipcMain as ipc, screen, BrowserWindow, systemPreferences, MessageBoxOptions, Display } from 'electron'; import { parseLineAndColumnAware } from 'vs/code/node/paths'; import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; -import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; -import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/code/node/windowsFinder'; +import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest } from 'vs/platform/windows/common/windows'; +import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/platform/windows/node/window'; import { Event as CommonEvent, Emitter } from 'vs/base/common/event'; import product from 'vs/platform/product/common/product'; -import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; -import { IRecent } from 'vs/platform/history/common/history'; -import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; +import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform'; -import { IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IRecent } from 'vs/platform/workspaces/common/workspaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { Schemas } from 'vs/base/common/network'; -import { normalizeNFC } from 'vs/base/common/normalization'; import { URI } from 'vs/base/common/uri'; -import { Queue } from 'vs/base/common/async'; -import { exists, dirExists } from 'vs/base/node/pfs'; -import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources'; +import { getComparisonKey, isEqual, normalizePath, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; -import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage'; +import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/platform/windows/electron-main/windowsStateStorage'; import { getWorkspaceIdentifier, IWorkspacesMainService } 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, - CRASHED = 2 -} +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { isWindowsDriveLetter, toSlashes } from 'vs/base/common/extpath'; +import { CharCode } from 'vs/base/common/charCode'; export interface IWindowState { workspace?: IWorkspaceIdentifier; @@ -156,7 +149,7 @@ interface IWorkspacePathToOpen { label?: string; } -export class WindowsManager extends Disposable implements IWindowsMainService { +export class WindowsMainService extends Disposable implements IWindowsMainService { _serviceBrand: undefined; @@ -167,18 +160,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService { private readonly windowsState: IWindowsState; private lastClosedWindowState?: IWindowState; - private readonly dialogs: Dialogs; - private readonly workspacesManager: WorkspacesManager; - private readonly _onWindowReady = this._register(new Emitter()); readonly onWindowReady: CommonEvent = this._onWindowReady.event; private readonly _onWindowClose = this._register(new Emitter()); readonly onWindowClose: CommonEvent = this._onWindowClose.event; - private readonly _onWindowLoad = this._register(new Emitter()); - readonly onWindowLoad: CommonEvent = this._onWindowLoad.event; - private readonly _onWindowsCountChanged = this._register(new Emitter()); readonly onWindowsCountChanged: CommonEvent = this._onWindowsCountChanged.event; @@ -190,22 +177,19 @@ export class WindowsManager extends Disposable implements IWindowsMainService { @IEnvironmentService private readonly environmentService: IEnvironmentService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, - @ITelemetryService private readonly telemetryService: ITelemetryService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IHistoryMainService private readonly historyMainService: IHistoryMainService, + @IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, - @IInstantiationService private readonly instantiationService: IInstantiationService + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IDialogMainService private readonly dialogMainService: IDialogMainService ) { super(); - this.windowsState = restoreWindowsState(this.stateService.getItem(WindowsManager.windowsStateStorageKey)); + this.windowsState = restoreWindowsState(this.stateService.getItem(WindowsMainService.windowsStateStorageKey)); if (!Array.isArray(this.windowsState.openedWindows)) { this.windowsState.openedWindows = []; } - this.dialogs = new Dialogs(stateService, this); - this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this); - this.lifecycleMainService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex()); } @@ -240,13 +224,16 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // React to HC color scheme changes (Windows) if (isWindows) { - systemPreferences.on('inverted-color-scheme-changed', () => { - if (systemPreferences.isInvertedColorScheme()) { + const onHighContrastChange = () => { + if (systemPreferences.isInvertedColorScheme() || systemPreferences.isHighContrastColorScheme()) { this.sendToAll('vscode:enterHighContrast'); } else { this.sendToAll('vscode:leaveHighContrast'); } - }); + }; + + systemPreferences.on('inverted-color-scheme-changed', () => onHighContrastChange()); + systemPreferences.on('high-contrast-color-scheme-changed', () => onHighContrastChange()); } // Handle various lifecycle events around windows @@ -260,6 +247,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.lastClosedWindowState = undefined; } }); + + // Signal a window is ready after having entered a workspace + this._register(this.workspacesMainService.onWorkspaceEntered(event => { + this._onWindowReady.fire(event.window); + })); } // Note that onBeforeShutdown() and onBeforeWindowClose() are fired in different order depending on the OS: @@ -310,7 +302,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { if (!currentWindowsState.lastActiveWindow) { let activeWindow = this.getLastActiveWindow(); if (!activeWindow || activeWindow.isExtensionDevelopmentHost) { - activeWindow = WindowsManager.WINDOWS.filter(window => !window.isExtensionDevelopmentHost)[0]; + activeWindow = WindowsMainService.WINDOWS.filter(window => !window.isExtensionDevelopmentHost)[0]; } if (activeWindow) { @@ -319,7 +311,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // 2.) Find extension host window - const extensionHostWindow = WindowsManager.WINDOWS.filter(window => window.isExtensionDevelopmentHost && !window.isExtensionTestHost)[0]; + const extensionHostWindow = WindowsMainService.WINDOWS.filter(window => window.isExtensionDevelopmentHost && !window.isExtensionTestHost)[0]; if (extensionHostWindow) { currentWindowsState.lastPluginDevelopmentHostWindow = this.toWindowState(extensionHostWindow); } @@ -330,11 +322,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // so if we ever want to persist the UI state of the last closed window (window count === 1), it has // to come from the stored lastClosedWindowState on Win/Linux at least if (this.getWindowCount() > 1) { - currentWindowsState.openedWindows = WindowsManager.WINDOWS.filter(window => !window.isExtensionDevelopmentHost).map(window => this.toWindowState(window)); + currentWindowsState.openedWindows = WindowsMainService.WINDOWS.filter(window => !window.isExtensionDevelopmentHost).map(window => this.toWindowState(window)); } // Persist - this.stateService.setItem(WindowsManager.windowsStateStorageKey, getWindowsStateStoreData(currentWindowsState)); + this.stateService.setItem(WindowsMainService.windowsStateStorageKey, getWindowsStateStoreData(currentWindowsState)); } // See note on #onBeforeShutdown() for details how these events are flowing @@ -380,10 +372,17 @@ export class WindowsManager extends Disposable implements IWindowsMainService { }; } - async openExternal(url: string): Promise { - shell.openExternal(url); + openEmptyWindow(context: OpenContext, options?: IOpenEmptyWindowOptions): ICodeWindow[] { + let cli = this.environmentService.args; + const remote = options?.remoteAuthority; + if (cli && (cli.remote !== remote)) { + cli = { ...cli, remote }; + } - return true; + const forceReuseWindow = options?.forceReuseWindow; + const forceNewWindow = !forceReuseWindow; + + return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow }); } open(openConfig: IOpenConfiguration): ICodeWindow[] { @@ -463,7 +462,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // 1.) focus last active window if we are not instructed to open any paths if (focusLastActive) { - const lastActiveWindow = usedWindows.filter(window => window.backupPath === this.windowsState.lastActiveWindow!.backupPath); + const lastActiveWindow = usedWindows.filter(window => this.windowsState.lastActiveWindow && window.backupPath === this.windowsState.lastActiveWindow.backupPath); if (lastActiveWindow.length) { lastActiveWindow[0].focus(); focusLastOpened = false; @@ -476,9 +475,9 @@ export class WindowsManager extends Disposable implements IWindowsMainService { for (let i = usedWindows.length - 1; i >= 0; i--) { const usedWindow = usedWindows[i]; if ( - (usedWindow.openedWorkspace && workspacesToRestore.some(workspace => workspace.workspace.id === usedWindow.openedWorkspace!.id)) || // skip over restored workspace - (usedWindow.openedFolderUri && foldersToRestore.some(uri => isEqual(uri, usedWindow.openedFolderUri))) || // skip over restored folder - (usedWindow.backupPath && emptyToRestore.some(empty => empty.backupFolder === basename(usedWindow.backupPath!))) // skip over restored empty window + (usedWindow.openedWorkspace && workspacesToRestore.some(workspace => usedWindow.openedWorkspace && workspace.workspace.id === usedWindow.openedWorkspace.id)) || // skip over restored workspace + (usedWindow.openedFolderUri && foldersToRestore.some(uri => isEqual(uri, usedWindow.openedFolderUri))) || // skip over restored folder + (usedWindow.backupPath && emptyToRestore.some(empty => usedWindow.backupPath && empty.backupFolder === basename(usedWindow.backupPath))) // skip over restored empty window ) { continue; } @@ -497,7 +496,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Remember in recent document list (unless this opens for extension development) // Also do not add paths when files are opened for diffing, only if opened individually - if (!usedWindows.some(window => window.isExtensionDevelopmentHost) && !openConfig.diffMode && !openConfig.noRecentEntry) { + if (!usedWindows.some(window => window.isExtensionDevelopmentHost) && !(fileInputs?.filesToDiff) && !openConfig.noRecentEntry) { const recents: IRecent[] = []; for (let pathToOpen of pathsToOpen) { if (pathToOpen.workspace) { @@ -508,7 +507,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { recents.push({ label: pathToOpen.label, fileUri: pathToOpen.fileUri }); } } - this.historyMainService.addRecentlyOpened(recents); + this.workspacesHistoryMainService.addRecentlyOpened(recents); } // If we got started with --wait from the CLI, we need to signal to the outside when the window @@ -516,7 +515,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // process can continue. We do this by deleting the waitMarkerFilePath. const waitMarkerFileURI = openConfig.waitMarkerFileURI; if (openConfig.context === OpenContext.CLI && waitMarkerFileURI && usedWindows.length === 1 && usedWindows[0]) { - this.waitForWindowCloseOrLoad(usedWindows[0].id).then(() => fs.unlink(waitMarkerFileURI.fsPath, _error => undefined)); + usedWindows[0].whenClosedOrLoaded.then(() => fs.unlink(waitMarkerFileURI.fsPath, _error => undefined)); } return usedWindows; @@ -563,13 +562,13 @@ export class WindowsManager extends Disposable implements IWindowsMainService { const fileToCheck = fileInputs.filesToOpenOrCreate[0] || fileInputs.filesToDiff[0]; // only look at the windows with correct authority - const windows = WindowsManager.WINDOWS.filter(window => window.remoteAuthority === fileInputs!.remoteAuthority); + const windows = WindowsMainService.WINDOWS.filter(window => fileInputs && window.remoteAuthority === fileInputs.remoteAuthority); const bestWindowOrFolder = findBestWindowOrFolderForFile({ windows, newWindow: openFilesInNewWindow, context: openConfig.context, - fileUri: fileToCheck && fileToCheck.fileUri, + fileUri: fileToCheck?.fileUri, localWorkspaceResolver: workspace => workspace.configPath.scheme === Schemas.file ? this.workspacesMainService.resolveLocalWorkspaceSync(workspace.configPath) : null }); @@ -619,10 +618,10 @@ export class WindowsManager extends Disposable implements IWindowsMainService { if (allWorkspacesToOpen.length > 0) { // Check for existing instances - const windowsOnWorkspace = arrays.coalesce(allWorkspacesToOpen.map(workspaceToOpen => findWindowOnWorkspace(WindowsManager.WINDOWS, workspaceToOpen.workspace))); + const windowsOnWorkspace = arrays.coalesce(allWorkspacesToOpen.map(workspaceToOpen => findWindowOnWorkspace(WindowsMainService.WINDOWS, workspaceToOpen.workspace))); if (windowsOnWorkspace.length > 0) { const windowOnWorkspace = windowsOnWorkspace[0]; - const fileInputsForWindow = (fileInputs && fileInputs.remoteAuthority === windowOnWorkspace.remoteAuthority) ? fileInputs : undefined; + const fileInputsForWindow = (fileInputs?.remoteAuthority === windowOnWorkspace.remoteAuthority) ? fileInputs : undefined; // Do open files usedWindows.push(this.doOpenFilesInExistingWindow(openConfig, windowOnWorkspace, fileInputsForWindow)); @@ -637,12 +636,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Open remaining ones allWorkspacesToOpen.forEach(workspaceToOpen => { - if (windowsOnWorkspace.some(win => win.openedWorkspace!.id === workspaceToOpen.workspace.id)) { + if (windowsOnWorkspace.some(win => win.openedWorkspace && win.openedWorkspace.id === workspaceToOpen.workspace.id)) { return; // ignore folders that are already open } const remoteAuthority = workspaceToOpen.remoteAuthority; - const fileInputsForWindow = (fileInputs && fileInputs.remoteAuthority === remoteAuthority) ? fileInputs : undefined; + const fileInputsForWindow = (fileInputs?.remoteAuthority === remoteAuthority) ? fileInputs : undefined; // Do open folder usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, workspaceToOpen, openFolderInNewWindow, fileInputsForWindow)); @@ -661,10 +660,10 @@ export class WindowsManager extends Disposable implements IWindowsMainService { if (allFoldersToOpen.length > 0) { // Check for existing instances - const windowsOnFolderPath = arrays.coalesce(allFoldersToOpen.map(folderToOpen => findWindowOnWorkspace(WindowsManager.WINDOWS, folderToOpen.folderUri))); + const windowsOnFolderPath = arrays.coalesce(allFoldersToOpen.map(folderToOpen => findWindowOnWorkspace(WindowsMainService.WINDOWS, folderToOpen.folderUri))); if (windowsOnFolderPath.length > 0) { const windowOnFolderPath = windowsOnFolderPath[0]; - const fileInputsForWindow = fileInputs && fileInputs.remoteAuthority === windowOnFolderPath.remoteAuthority ? fileInputs : undefined; + const fileInputsForWindow = fileInputs?.remoteAuthority === windowOnFolderPath.remoteAuthority ? fileInputs : undefined; // Do open files usedWindows.push(this.doOpenFilesInExistingWindow(openConfig, windowOnFolderPath, fileInputsForWindow)); @@ -685,7 +684,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } const remoteAuthority = folderToOpen.remoteAuthority; - const fileInputsForWindow = (fileInputs && fileInputs.remoteAuthority === remoteAuthority) ? fileInputs : undefined; + const fileInputsForWindow = (fileInputs?.remoteAuthority === remoteAuthority) ? fileInputs : undefined; // Do open folder usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, folderToOpen, openFolderInNewWindow, fileInputsForWindow)); @@ -704,7 +703,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { if (allEmptyToRestore.length > 0) { allEmptyToRestore.forEach(emptyWindowBackupInfo => { const remoteAuthority = emptyWindowBackupInfo.remoteAuthority; - const fileInputsForWindow = (fileInputs && fileInputs.remoteAuthority === remoteAuthority) ? fileInputs : undefined; + const fileInputsForWindow = (fileInputs?.remoteAuthority === remoteAuthority) ? fileInputs : undefined; usedWindows.push(this.openInBrowserWindow({ userEnv: openConfig.userEnv, @@ -776,7 +775,9 @@ export class WindowsManager extends Disposable implements IWindowsMainService { private doAddFoldersToExistingWindow(window: ICodeWindow, foldersToAdd: URI[]): ICodeWindow { window.focus(); // make sure window has focus - window.sendWhenReady('vscode:addFolders', { foldersToAdd }); + const request: IAddFoldersRequest = { foldersToAdd }; + + window.sendWhenReady('vscode:addFolders', request); return window; } @@ -862,7 +863,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { path.label = pathToOpen.label; pathsToOpen.push(path); } else { - const uri = resourceFromURIToOpen(pathToOpen); + const uri = this.resourceFromURIToOpen(pathToOpen); + // Warn about the invalid URI or path let message, detail; if (uri.scheme === Schemas.file) { @@ -881,7 +883,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { noLink: true }; - this.dialogs.showMessageBox(options, this.getFocusedWindow()); + this.dialogMainService.showMessageBox(options, withNullAsUndefined(BrowserWindow.getFocusedWindow())); } } return pathsToOpen; @@ -964,12 +966,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService { for (const openedWindow of openedWindows) { if (openedWindow.workspace) { // Workspaces const pathToOpen = this.parseUri({ workspaceUri: openedWindow.workspace.configPath }, { remoteAuthority: openedWindow.remoteAuthority }); - if (pathToOpen && pathToOpen.workspace) { + if (pathToOpen?.workspace) { windowsToOpen.push(pathToOpen); } } else if (openedWindow.folderUri) { // Folders const pathToOpen = this.parseUri({ folderUri: openedWindow.folderUri }, { remoteAuthority: openedWindow.remoteAuthority }); - if (pathToOpen && pathToOpen.folderUri) { + if (pathToOpen?.folderUri) { windowsToOpen.push(pathToOpen); } } else if (restoreWindows !== 'folders' && openedWindow.backupPath && !openedWindow.remoteAuthority) { // Local windows that were empty. Empty windows with backups will always be restored in open() @@ -994,7 +996,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { restoreWindows = 'all'; // always reopen all windows when an update was applied } else { const windowConfig = this.configurationService.getValue('window'); - restoreWindows = ((windowConfig && windowConfig.restoreWindows) || 'one'); + restoreWindows = windowConfig?.restoreWindows || 'one'; if (['all', 'folders', 'one', 'none'].indexOf(restoreWindows) === -1) { restoreWindows = 'one'; @@ -1011,10 +1013,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.logService.error(`Invalid URI input string, scheme missing: ${arg}`); return undefined; } + return uri; } catch (e) { this.logService.error(`Invalid URI input string: ${arg}, ${e.message}`); } + return undefined; } @@ -1023,7 +1027,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return undefined; } - let uri = resourceFromURIToOpen(toOpen); + let uri = this.resourceFromURIToOpen(toOpen); if (uri.scheme === Schemas.file) { return this.parsePath(uri.fsPath, options, isFileToOpen(toOpen)); } @@ -1050,6 +1054,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { remoteAuthority }; } + return { fileUri: uri, remoteAuthority @@ -1071,6 +1076,18 @@ export class WindowsManager extends Disposable implements IWindowsMainService { }; } + private resourceFromURIToOpen(openable: IWindowOpenable): URI { + if (isWorkspaceToOpen(openable)) { + return openable.workspaceUri; + } + + if (isFolderToOpen(openable)) { + return openable.folderUri; + } + + return openable.fileUri; + } + private parsePath(anyPath: string, options: IPathParseOptions, forceOpenWorkspaceAsFile?: boolean): IPathToOpen | undefined { if (!anyPath) { return undefined; @@ -1086,11 +1103,36 @@ export class WindowsManager extends Disposable implements IWindowsMainService { anyPath = parsedPath.path; } - // open remote if either specified in the cli even if it is a local file. TODO@aeschli: Future idea: resolve in remote host context. + // open remote if either specified in the cli even if it is a local file. const remoteAuthority = options.remoteAuthority; - const candidate = normalize(anyPath); + if (remoteAuthority) { + // assume it's a folder or workspace file + + const first = anyPath.charCodeAt(0); + // make absolute + if (first !== CharCode.Slash) { + if (isWindowsDriveLetter(first) && anyPath.charCodeAt(anyPath.charCodeAt(1)) === CharCode.Colon) { + anyPath = toSlashes(anyPath); + } + anyPath = '/' + anyPath; + } + + const uri = URI.from({ scheme: Schemas.vscodeRemote, authority: remoteAuthority, path: anyPath }); + + if (hasWorkspaceFileExtension(anyPath)) { + if (forceOpenWorkspaceAsFile) { + return { fileUri: uri, remoteAuthority }; + } + return { workspace: getWorkspaceIdentifier(uri), remoteAuthority }; + } + return { folderUri: uri, remoteAuthority }; + } + + let candidate = normalize(anyPath); + try { + const candidateStat = fs.statSync(candidate); if (candidateStat.isFile()) { @@ -1128,10 +1170,10 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } } catch (error) { const fileUri = URI.file(candidate); - this.historyMainService.removeFromRecentlyOpened([fileUri]); // since file does not seem to exist anymore, remove from recent + this.workspacesHistoryMainService.removeFromRecentlyOpened([fileUri]); // since file does not seem to exist anymore, remove from recent // assume this is a file that does not yet exist - if (options && options.ignoreFileNotFound) { + if (options?.ignoreFileNotFound) { return { fileUri, remoteAuthority, @@ -1147,8 +1189,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // let the user settings override how folders are open in a new window or same window unless we are forced const windowConfig = this.configurationService.getValue('window'); - const openFolderInNewWindowConfig = (windowConfig && windowConfig.openFoldersInNewWindow) || 'default' /* default */; - const openFilesInNewWindowConfig = (windowConfig && windowConfig.openFilesInNewWindow) || 'off' /* default */; + const openFolderInNewWindowConfig = windowConfig?.openFoldersInNewWindow || 'default' /* default */; + const openFilesInNewWindowConfig = windowConfig?.openFilesInNewWindow || 'off' /* default */; let openFolderInNewWindow = (openConfig.preferNewWindow || openConfig.forceNewWindow) && !openConfig.forceReuseWindow; if (!openConfig.forceNewWindow && !openConfig.forceReuseWindow && (openFolderInNewWindowConfig === 'on' || openFolderInNewWindowConfig === 'off')) { @@ -1185,17 +1227,17 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return { openFolderInNewWindow: !!openFolderInNewWindow, openFilesInNewWindow }; } - openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void { + openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[] { // Reload an existing extension development host window on the same path // We currently do not allow more than one extension development window // on the same extension path. - const existingWindow = findWindowOnExtensionDevelopmentPath(WindowsManager.WINDOWS, extensionDevelopmentPath); + const existingWindow = findWindowOnExtensionDevelopmentPath(WindowsMainService.WINDOWS, extensionDevelopmentPath); if (existingWindow) { - this.reload(existingWindow, openConfig.cli); + this.lifecycleMainService.reload(existingWindow, openConfig.cli); existingWindow.focus(); // make sure it gets focus and is restored - return; + return [existingWindow]; } let folderUris = openConfig.cli['folder-uri'] || []; let fileUris = openConfig.cli['file-uri'] || []; @@ -1244,7 +1286,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { cliArgs = cliArgs.filter(path => { const uri = URI.file(path); - if (!!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, uri)) { + if (!!findWindowOnWorkspaceOrFolderUri(WindowsMainService.WINDOWS, uri)) { return false; } return uri.authority === authority; @@ -1252,7 +1294,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { folderUris = folderUris.filter(uri => { const u = this.argToUri(uri); - if (!!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, u)) { + if (!!findWindowOnWorkspaceOrFolderUri(WindowsMainService.WINDOWS, u)) { return false; } return u ? u.authority === authority : false; @@ -1260,7 +1302,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { fileUris = fileUris.filter(uri => { const u = this.argToUri(uri); - if (!!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, u)) { + if (!!findWindowOnWorkspaceOrFolderUri(WindowsMainService.WINDOWS, u)) { return false; } return u ? u.authority === authority : false; @@ -1286,7 +1328,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { noRecentEntry: true, waitMarkerFileURI: openConfig.waitMarkerFileURI }; - this.open(openArgs); + + return this.open(openArgs); } private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow { @@ -1335,12 +1378,21 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Window state is not from a previous session: only allow fullscreen if we inherit it or user wants fullscreen let allowFullscreen: boolean; if (state.hasDefaultState) { - allowFullscreen = (windowConfig && windowConfig.newWindowDimensions && ['fullscreen', 'inherit'].indexOf(windowConfig.newWindowDimensions) >= 0); + allowFullscreen = (windowConfig?.newWindowDimensions && ['fullscreen', 'inherit'].indexOf(windowConfig.newWindowDimensions) >= 0); } // Window state is from a previous session: only allow fullscreen when we got updated or user wants to restore else { - allowFullscreen = this.lifecycleMainService.wasRestarted || (windowConfig && windowConfig.restoreFullscreen); + allowFullscreen = this.lifecycleMainService.wasRestarted || windowConfig?.restoreFullscreen; + + if (allowFullscreen && isMacintosh && WindowsMainService.WINDOWS.some(win => win.isFullScreen)) { + // macOS: Electron does not allow to restore multiple windows in + // fullscreen. As such, if we already restored a window in that + // state, we cannot allow more fullscreen windows. See + // https://github.com/microsoft/vscode/issues/41691 and + // https://github.com/electron/electron/issues/13077 + allowFullscreen = false; + } } if (state.mode === WindowMode.Fullscreen && !allowFullscreen) { @@ -1348,7 +1400,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // Create the window - window = this.instantiationService.createInstance(CodeWindow, { + const createdWindow = window = this.instantiationService.createInstance(CodeWindow, { state, extensionDevelopmentPath: configuration.extensionDevelopmentPath, isExtensionTestHost: !!configuration.extensionTestsPath @@ -1363,17 +1415,16 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // Add to our list of windows - WindowsManager.WINDOWS.push(window); + WindowsMainService.WINDOWS.push(window); // Indicate number change via event - this._onWindowsCountChanged.fire({ oldCount: WindowsManager.WINDOWS.length - 1, newCount: WindowsManager.WINDOWS.length }); + this._onWindowsCountChanged.fire({ oldCount: WindowsMainService.WINDOWS.length - 1, newCount: WindowsMainService.WINDOWS.length }); // Window Events + once(window.onClose)(() => this.onWindowClosed(createdWindow)); + once(window.onDestroy)(() => this.onBeforeWindowClose(createdWindow)); // try to save state before destroy because close will not fire window.win.webContents.removeAllListeners('devtools-reload-page'); // remove built in listener so we can handle this on our own - window.win.webContents.on('devtools-reload-page', () => this.reload(window!)); - window.win.webContents.on('crashed', () => this.onWindowError(window!, WindowError.CRASHED)); - window.win.on('unresponsive', () => this.onWindowError(window!, WindowError.UNRESPONSIVE)); - window.win.on('closed', () => this.onWindowClosed(window!)); + window.win.webContents.on('devtools-reload-page', () => this.lifecycleMainService.reload(createdWindow)); // Lifecycle (this.lifecycleMainService as LifecycleMainService).registerWindow(window); @@ -1427,9 +1478,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Load it window.load(configuration); - - // Signal event - this._onWindowLoad.fire(window.id); } private getNewWindowState(configuration: IWindowConfiguration): INewWindowState { @@ -1518,7 +1566,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Check for newWindowDimensions setting and adjust accordingly const windowConfig = this.configurationService.getValue('window'); let ensureNoOverlap = true; - if (windowConfig && windowConfig.newWindowDimensions) { + if (windowConfig?.newWindowDimensions) { if (windowConfig.newWindowDimensions === 'maximized') { state.mode = WindowMode.Maximized; ensureNoOverlap = false; @@ -1547,14 +1595,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } private ensureNoOverlap(state: ISingleWindowState): ISingleWindowState { - if (WindowsManager.WINDOWS.length === 0) { + if (WindowsMainService.WINDOWS.length === 0) { return state; } state.x = typeof state.x === 'number' ? state.x : 0; state.y = typeof state.y === 'number' ? state.y : 0; - const existingWindowBounds = WindowsManager.WINDOWS.map(win => win.getBounds()); + const existingWindowBounds = WindowsMainService.WINDOWS.map(win => win.getBounds()); while (existingWindowBounds.some(b => b.x === state.x || b.y === state.y)) { state.x += 30; state.y += 30; @@ -1563,40 +1611,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return state; } - async reload(win: ICodeWindow, cli?: ParsedArgs): Promise { - - // Only reload when the window has not vetoed this - const veto = await this.lifecycleMainService.unload(win, UnloadReason.RELOAD); - if (!veto) { - win.reload(undefined, cli); - } - } - - closeWorkspace(win: ICodeWindow): void { - this.openInBrowserWindow({ - cli: this.environmentService.args, - windowToUse: win, - remoteAuthority: win.remoteAuthority - }); - } - - 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 { - - // Mark as recently opened - this.historyMainService.addRecentlyOpened([{ workspace: result.workspace }]); - - // Trigger Eevent to indicate load of workspace into window - this._onWindowReady.fire(win); - - return result; - } - focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow { const lastActive = this.getLastActiveWindow(); if (lastActive) { @@ -1610,42 +1624,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } getLastActiveWindow(): ICodeWindow | undefined { - return getLastActiveWindow(WindowsManager.WINDOWS); + return getLastActiveWindow(WindowsMainService.WINDOWS); } - getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined { - return getLastActiveWindow(WindowsManager.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority)); - } - - openEmptyWindow(context: OpenContext, options?: IOpenEmptyWindowOptions): ICodeWindow[] { - let cli = this.environmentService.args; - const remote = options && options.remoteAuthority; - if (cli && (cli.remote !== remote)) { - cli = { ...cli, remote }; - } - const forceReuseWindow = options && options.reuse; - const forceNewWindow = !forceReuseWindow; - return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow }); - } - - openNewTabbedWindow(context: OpenContext): ICodeWindow[] { - return this.open({ context, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true }); - } - - waitForWindowCloseOrLoad(windowId: number): Promise { - return new Promise(resolve => { - function handler(id: number) { - if (id === windowId) { - closeListener.dispose(); - loadListener.dispose(); - - resolve(); - } - } - - const closeListener = this.onWindowClose(id => handler(id)); - const loadListener = this.onWindowLoad(id => handler(id)); - }); + private getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined { + return getLastActiveWindow(WindowsMainService.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority)); } sendToFocused(channel: string, ...args: any[]): void { @@ -1657,7 +1640,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } sendToAll(channel: string, payload?: any, windowIdsToIgnore?: number[]): void { - for (const window of WindowsManager.WINDOWS) { + for (const window of WindowsMainService.WINDOWS) { if (windowIdsToIgnore && windowIdsToIgnore.indexOf(window.id) >= 0) { continue; // do not send if we are instructed to ignore it } @@ -1666,7 +1649,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } } - getFocusedWindow(): ICodeWindow | undefined { + private getFocusedWindow(): ICodeWindow | undefined { const win = BrowserWindow.getFocusedWindow(); if (win) { return this.getWindowById(win.id); @@ -1676,443 +1659,27 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } getWindowById(windowId: number): ICodeWindow | undefined { - const res = WindowsManager.WINDOWS.filter(window => window.id === windowId); + const res = WindowsMainService.WINDOWS.filter(window => window.id === windowId); + return arrays.firstOrDefault(res); } getWindows(): ICodeWindow[] { - return WindowsManager.WINDOWS; + return WindowsMainService.WINDOWS; } getWindowCount(): number { - return WindowsManager.WINDOWS.length; - } - - private onWindowError(window: ICodeWindow, error: WindowError): void { - this.logService.error(error === WindowError.CRASHED ? '[VS Code]: render process crashed!' : '[VS Code]: detected unresponsive'); - 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())) { - // TODO@Ben Workaround for https://github.com/Microsoft/vscode/issues/56994 - // In certain cases the window can report unresponsiveness because a breakpoint was hit - // and the process is stopped executing. The most typical cases are: - // - devtools are opened and debugging happens - // - window is an extensions development host that is being debugged - // - window is an extension test development host that is being debugged - return; - } - - // Show Dialog - this.dialogs.showMessageBox({ - title: product.nameLong, - type: 'warning', - buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'wait', comment: ['&& denotes a mnemonic'] }, "&&Keep Waiting")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], - message: localize('appStalled', "The window is no longer responding"), - detail: localize('appStalledDetail', "You can reopen or close the window or keep waiting."), - noLink: true - }, window).then(result => { - if (!window.win) { - return; // Return early if the window has been going down already - } - - if (result.response === 0) { - window.reload(); - } else if (result.response === 2) { - this.onBeforeWindowClose(window); // 'close' event will not be fired on destroy(), so run it manually - window.win.destroy(); // make sure to destroy the window as it is unresponsive - } - }); - } - - // Crashed - else { - this.dialogs.showMessageBox({ - title: product.nameLong, - type: 'warning', - buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], - message: localize('appCrashed', "The window has crashed"), - detail: localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."), - noLink: true - }, window).then(result => { - if (!window.win) { - return; // Return early if the window has been going down already - } - - if (result.response === 0) { - window.reload(); - } else if (result.response === 1) { - this.onBeforeWindowClose(window); // 'close' event will not be fired on destroy(), so run it manually - window.win.destroy(); // make sure to destroy the window as it has crashed - } - }); - } + return WindowsMainService.WINDOWS.length; } private onWindowClosed(win: ICodeWindow): void { - // Tell window - win.dispose(); - // Remove from our list so that Electron can clean it up - const index = WindowsManager.WINDOWS.indexOf(win); - WindowsManager.WINDOWS.splice(index, 1); + const index = WindowsMainService.WINDOWS.indexOf(win); + WindowsMainService.WINDOWS.splice(index, 1); // Emit - this._onWindowsCountChanged.fire({ oldCount: WindowsManager.WINDOWS.length + 1, newCount: WindowsManager.WINDOWS.length }); + this._onWindowsCountChanged.fire({ oldCount: WindowsMainService.WINDOWS.length + 1, newCount: WindowsMainService.WINDOWS.length }); this._onWindowClose.fire(win.id); } - - async pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise { - const title = localize('open', "Open"); - 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(async path => { - const isDir = await dirExists(path); - - return isDir ? { folderUri: URI.file(path) } : { fileUri: URI.file(path) }; - })); - this.open({ - context: OpenContext.DIALOG, - contextWindowId: win ? win.id : undefined, - cli: this.environmentService.args, - urisToOpen, - forceNewWindow: options.forceNewWindow - }); - } - } - - async pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise { - const title = localize('openFolder', "Open Folder"); - const paths = await this.dialogs.pick({ ...options, pickFolders: true, title }); - if (paths) { - this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFolder', options.telemetryExtraData); - this.open({ - context: OpenContext.DIALOG, - contextWindowId: win ? win.id : undefined, - cli: this.environmentService.args, - urisToOpen: paths.map(path => ({ folderUri: URI.file(path) })), - forceNewWindow: options.forceNewWindow - }); - } - } - - async pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise { - const title = localize('openFile', "Open File"); - const paths = await this.dialogs.pick({ ...options, pickFiles: true, title }); - if (paths) { - this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFile', options.telemetryExtraData); - this.open({ - context: OpenContext.DIALOG, - contextWindowId: win ? win.id : undefined, - cli: this.environmentService.args, - urisToOpen: paths.map(path => ({ fileUri: URI.file(path) })), - forceNewWindow: options.forceNewWindow - }); - } - } - - async pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise { - const title = localize('openWorkspaceTitle', "Open Workspace"); - const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open")); - const filters = WORKSPACE_FILTER; - const paths = await this.dialogs.pick({ ...options, pickFiles: true, title, filters, buttonLabel }); - if (paths) { - this.sendPickerTelemetry(paths, options.telemetryEventName || 'openWorkspace', options.telemetryExtraData); - this.open({ - context: OpenContext.DIALOG, - contextWindowId: win ? win.id : undefined, - cli: this.environmentService.args, - urisToOpen: paths.map(path => ({ workspaceUri: URI.file(path) })), - forceNewWindow: options.forceNewWindow - }); - } - - } - - private sendPickerTelemetry(paths: string[], telemetryEventName: string, telemetryExtraData?: ITelemetryData) { - - const numberOfPaths = paths ? paths.length : 0; - - // Telemetry - // __GDPR__TODO__ Dynamic event names and dynamic properties. Can not be registered statically. - this.telemetryService.publicLog(telemetryEventName, { - ...telemetryExtraData, - outcome: numberOfPaths ? 'success' : 'canceled', - numberOfPaths - }); - } - - showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise { - return this.dialogs.showMessageBox(options, win); - } - - showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise { - return this.dialogs.showSaveDialog(options, win); - } - - showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise { - return this.dialogs.showOpenDialog(options, win); - } - - quit(): void { - - // If the user selected to exit from an extension development host window, do not quit, but just - // close the window unless this is the last window that is opened. - const window = this.getFocusedWindow(); - if (window && window.isExtensionDevelopmentHost && this.getWindowCount() > 1) { - window.win.close(); - } - - // Otherwise: normal quit - else { - setTimeout(() => { - this.lifecycleMainService.quit(); - }, 10 /* delay to unwind callback stack (IPC) */); - } - } -} - -interface IInternalNativeOpenDialogOptions extends INativeOpenDialogOptions { - - pickFolders?: boolean; - pickFiles?: boolean; - - title: string; - buttonLabel?: string; - filters?: FileFilter[]; -} - -class Dialogs { - - private static readonly workingDirPickerStorageKey = 'pickerWorkingDir'; - - private readonly mapWindowToDialogQueue: Map>; - private readonly noWindowDialogQueue: Queue; - - constructor( - private readonly stateService: IStateService, - private readonly windowsMainService: IWindowsMainService - ) { - this.mapWindowToDialogQueue = new Map>(); - this.noWindowDialogQueue = new Queue(); - } - - async pick(options: IInternalNativeOpenDialogOptions, win?: ICodeWindow): Promise { - - // Ensure dialog options - const dialogOptions: OpenDialogOptions = { - title: options.title, - buttonLabel: options.buttonLabel, - filters: options.filters - }; - - // Ensure defaultPath - dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem(Dialogs.workingDirPickerStorageKey); - - - // Ensure properties - if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') { - dialogOptions.properties = undefined; // let it override based on the booleans - - if (options.pickFiles && options.pickFolders) { - dialogOptions.properties = ['multiSelections', 'openDirectory', 'openFile', 'createDirectory']; - } - } - - if (!dialogOptions.properties) { - dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory']; - } - - if (isMacintosh) { - dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files - } - - // Show Dialog - const windowToUse = win || this.windowsMainService.getFocusedWindow(); - - const result = await this.showOpenDialog(dialogOptions, windowToUse); - if (result && result.filePaths && result.filePaths.length > 0) { - - // Remember path in storage for next time - this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(result.filePaths[0])); - - return result.filePaths; - } - - return; - } - - private getDialogQueue(window?: ICodeWindow): Queue { - if (!window) { - return this.noWindowDialogQueue; - } - - let windowDialogQueue = this.mapWindowToDialogQueue.get(window.id); - if (!windowDialogQueue) { - windowDialogQueue = new Queue(); - this.mapWindowToDialogQueue.set(window.id, windowDialogQueue); - } - - return windowDialogQueue; - } - - showMessageBox(options: MessageBoxOptions, window?: ICodeWindow): Promise { - return this.getDialogQueue(window).queue(async () => { - if (window) { - return dialog.showMessageBox(window.win, options); - } - - return dialog.showMessageBox(options); - }); - } - - showSaveDialog(options: SaveDialogOptions, window?: ICodeWindow): Promise { - - function normalizePath(path: string | undefined): string | undefined { - if (path && isMacintosh) { - path = normalizeNFC(path); // normalize paths returned from the OS - } - - return path; - } - - return this.getDialogQueue(window).queue(async () => { - let result: SaveDialogReturnValue; - if (window) { - result = await dialog.showSaveDialog(window.win, options); - } else { - result = await dialog.showSaveDialog(options); - } - - result.filePath = normalizePath(result.filePath); - - return result; - }); - } - - showOpenDialog(options: OpenDialogOptions, window?: ICodeWindow): Promise { - - function normalizePaths(paths: string[] | undefined): string[] | undefined { - if (paths && paths.length > 0 && isMacintosh) { - paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS - } - - return paths; - } - - return this.getDialogQueue(window).queue(async () => { - - // Ensure the path exists (if provided) - if (options.defaultPath) { - const pathExists = await exists(options.defaultPath); - if (!pathExists) { - options.defaultPath = undefined; - } - } - - // Show dialog - let result: OpenDialogReturnValue; - if (window) { - result = await dialog.showOpenDialog(window.win, options); - } else { - result = await dialog.showOpenDialog(options); - } - - result.filePaths = normalizePaths(result.filePaths); - - return result; - }); - } -} - -class WorkspacesManager { - - constructor( - private readonly workspacesMainService: IWorkspacesMainService, - private readonly backupMainService: IBackupMainService, - private readonly windowsMainService: IWindowsMainService, - ) { } - - async enterWorkspace(window: ICodeWindow, path: URI): Promise { - if (!window || !window.win || !window.isReady) { - return null; // return early if the window is not ready or disposed - } - - 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 async isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise { - if (!path) { - return true; - } - - if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) { - return false; // window is already opened on a workspace with that path - } - - // Prevent overwriting a workspace that is currently opened in another window - if (findWindowOnWorkspace(this.windowsMainService.getWindows(), getWorkspaceIdentifier(path))) { - const options: MessageBoxOptions = { - title: product.nameLong, - type: 'info', - buttons: [localize('ok', "OK")], - message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", resourcesBasename(path)), - detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."), - noLink: true - }; - - await this.windowsMainService.showMessageBox(options, this.windowsMainService.getFocusedWindow()); - - return false; - } - - return true; // OK - } - - private doOpenWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult { - window.focus(); - - // Register window for backups and migrate current backups over - let backupPath: string | undefined; - if (!window.config.extensionDevelopmentPath) { - backupPath = this.backupMainService.registerWorkspaceBackupSync({ workspace, remoteAuthority: window.remoteAuthority }, window.config.backupPath); - } - - // if the window was opened on an untitled workspace, delete it. - if (window.openedWorkspace && this.workspacesMainService.isUntitledWorkspace(window.openedWorkspace)) { - this.workspacesMainService.deleteUntitledWorkspaceSync(window.openedWorkspace); - } - - // Update window configuration properly based on transition to workspace - window.config.folderUri = undefined; - window.config.workspace = workspace; - window.config.backupPath = backupPath; - - return { workspace, backupPath }; - } -} - -function resourceFromURIToOpen(openable: IWindowOpenable): URI { - if (isWorkspaceToOpen(openable)) { - return openable.workspaceUri; - } - - if (isFolderToOpen(openable)) { - return openable.folderUri; - } - - return openable.fileUri; } diff --git a/src/vs/code/electron-main/windowsStateStorage.ts b/src/vs/platform/windows/electron-main/windowsStateStorage.ts similarity index 97% rename from src/vs/code/electron-main/windowsStateStorage.ts rename to src/vs/platform/windows/electron-main/windowsStateStorage.ts index 16eac66cc20..165333950bc 100644 --- a/src/vs/code/electron-main/windowsStateStorage.ts +++ b/src/vs/platform/windows/electron-main/windowsStateStorage.ts @@ -5,7 +5,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { IWindowState as IWindowUIState } from 'vs/platform/windows/electron-main/windows'; -import { IWindowState, IWindowsState } from 'vs/code/electron-main/windows'; +import { IWindowState, IWindowsState } from 'vs/platform/windows/electron-main/windowsMainService'; export type WindowsStateStorageData = object; @@ -35,12 +35,15 @@ export function restoreWindowsState(data: WindowsStateStorageData | undefined): if (windowsState.lastActiveWindow) { result.lastActiveWindow = restoreWindowState(windowsState.lastActiveWindow); } + if (windowsState.lastPluginDevelopmentHostWindow) { result.lastPluginDevelopmentHostWindow = restoreWindowState(windowsState.lastPluginDevelopmentHostWindow); } + if (Array.isArray(windowsState.openedWindows)) { result.openedWindows = windowsState.openedWindows.map(windowState => restoreWindowState(windowState)); } + return result; } @@ -49,9 +52,11 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState { if (windowState.backupPath) { result.backupPath = windowState.backupPath; } + if (windowState.remoteAuthority) { result.remoteAuthority = windowState.remoteAuthority; } + if (windowState.folder) { result.folderUri = URI.parse(windowState.folder); } else if (windowState.folderUri) { @@ -59,11 +64,13 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState { } else if (windowState.folderPath) { result.folderUri = URI.file(windowState.folderPath); } + if (windowState.workspaceIdentifier) { result.workspace = { id: windowState.workspaceIdentifier.id, configPath: URI.parse(windowState.workspaceIdentifier.configURIPath) }; } else if (windowState.workspace) { result.workspace = { id: windowState.workspace.id, configPath: URI.file(windowState.workspace.configPath) }; } + return result; } @@ -83,4 +90,4 @@ function serializeWindowState(windowState: IWindowState): ISerializedWindowState remoteAuthority: windowState.remoteAuthority, uiState: windowState.uiState }; -} \ No newline at end of file +} diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/platform/windows/node/window.ts similarity index 76% rename from src/vs/code/node/windowsFinder.ts rename to src/vs/platform/windows/node/window.ts index 03e836c4827..08a4e800d3b 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/platform/windows/node/window.ts @@ -3,14 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { OpenContext, IOpenWindowOptions } from 'vs/platform/windows/common/windows'; +import { URI } from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; import * as extpath from 'vs/base/common/extpath'; -import { OpenContext } from 'vs/platform/windows/common/windows'; import { IWorkspaceIdentifier, IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { URI } from 'vs/base/common/uri'; import { isEqual, isEqualOrParent } from 'vs/base/common/resources'; -export interface ISimpleWindow { +export interface INativeOpenWindowOptions extends IOpenWindowOptions { + diffMode?: boolean; + addMode?: boolean; + gotoLineMode?: boolean; + waitMarkerFileURI?: URI; +} + +export interface IWindowContext { openedWorkspace?: IWorkspaceIdentifier; openedFolderUri?: URI; @@ -18,7 +25,7 @@ export interface ISimpleWindow { lastFocusTime: number; } -export interface IBestWindowOrFolderOptions { +export interface IBestWindowOrFolderOptions { windows: W[]; newWindow: boolean; context: OpenContext; @@ -28,7 +35,7 @@ export interface IBestWindowOrFolderOptions { localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null; } -export function findBestWindowOrFolderForFile({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions): W | undefined { +export function findBestWindowOrFolderForFile({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions): W | undefined { if (!newWindow && fileUri && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) { const windowOnFilePath = findWindowOnFilePath(windows, fileUri, workspaceResolver); if (windowOnFilePath) { @@ -38,7 +45,7 @@ export function findBestWindowOrFolderForFile({ windows return !newWindow ? getLastActiveWindow(windows) : undefined; } -function findWindowOnFilePath(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null { +function findWindowOnFilePath(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null { // First check for windows with workspaces that have a parent folder of the provided path opened for (const window of windows) { @@ -68,13 +75,13 @@ function findWindowOnFilePath(windows: W[], fileUri: UR return null; } -export function getLastActiveWindow(windows: W[]): W | undefined { +export function getLastActiveWindow(windows: W[]): W | undefined { const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); return windows.filter(window => window.lastFocusTime === lastFocusedDate)[0]; } -export function findWindowOnWorkspace(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null { +export function findWindowOnWorkspace(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null { if (isSingleFolderWorkspaceIdentifier(workspace)) { for (const window of windows) { // match on folder @@ -95,7 +102,7 @@ export function findWindowOnWorkspace(windows: W[], wor return null; } -export function findWindowOnExtensionDevelopmentPath(windows: W[], extensionDevelopmentPaths: string[]): W | null { +export function findWindowOnExtensionDevelopmentPath(windows: W[], extensionDevelopmentPaths: string[]): W | null { const matches = (uriString: string): boolean => { return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */)); @@ -104,7 +111,7 @@ export function findWindowOnExtensionDevelopmentPath(wi for (const window of windows) { // match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough const currPaths = window.extensionDevelopmentPath; - if (currPaths && currPaths.some(p => matches(p))) { + if (currPaths?.some(p => matches(p))) { return window; } } @@ -112,7 +119,7 @@ export function findWindowOnExtensionDevelopmentPath(wi return null; } -export function findWindowOnWorkspaceOrFolderUri(windows: W[], uri: URI | undefined): W | null { +export function findWindowOnWorkspaceOrFolderUri(windows: W[], uri: URI | undefined): W | null { if (!uri) { return null; } diff --git a/src/vs/code/test/node/windowsFinder.test.ts b/src/vs/platform/windows/test/node/window.test.ts similarity index 80% rename from src/vs/code/test/node/windowsFinder.test.ts rename to src/vs/platform/windows/test/node/window.test.ts index 7327dd74013..efda0b1afbc 100644 --- a/src/vs/code/test/node/windowsFinder.test.ts +++ b/src/vs/platform/windows/test/node/window.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import * as path from 'vs/base/common/path'; -import { findBestWindowOrFolderForFile, ISimpleWindow, IBestWindowOrFolderOptions } from 'vs/code/node/windowsFinder'; +import { IBestWindowOrFolderOptions, IWindowContext, findBestWindowOrFolderForFile } from 'vs/platform/windows/node/window'; import { OpenContext } from 'vs/platform/windows/common/windows'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; @@ -20,7 +20,7 @@ const testWorkspace: IWorkspaceIdentifier = { const testWorkspaceFolders = toWorkspaceFolders([{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }], testWorkspace.configPath); -function options(custom?: Partial>): IBestWindowOrFolderOptions { +function options(custom?: Partial>): IBestWindowOrFolderOptions { return { windows: [], newWindow: false, @@ -31,10 +31,10 @@ function options(custom?: Partial>): I }; } -const vscodeFolderWindow: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder')) }; -const lastActiveWindow: ISimpleWindow = { lastFocusTime: 3, openedFolderUri: undefined }; -const noVscodeFolderWindow: ISimpleWindow = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) }; -const windows: ISimpleWindow[] = [ +const vscodeFolderWindow: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder')) }; +const lastActiveWindow: IWindowContext = { lastFocusTime: 3, openedFolderUri: undefined }; +const noVscodeFolderWindow: IWindowContext = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) }; +const windows: IWindowContext[] = [ vscodeFolderWindow, lastActiveWindow, noVscodeFolderWindow, @@ -102,7 +102,7 @@ suite('WindowsFinder', () => { windows, fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt')) })), vscodeFolderWindow); - const window: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder')) }; + const window: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder')) }; assert.equal(findBestWindowOrFolderForFile(options({ windows: [window], fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder', 'subfolder', 'file.txt')) @@ -110,8 +110,8 @@ suite('WindowsFinder', () => { }); test('More specific existing window wins', () => { - const window: ISimpleWindow = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) }; - const nestedFolderWindow: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder')) }; + const window: IWindowContext = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) }; + const nestedFolderWindow: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder')) }; assert.equal(findBestWindowOrFolderForFile(options({ windows: [window, nestedFolderWindow], fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder', 'subfolder', 'file.txt')) @@ -119,7 +119,7 @@ suite('WindowsFinder', () => { }); test('Workspace folder wins', () => { - const window: ISimpleWindow = { lastFocusTime: 1, openedWorkspace: testWorkspace }; + const window: IWindowContext = { lastFocusTime: 1, openedWorkspace: testWorkspace }; assert.equal(findBestWindowOrFolderForFile(options({ windows: [window], fileUri: URI.file(path.join(fixturesFolder, 'vscode_workspace_2_folder', 'nested_vscode_folder', 'subfolder', 'file.txt')) diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 894c7d33642..6ab9770b32f 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -12,35 +12,23 @@ import { IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, export const IWorkspaceContextService = createDecorator('contextService'); -export const enum WorkbenchState { - EMPTY = 1, - FOLDER, - WORKSPACE -} - -export interface IWorkspaceFoldersChangeEvent { - added: IWorkspaceFolder[]; - removed: IWorkspaceFolder[]; - changed: IWorkspaceFolder[]; -} - export interface IWorkspaceContextService { _serviceBrand: undefined; /** * An event which fires on workbench state changes. */ - onDidChangeWorkbenchState: Event; + readonly onDidChangeWorkbenchState: Event; /** * An event which fires on workspace name changes. */ - onDidChangeWorkspaceName: Event; + readonly onDidChangeWorkspaceName: Event; /** * An event which fires on workspace folders change. */ - onDidChangeWorkspaceFolders: Event; + readonly onDidChangeWorkspaceFolders: Event; /** * Provides access to the complete workspace object. @@ -79,6 +67,18 @@ export interface IWorkspaceContextService { isInsideWorkspace(resource: URI): boolean; } +export const enum WorkbenchState { + EMPTY = 1, + FOLDER, + WORKSPACE +} + +export interface IWorkspaceFoldersChangeEvent { + added: IWorkspaceFolder[]; + removed: IWorkspaceFolder[]; + changed: IWorkspaceFolder[]; +} + export namespace IWorkspace { export function isIWorkspace(thing: any): thing is IWorkspace { return thing && typeof thing === 'object' @@ -106,6 +106,7 @@ export interface IWorkspace { } export interface IWorkspaceFolderData { + /** * The associated URI for this workspace folder. */ @@ -264,5 +265,6 @@ export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], } } } + return result; } diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 01846dbcea5..3864a42fd38 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -17,11 +17,68 @@ import { normalizeDriveLetter } from 'vs/base/common/labels'; import { toSlashes } from 'vs/base/common/extpath'; import { FormattingOptions } from 'vs/base/common/jsonFormatter'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; +import { ILogService } from 'vs/platform/log/common/log'; +import { Event as CommonEvent } from 'vs/base/common/event'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; export const WORKSPACE_EXTENSION = 'code-workspace'; export const WORKSPACE_FILTER = [{ name: localize('codeWorkspace', "Code Workspace"), extensions: [WORKSPACE_EXTENSION] }]; export const UNTITLED_WORKSPACE_NAME = 'workspace.json'; +export const IWorkspacesService = createDecorator('workspacesService'); + +export interface IWorkspacesService { + + _serviceBrand: undefined; + + // Management + enterWorkspace(path: URI): Promise; + createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; + deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise; + getWorkspaceIdentifier(workspacePath: URI): Promise; + + // History + readonly onRecentlyOpenedChange: CommonEvent; + addRecentlyOpened(recents: IRecent[]): Promise; + removeFromRecentlyOpened(workspaces: URI[]): Promise; + clearRecentlyOpened(): Promise; + getRecentlyOpened(): Promise; +} + +export interface IRecentlyOpened { + workspaces: Array; + files: IRecentFile[]; +} + +export type IRecent = IRecentWorkspace | IRecentFolder | IRecentFile; + +export interface IRecentWorkspace { + workspace: IWorkspaceIdentifier; + label?: string; +} + +export interface IRecentFolder { + folderUri: ISingleFolderWorkspaceIdentifier; + label?: string; +} + +export interface IRecentFile { + fileUri: URI; + label?: string; +} + +export function isRecentWorkspace(curr: IRecent): curr is IRecentWorkspace { + return curr.hasOwnProperty('workspace'); +} + +export function isRecentFolder(curr: IRecent): curr is IRecentFolder { + return curr.hasOwnProperty('folderUri'); +} + +export function isRecentFile(curr: IRecent): curr is IRecentFile { + return curr.hasOwnProperty('fileUri'); +} + /** * A single folder workspace identifier is just the path to the folder. */ @@ -76,11 +133,6 @@ export interface IStoredWorkspace { remoteAuthority?: string; } -export interface IWorkspaceSavedEvent { - workspace: IWorkspaceIdentifier; - oldConfigPath: string; -} - export interface IWorkspaceFolderCreationData { uri: URI; name?: string; @@ -96,21 +148,6 @@ export interface IEnterWorkspaceResult { backupPath?: string; } -export const IWorkspacesService = createDecorator('workspacesService'); - -export interface IWorkspacesService { - - _serviceBrand: undefined; - - enterWorkspace(path: URI): Promise; - - createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; - - deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise; - - getWorkspaceIdentifier(workspacePath: URI): Promise; -} - export function isSingleFolderWorkspaceIdentifier(obj: any): obj is ISingleFolderWorkspaceIdentifier { return obj instanceof URI; } @@ -136,6 +173,10 @@ export function toWorkspaceIdentifier(workspace: IWorkspace): IWorkspaceIdentifi return undefined; } +export function isUntitledWorkspace(path: URI, environmentService: IEnvironmentService): boolean { + return isEqualOrParent(path, environmentService.untitledWorkspacesHome); +} + export type IMultiFolderWorkspaceInitializationPayload = IWorkspaceIdentifier; export interface ISingleFolderWorkspaceInitializationPayload { id: string; folder: ISingleFolderWorkspaceIdentifier; } export interface IEmptyWorkspaceInitializationPayload { id: string; } @@ -244,12 +285,9 @@ function doParseStoredWorkspace(path: URI, contents: string): IStoredWorkspace { let storedWorkspace: IStoredWorkspace = json.parse(contents); // use fault tolerant parser // Filter out folders which do not have a path or uri set - if (Array.isArray(storedWorkspace.folders)) { + if (storedWorkspace && Array.isArray(storedWorkspace.folders)) { storedWorkspace.folders = storedWorkspace.folders.filter(folder => isStoredWorkspaceFolder(folder)); - } - - // Validate - if (!Array.isArray(storedWorkspace.folders)) { + } else { throw new Error(`${path} looks like an invalid workspace file.`); } @@ -258,12 +296,133 @@ function doParseStoredWorkspace(path: URI, contents: string): IStoredWorkspace { export function useSlashForPath(storedFolders: IStoredWorkspaceFolder[]): boolean { if (isWindows) { - for (const folder of storedFolders) { - if (isRawFileWorkspaceFolder(folder) && folder.path.indexOf(SLASH) >= 0) { - return true; - } - } - return false; + return storedFolders.some(folder => isRawFileWorkspaceFolder(folder) && folder.path.indexOf(SLASH) >= 0); } return true; } + +//#region Workspace Storage + +interface ISerializedRecentlyOpened { + workspaces3: Array; // workspace or URI.toString() // added in 1.32 + workspaceLabels?: Array; // added in 1.33 + files2: string[]; // files as URI.toString() // added in 1.32 + fileLabels?: Array; // added in 1.33 +} + +interface ILegacySerializedRecentlyOpened { + workspaces2: Array; // legacy, configPath as file path + workspaces: Array; // legacy (UriComponents was also supported for a few insider builds) + files: string[]; // files as paths +} + +interface ISerializedWorkspace { id: string; configURIPath: string; } +interface ILegacySerializedWorkspace { id: string; configPath: string; } + +function isLegacySerializedWorkspace(curr: any): curr is ILegacySerializedWorkspace { + return typeof curr === 'object' && typeof curr['id'] === 'string' && typeof curr['configPath'] === 'string'; +} + +function isUriComponents(curr: any): curr is UriComponents { + return curr && typeof curr['path'] === 'string' && typeof curr['scheme'] === 'string'; +} + +export type RecentlyOpenedStorageData = object; + +export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefined, logService: ILogService): IRecentlyOpened { + const result: IRecentlyOpened = { workspaces: [], files: [] }; + if (data) { + const restoreGracefully = function (entries: T[], func: (entry: T, index: number) => void) { + for (let i = 0; i < entries.length; i++) { + try { + func(entries[i], i); + } catch (e) { + logService.warn(`Error restoring recent entry ${JSON.stringify(entries[i])}: ${e.toString()}. Skip entry.`); + } + } + }; + + const storedRecents = data as ISerializedRecentlyOpened & ILegacySerializedRecentlyOpened; + if (Array.isArray(storedRecents.workspaces3)) { + restoreGracefully(storedRecents.workspaces3, (workspace, i) => { + const label: string | undefined = (Array.isArray(storedRecents.workspaceLabels) && storedRecents.workspaceLabels[i]) || undefined; + if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configURIPath === 'string') { + result.workspaces.push({ label, workspace: { id: workspace.id, configPath: URI.parse(workspace.configURIPath) } }); + } else if (typeof workspace === 'string') { + result.workspaces.push({ label, folderUri: URI.parse(workspace) }); + } + }); + } else if (Array.isArray(storedRecents.workspaces2)) { + restoreGracefully(storedRecents.workspaces2, workspace => { + if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configPath === 'string') { + result.workspaces.push({ workspace: { id: workspace.id, configPath: URI.file(workspace.configPath) } }); + } else if (typeof workspace === 'string') { + result.workspaces.push({ folderUri: URI.parse(workspace) }); + } + }); + } else if (Array.isArray(storedRecents.workspaces)) { + // TODO@martin legacy support can be removed at some point (6 month?) + // format of 1.25 and before + restoreGracefully(storedRecents.workspaces, workspace => { + if (typeof workspace === 'string') { + result.workspaces.push({ folderUri: URI.file(workspace) }); + } else if (isLegacySerializedWorkspace(workspace)) { + result.workspaces.push({ workspace: { id: workspace.id, configPath: URI.file(workspace.configPath) } }); + } else if (isUriComponents(workspace)) { + // added by 1.26-insiders + result.workspaces.push({ folderUri: URI.revive(workspace) }); + } + }); + } + if (Array.isArray(storedRecents.files2)) { + restoreGracefully(storedRecents.files2, (file, i) => { + const label: string | undefined = (Array.isArray(storedRecents.fileLabels) && storedRecents.fileLabels[i]) || undefined; + if (typeof file === 'string') { + result.files.push({ label, fileUri: URI.parse(file) }); + } + }); + } else if (Array.isArray(storedRecents.files)) { + restoreGracefully(storedRecents.files, file => { + if (typeof file === 'string') { + result.files.push({ fileUri: URI.file(file) }); + } + }); + } + } + + return result; +} + +export function toStoreData(recents: IRecentlyOpened): RecentlyOpenedStorageData { + const serialized: ISerializedRecentlyOpened = { workspaces3: [], files2: [] }; + + let hasLabel = false; + const workspaceLabels: (string | null)[] = []; + for (const recent of recents.workspaces) { + if (isRecentFolder(recent)) { + serialized.workspaces3.push(recent.folderUri.toString()); + } else { + serialized.workspaces3.push({ id: recent.workspace.id, configURIPath: recent.workspace.configPath.toString() }); + } + workspaceLabels.push(recent.label || null); + hasLabel = hasLabel || !!recent.label; + } + if (hasLabel) { + serialized.workspaceLabels = workspaceLabels; + } + + hasLabel = false; + const fileLabels: (string | null)[] = []; + for (const recent of recents.files) { + serialized.files2.push(recent.fileUri.toString()); + fileLabels.push(recent.label || null); + hasLabel = hasLabel || !!recent.label; + } + if (hasLabel) { + serialized.fileLabels = fileLabels; + } + + return serialized; +} + +//#endregion diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts similarity index 83% rename from src/vs/platform/history/electron-main/historyMainService.ts rename to src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index 54ca0d95c81..9c1239d1f13 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -5,34 +5,33 @@ import * as nls from 'vs/nls'; import * as arrays from 'vs/base/common/arrays'; -import { IStateService } from 'vs/platform/state/common/state'; +import { IStateService } from 'vs/platform/state/node/state'; import { app, JumpListCategory } from 'electron'; import { ILogService } from 'vs/platform/log/common/log'; -import { getBaseLabel, getPathLabel } from 'vs/base/common/labels'; +import { getBaseLabel, getPathLabel, splitName } from 'vs/base/common/labels'; import { IPath } from 'vs/platform/windows/common/windows'; import { Event as CommonEvent, Emitter } from 'vs/base/common/event'; import { isWindows, isMacintosh } from 'vs/base/common/platform'; -import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IRecentlyOpened, isRecentWorkspace, isRecentFolder, IRecent, isRecentFile, IRecentFolder, IRecentWorkspace, IRecentFile, toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { IRecentlyOpened, isRecentWorkspace, isRecentFolder, IRecent, isRecentFile, IRecentFolder, IRecentWorkspace, IRecentFile } from 'vs/platform/history/common/history'; import { ThrottledDelayer } from 'vs/base/common/async'; import { isEqual as areResourcesEqual, dirname, originalFSPath, basename } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label'; -import { toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/history/common/historyStorage'; import { exists } from 'vs/base/node/pfs'; import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Disposable } from 'vs/base/common/lifecycle'; -export const IHistoryMainService = createDecorator('historyMainService'); +export const IWorkspacesHistoryMainService = createDecorator('workspacesHistoryMainService'); -export interface IHistoryMainService { +export interface IWorkspacesHistoryMainService { _serviceBrand: undefined; - onRecentlyOpenedChange: CommonEvent; + readonly onRecentlyOpenedChange: CommonEvent; addRecentlyOpened(recents: IRecent[]): void; getRecentlyOpened(currentWorkspace?: IWorkspaceIdentifier, currentFolder?: ISingleFolderWorkspaceIdentifier, currentFiles?: IPath[]): IRecentlyOpened; @@ -42,7 +41,7 @@ export interface IHistoryMainService { updateWindowsJumpList(): void; } -export class HistoryMainService implements IHistoryMainService { +export class WorkspacesHistoryMainService extends Disposable implements IWorkspacesHistoryMainService { private static readonly MAX_TOTAL_RECENT_ENTRIES = 100; @@ -62,18 +61,27 @@ export class HistoryMainService implements IHistoryMainService { private readonly _onRecentlyOpenedChange = new Emitter(); readonly onRecentlyOpenedChange: CommonEvent = this._onRecentlyOpenedChange.event; - private macOSRecentDocumentsUpdater: ThrottledDelayer; + private macOSRecentDocumentsUpdater = this._register(new ThrottledDelayer(800)); constructor( @IStateService private readonly stateService: IStateService, @ILogService private readonly logService: ILogService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleMainService lifecycleMainService: ILifecycleMainService + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService ) { - this.macOSRecentDocumentsUpdater = new ThrottledDelayer(800); + super(); - lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList()); + this.registerListeners(); + } + + private registerListeners(): void { + + // Install window jump list after opening window + this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList()); + + // Add to history when entering workspace + this._register(this.workspacesMainService.onWorkspaceEntered(event => this.addRecentlyOpened([{ workspace: event.workspace }]))); } private handleWindowsJumpList(): void { @@ -108,7 +116,7 @@ export class HistoryMainService implements IHistoryMainService { // File else { const alreadyExistsInHistory = indexOfFile(files, curr.fileUri) >= 0; - const shouldBeFiltered = curr.fileUri.scheme === Schemas.file && HistoryMainService.COMMON_FILES_FILTER.indexOf(basename(curr.fileUri)) >= 0; + const shouldBeFiltered = curr.fileUri.scheme === Schemas.file && WorkspacesHistoryMainService.COMMON_FILES_FILTER.indexOf(basename(curr.fileUri)) >= 0; if (!alreadyExistsInHistory && !shouldBeFiltered) { files.push(curr); @@ -123,12 +131,12 @@ export class HistoryMainService implements IHistoryMainService { this.addEntriesFromStorage(workspaces, files); - if (workspaces.length > HistoryMainService.MAX_TOTAL_RECENT_ENTRIES) { - workspaces.length = HistoryMainService.MAX_TOTAL_RECENT_ENTRIES; + if (workspaces.length > WorkspacesHistoryMainService.MAX_TOTAL_RECENT_ENTRIES) { + workspaces.length = WorkspacesHistoryMainService.MAX_TOTAL_RECENT_ENTRIES; } - if (files.length > HistoryMainService.MAX_TOTAL_RECENT_ENTRIES) { - files.length = HistoryMainService.MAX_TOTAL_RECENT_ENTRIES; + if (files.length > WorkspacesHistoryMainService.MAX_TOTAL_RECENT_ENTRIES) { + files.length = WorkspacesHistoryMainService.MAX_TOTAL_RECENT_ENTRIES; } this.saveRecentlyOpened({ workspaces, files }); @@ -180,7 +188,7 @@ export class HistoryMainService implements IHistoryMainService { // Collect max-N recent workspaces that are known to exist const workspaceEntries: string[] = []; let entries = 0; - for (let i = 0; i < mru.workspaces.length && entries < HistoryMainService.MAX_MACOS_DOCK_RECENT_WORKSPACES; i++) { + for (let i = 0; i < mru.workspaces.length && entries < WorkspacesHistoryMainService.MAX_MACOS_DOCK_RECENT_WORKSPACES; i++) { const loc = location(mru.workspaces[i]); if (loc.scheme === Schemas.file) { const workspacePath = originalFSPath(loc); @@ -193,12 +201,12 @@ export class HistoryMainService implements IHistoryMainService { // Collect max-N recent files that are known to exist const fileEntries: string[] = []; - for (let i = 0; i < mru.files.length && entries < HistoryMainService.MAX_MACOS_DOCK_RECENT_ENTRIES_TOTAL; i++) { + for (let i = 0; i < mru.files.length && entries < WorkspacesHistoryMainService.MAX_MACOS_DOCK_RECENT_ENTRIES_TOTAL; i++) { const loc = location(mru.files[i]); if (loc.scheme === Schemas.file) { const filePath = originalFSPath(loc); if ( - HistoryMainService.COMMON_FILES_FILTER.indexOf(basename(loc)) !== -1 || // skip some well known file entries + WorkspacesHistoryMainService.COMMON_FILES_FILTER.indexOf(basename(loc)) !== -1 || // skip some well known file entries workspaceEntries.indexOf(filePath) !== -1 // prefer a workspace entry over a file entry (e.g. for .code-workspace) ) { continue; @@ -285,7 +293,7 @@ export class HistoryMainService implements IHistoryMainService { } private getRecentlyOpenedFromStorage(): IRecentlyOpened { - const storedRecents = this.stateService.getItem(HistoryMainService.recentlyOpenedStorageKey); + const storedRecents = this.stateService.getItem(WorkspacesHistoryMainService.recentlyOpenedStorageKey); return restoreRecentlyOpened(storedRecents, this.logService); } @@ -293,7 +301,7 @@ export class HistoryMainService implements IHistoryMainService { private saveRecentlyOpened(recent: IRecentlyOpened): void { const serialized = toStoreData(recent); - this.stateService.setItem(HistoryMainService.recentlyOpenedStorageKey, serialized); + this.stateService.setItem(WorkspacesHistoryMainService.recentlyOpenedStorageKey, serialized); } updateWindowsJumpList(): void { @@ -344,7 +352,7 @@ export class HistoryMainService implements IHistoryMainService { name: nls.localize('recentFolders', "Recent Workspaces"), items: arrays.coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(recent => { const workspace = isRecentWorkspace(recent) ? recent.workspace : recent.folderUri; - const title = recent.label || getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome); + const title = recent.label ? splitName(recent.label).name : getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome); let description; let args; diff --git a/src/vs/platform/workspaces/electron-main/workspacesIpc.ts b/src/vs/platform/workspaces/electron-main/workspacesIpc.ts deleted file mode 100644 index eee7aa30655..00000000000 --- a/src/vs/platform/workspaces/electron-main/workspacesIpc.ts +++ /dev/null @@ -1,58 +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 { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; -import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { URI } from 'vs/base/common/uri'; -import { Event } from 'vs/base/common/event'; -import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; - -export class WorkspacesChannel implements IServerChannel { - - constructor( - private workspacesMainService: IWorkspacesMainService, - private windowsMainService: IWindowsMainService - ) { } - - listen(_: unknown, event: string): Event { - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'createUntitledWorkspace': { - const rawFolders: IWorkspaceFolderCreationData[] = arg[0]; - const remoteAuthority: string = arg[1]; - let folders: IWorkspaceFolderCreationData[] | undefined = undefined; - if (Array.isArray(rawFolders)) { - folders = rawFolders.map(rawFolder => { - return { - uri: URI.revive(rawFolder.uri), // convert raw URI back to real URI - name: rawFolder.name - }; - }); - } - - return this.workspacesMainService.createUntitledWorkspace(folders, remoteAuthority); - } - case 'deleteUntitledWorkspace': { - const identifier: IWorkspaceIdentifier = arg; - return this.workspacesMainService.deleteUntitledWorkspace({ id: identifier.id, configPath: URI.revive(identifier.configPath) }); - } - case 'getWorkspaceIdentifier': { - return this.workspacesMainService.getWorkspaceIdentifier(URI.revive(arg)); - } - case 'enterWorkspace': { - const window = this.windowsMainService.getWindowById(arg[0]); - if (window) { - return this.windowsMainService.enterWorkspace(window, URI.revive(arg[1])); - } - } - } - - throw new Error(`Call not found: ${command}`); - } -} diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 6eaaba5d823..68dc1d14adb 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder, IEnterWorkspaceResult, isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { join, dirname } from 'vs/base/common/path'; import { mkdirp, writeFile, rimrafSync, readdirSync, writeFileSync } from 'vs/base/node/pfs'; @@ -17,39 +17,51 @@ import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { Disposable } from 'vs/base/common/lifecycle'; -import { originalFSPath, isEqualOrParent, joinPath } from 'vs/base/common/resources'; +import { originalFSPath, joinPath, isEqual, basename } from 'vs/base/common/resources'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; - -export interface IStoredWorkspace { - folders: IStoredWorkspaceFolder[]; - remoteAuthority?: string; -} +import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; +import { localize } from 'vs/nls'; +import product from 'vs/platform/product/common/product'; +import { MessageBoxOptions, BrowserWindow } from 'electron'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { findWindowOnWorkspace } from 'vs/platform/windows/node/window'; export const IWorkspacesMainService = createDecorator('workspacesMainService'); +export interface IWorkspaceEnteredEvent { + window: ICodeWindow; + workspace: IWorkspaceIdentifier; +} + export interface IWorkspacesMainService { _serviceBrand: undefined; - onUntitledWorkspaceDeleted: Event; + readonly onUntitledWorkspaceDeleted: Event; + readonly onWorkspaceEntered: Event; + enterWorkspace(intoWindow: ICodeWindow, openedWindows: ICodeWindow[], path: URI): Promise; + + createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; createUntitledWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier; - resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | null; - - isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean; - + deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise; deleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void; getUntitledWorkspacesSync(): IUntitledWorkspaceInfo[]; + isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean; - createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; - - deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise; - + resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | null; getWorkspaceIdentifier(workspacePath: URI): Promise; } +export interface IStoredWorkspace { + folders: IStoredWorkspaceFolder[]; + remoteAuthority?: string; +} + export class WorkspacesMainService extends Disposable implements IWorkspacesMainService { _serviceBrand: undefined; @@ -59,9 +71,14 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain private readonly _onUntitledWorkspaceDeleted = this._register(new Emitter()); readonly onUntitledWorkspaceDeleted: Event = this._onUntitledWorkspaceDeleted.event; + private readonly _onWorkspaceEntered = this._register(new Emitter()); + readonly onWorkspaceEntered: Event = this._onWorkspaceEntered.event; + constructor( @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IBackupMainService private readonly backupMainService: IBackupMainService, + @IDialogMainService private readonly dialogMainService: IDialogMainService ) { super(); @@ -87,7 +104,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain } private isWorkspacePath(uri: URI): boolean { - return this.isInsideWorkspacesHome(uri) || hasWorkspaceFileExtension(uri); + return isUntitledWorkspace(uri, this.environmentService) || hasWorkspaceFileExtension(uri); } private doResolveWorkspace(path: URI, contents: string): IResolvedWorkspace | null { @@ -113,22 +130,15 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain let storedWorkspace: IStoredWorkspace = json.parse(contents); // use fault tolerant parser // Filter out folders which do not have a path or uri set - if (Array.isArray(storedWorkspace.folders)) { + if (storedWorkspace && Array.isArray(storedWorkspace.folders)) { storedWorkspace.folders = storedWorkspace.folders.filter(folder => isStoredWorkspaceFolder(folder)); - } - - // Validate - if (!Array.isArray(storedWorkspace.folders)) { + } else { throw new Error(`${path.toString()} looks like an invalid workspace file.`); } return storedWorkspace; } - private isInsideWorkspacesHome(path: URI): boolean { - return isEqualOrParent(path, this.environmentService.untitledWorkspacesHome); - } - async createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { const { workspace, storedWorkspace } = this.newUntitledWorkspace(folders, remoteAuthority); const configPath = workspace.configPath.fsPath; @@ -179,7 +189,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain } isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean { - return this.isInsideWorkspacesHome(workspace.configPath); + return isUntitledWorkspace(workspace.configPath, this.environmentService); } deleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void { @@ -230,12 +240,87 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain } } } catch (error) { - if (error && error.code !== 'ENOENT') { + if (error.code !== 'ENOENT') { this.logService.warn(`Unable to read folders in ${this.untitledWorkspacesHome} (${error}).`); } } return untitledWorkspaces; } + + async enterWorkspace(window: ICodeWindow, windows: ICodeWindow[], path: URI): Promise { + if (!window || !window.win || !window.isReady) { + return null; // return early if the window is not ready or disposed + } + + const isValid = await this.isValidTargetWorkspacePath(window, windows, path); + if (!isValid) { + return null; // return early if the workspace is not valid + } + + const result = this.doEnterWorkspace(window, getWorkspaceIdentifier(path)); + if (!result) { + return null; + } + + // Emit as event + this._onWorkspaceEntered.fire({ window, workspace: result.workspace }); + + return result; + } + + private async isValidTargetWorkspacePath(window: ICodeWindow, windows: ICodeWindow[], path?: URI): Promise { + if (!path) { + return true; + } + + if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) { + return false; // window is already opened on a workspace with that path + } + + // Prevent overwriting a workspace that is currently opened in another window + if (findWindowOnWorkspace(windows, getWorkspaceIdentifier(path))) { + const options: MessageBoxOptions = { + title: product.nameLong, + type: 'info', + buttons: [localize('ok', "OK")], + message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", basename(path)), + detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."), + noLink: true + }; + + await this.dialogMainService.showMessageBox(options, withNullAsUndefined(BrowserWindow.getFocusedWindow())); + + return false; + } + + return true; // OK + } + + private doEnterWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult | null { + if (!window.config) { + return null; + } + + window.focus(); + + // Register window for backups and migrate current backups over + let backupPath: string | undefined; + if (!window.config.extensionDevelopmentPath) { + backupPath = this.backupMainService.registerWorkspaceBackupSync({ workspace, remoteAuthority: window.remoteAuthority }, window.config.backupPath); + } + + // if the window was opened on an untitled workspace, delete it. + if (window.openedWorkspace && this.isUntitledWorkspace(window.openedWorkspace)) { + this.deleteUntitledWorkspaceSync(window.openedWorkspace); + } + + // Update window configuration properly based on transition to workspace + window.config.folderUri = undefined; + window.config.workspace = workspace; + window.config.backupPath = backupPath; + + return { workspace, backupPath }; + } } function getWorkspaceId(configPath: URI): string { diff --git a/src/vs/platform/workspaces/electron-main/workspacesService.ts b/src/vs/platform/workspaces/electron-main/workspacesService.ts new file mode 100644 index 00000000000..f416b074be1 --- /dev/null +++ b/src/vs/platform/workspaces/electron-main/workspacesService.ts @@ -0,0 +1,75 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { AddFirstParameterToFunctions } from 'vs/base/common/types'; +import { IWorkspacesService, IEnterWorkspaceResult, IWorkspaceFolderCreationData, IWorkspaceIdentifier, IRecentlyOpened, IRecent } from 'vs/platform/workspaces/common/workspaces'; +import { URI } from 'vs/base/common/uri'; +import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; +import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; +import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; + +export class WorkspacesService implements AddFirstParameterToFunctions /* only methods, not events */, number /* window ID */> { + + _serviceBrand: undefined; + + constructor( + @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, + @IWindowsMainService private readonly windowsMainService: IWindowsMainService, + @IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService + ) { + } + + //#region Workspace Management + + async enterWorkspace(windowId: number, path: URI): Promise { + const window = this.windowsMainService.getWindowById(windowId); + if (window) { + return this.workspacesMainService.enterWorkspace(window, this.windowsMainService.getWindows(), path); + } + + return null; + } + + createUntitledWorkspace(windowId: number, folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { + return this.workspacesMainService.createUntitledWorkspace(folders, remoteAuthority); + } + + deleteUntitledWorkspace(windowId: number, workspace: IWorkspaceIdentifier): Promise { + return this.workspacesMainService.deleteUntitledWorkspace(workspace); + } + + getWorkspaceIdentifier(windowId: number, workspacePath: URI): Promise { + return this.workspacesMainService.getWorkspaceIdentifier(workspacePath); + } + + //#endregion + + //#region Workspaces History + + readonly onRecentlyOpenedChange = this.workspacesHistoryMainService.onRecentlyOpenedChange; + + async getRecentlyOpened(windowId: number): Promise { + const window = this.windowsMainService.getWindowById(windowId); + if (window?.config) { + return this.workspacesHistoryMainService.getRecentlyOpened(window.config.workspace, window.config.folderUri, window.config.filesToOpenOrCreate); + } + + return this.workspacesHistoryMainService.getRecentlyOpened(); + } + + async addRecentlyOpened(windowId: number, recents: IRecent[]): Promise { + return this.workspacesHistoryMainService.addRecentlyOpened(recents); + } + + async removeFromRecentlyOpened(windowId: number, paths: URI[]): Promise { + return this.workspacesHistoryMainService.removeFromRecentlyOpened(paths); + } + + async clearRecentlyOpened(windowId: number): Promise { + return this.workspacesHistoryMainService.clearRecentlyOpened(); + } + + //#endregion +} diff --git a/src/vs/platform/history/test/electron-main/historyStorage.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesHistoryStorage.test.ts similarity index 96% rename from src/vs/platform/history/test/electron-main/historyStorage.test.ts rename to src/vs/platform/workspaces/test/electron-main/workspacesHistoryStorage.test.ts index 4a76b1515ea..ecdc561c986 100644 --- a/src/vs/platform/history/test/electron-main/historyStorage.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesHistoryStorage.test.ts @@ -2,14 +2,12 @@ * 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 { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, IRecentlyOpened, isRecentFolder, IRecentFolder, IRecentWorkspace, toStoreData, restoreRecentlyOpened } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; -import { IRecentlyOpened, isRecentFolder, IRecentFolder, IRecentWorkspace } from 'vs/platform/history/common/history'; -import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage'; import { NullLogService } from 'vs/platform/log/common/log'; function toWorkspace(uri: URI): IWorkspaceIdentifier { @@ -221,4 +219,4 @@ suite('History Storage', () => { }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index 7a4c711c604..e7baa0d80bd 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -18,6 +18,7 @@ import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { isWindows } from 'vs/base/common/platform'; import { normalizeDriveLetter } from 'vs/base/common/labels'; import { dirname, joinPath } from 'vs/base/common/resources'; +import { TestBackupMainService, TestDialogMainService } from 'vs/workbench/test/workbenchTestServices'; suite('WorkspacesMainService', () => { const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesservice'); @@ -43,7 +44,7 @@ suite('WorkspacesMainService', () => { let service: WorkspacesMainService; setup(async () => { - service = new WorkspacesMainService(environmentService, logService); + service = new WorkspacesMainService(environmentService, logService, new TestBackupMainService(), new TestDialogMainService()); // Delete any existing backups completely and then re-create it. await pfs.rimraf(untitledWorkspacesHomePath, pfs.RimRafMode.MOVE); diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 8ea0f29d743..25d57792ec3 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3877,6 +3877,149 @@ declare module 'vscode' { provideSelectionRanges(document: TextDocument, positions: Position[], token: CancellationToken): ProviderResult; } + /** + * Represents programming constructs like functions or constructors in the context + * of call hierarchy. + */ + export class CallHierarchyItem { + /** + * The name of this item. + */ + name: string; + + /** + * The kind of this item. + */ + kind: SymbolKind; + + /** + * Tags for this item. + */ + tags?: ReadonlyArray; + + /** + * More detail for this item, e.g. the signature of a function. + */ + detail?: string; + + /** + * The resource identifier of this item. + */ + uri: Uri; + + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + */ + range: Range; + + /** + * The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. + * Must be contained by the [`range`](#CallHierarchyItem.range). + */ + selectionRange: Range; + + /** + * Creates a new call hierarchy item. + */ + constructor(kind: SymbolKind, name: string, detail: string, uri: Uri, range: Range, selectionRange: Range); + } + + /** + * Represents an incoming call, e.g. a caller of a method or constructor. + */ + export class CallHierarchyIncomingCall { + + /** + * The item that makes the call. + */ + from: CallHierarchyItem; + + /** + * The range at which at which the calls appears. This is relative to the caller + * denoted by [`this.from`](#CallHierarchyIncomingCall.from). + */ + fromRanges: Range[]; + + /** + * Create a new call object. + * + * @param item The item making the call. + * @param fromRanges The ranges at which the calls appear. + */ + constructor(item: CallHierarchyItem, fromRanges: Range[]); + } + + /** + * Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. + */ + export class CallHierarchyOutgoingCall { + + /** + * The item that is called. + */ + to: CallHierarchyItem; + + /** + * The range at which this item is called. This is the range relative to the caller, e.g the item + * passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls) + * and not [`this.to`](#CallHierarchyOutgoingCall.to). + */ + fromRanges: Range[]; + + /** + * Create a new call object. + * + * @param item The item being called + * @param fromRanges The ranges at which the calls appear. + */ + constructor(item: CallHierarchyItem, fromRanges: Range[]); + } + + /** + * The call hierarchy provider interface describes the constract between extensions + * and the call hierarchy feature which allows to browse calls and caller of function, + * methods, constructor etc. + */ + export interface CallHierarchyProvider { + + /** + * Bootstraps call hierarchy by returning the item that is denoted by the given document + * and position. This item will be used as entry into the call graph. Providers should + * return `undefined` or `null` when there is no item at the given location. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @returns A call hierarchy item or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + prepareCallHierarchy(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + + /** + * Provide all incoming calls for an item, e.g all callers for a method. In graph terms this describes directed + * and annotated edges inside the call graph, e.g the given item is the starting node and the result is the nodes + * that can be reached. + * + * @param item The hierarchy item for which incoming calls should be computed. + * @param token A cancellation token. + * @returns A set of incoming calls or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideCallHierarchyIncomingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult; + + /** + * Provide all outgoing calls for an item, e.g call calls to functions, methods, or constructors from the given item. In + * graph terms this describes directed and annotated edges inside the call graph, e.g the given item is the starting + * node and the result is the nodes that can be reached. + * + * @param item The hierarchy item for which outgoing calls should be computed. + * @param token A cancellation token. + * @returns A set of outgoing calls or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideCallHierarchyOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult; + } + /** * A tuple of two characters, like a pair of * opening and closing brackets. @@ -4080,11 +4223,11 @@ declare module 'vscode' { * - Workspace configuration (if available) * - Workspace folder configuration of the requested resource (if available) * - * *Global configuration* comes from User Settings and shadows Defaults. + * *Global configuration* comes from User Settings and overrides Defaults. * - * *Workspace configuration* comes from Workspace Settings and shadows Global configuration. + * *Workspace configuration* comes from Workspace Settings and overrides Global configuration. * - * *Workspace Folder configuration* comes from `.vscode` folder under one of the [workspace folders](#workspace.workspaceFolders). + * *Workspace Folder configuration* comes from `.vscode` folder under one of the [workspace folders](#workspace.workspaceFolders) and overrides Workspace configuration. * * *Note:* Workspace and Workspace Folder configurations contains `launch` and `tasks` settings. Their basename will be * part of the section identifier. The following snippets shows how to retrieve all configurations @@ -4133,9 +4276,9 @@ declare module 'vscode' { * a workspace-specific value and a folder-specific value. * * The *effective* value (returned by [`get`](#WorkspaceConfiguration.get)) - * is computed like this: `defaultValue` overwritten by `globalValue`, - * `globalValue` overwritten by `workspaceValue`. `workspaceValue` overwritten by `workspaceFolderValue`. - * Refer to [Settings Inheritance](https://code.visualstudio.com/docs/getstarted/settings) + * is computed like this: `defaultValue` overridden by `globalValue`, + * `globalValue` overridden by `workspaceValue`. `workspaceValue` overwridden by `workspaceFolderValue`. + * Refer to [Settings](https://code.visualstudio.com/docs/getstarted/settings) * for more information. * * *Note:* The configuration name must denote a leaf in the configuration tree @@ -4766,7 +4909,7 @@ declare module 'vscode' { /** * The extension kind describes if an extension runs where the UI runs * or if an extension runs where the remote extension host runs. The extension kind - * if defined in the `package.json` file of extensions but can also be refined + * is defined in the `package.json`-file of extensions but can also be refined * via the the `remote.extensionKind`-setting. When no remote extension host exists, * the value is [`ExtensionKind.UI`](#ExtensionKind.UI). */ @@ -5222,7 +5365,7 @@ declare module 'vscode' { /** * The shell command line. Is `undefined` if created with a command and arguments. */ - commandLine: string; + commandLine: string | undefined; /** * The shell command. Is `undefined` if created with a full command line. @@ -5241,6 +5384,22 @@ declare module 'vscode' { options?: ShellExecutionOptions; } + /** + * Class used to execute an extension callback as a task. + */ + export class CustomExecution { + /** + * Constructs a CustomExecution task object. The callback will be executed the task is run, at which point the + * extension should return the Pseudoterminal it will "run in". The task should wait to do further execution until + * [Pseudoterminal.open](#Pseudoterminal.open) is called. Task cancellation should be handled using + * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire + * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). + * @param process The [Pseudoterminal](#Pseudoterminal) to be used by the task to display output. + * @param callback The callback that will be called when the task is started by a user. + */ + constructor(callback: () => Thenable); + } + /** * The scope of a task. */ @@ -5283,7 +5442,7 @@ declare module 'vscode' { * or '$eslint'. Problem matchers can be contributed by an extension using * the `problemMatchers` extension point. */ - constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); /** * ~~Creates a new task.~~ @@ -5318,7 +5477,7 @@ declare module 'vscode' { /** * The task's execution engine */ - execution?: ProcessExecution | ShellExecution; + execution?: ProcessExecution | ShellExecution | CustomExecution; /** * Whether the task is a background task or not. @@ -6177,6 +6336,22 @@ declare module 'vscode' { writeText(value: string): Thenable; } + /** + * Possible kinds of UI that can use extensions. + */ + export enum UIKind { + + /** + * Extensions are accessed from a desktop application. + */ + Desktop = 1, + + /** + * Extensions are accessed from a web browser. + */ + Web = 2 + } + /** * Namespace describing the environment the editor runs in. */ @@ -6236,8 +6411,18 @@ declare module 'vscode' { export const shell: string; /** - * Opens an *external* item, e.g. a http(s) or mailto-link, using the - * default application. + * The UI kind property indicates from which UI extensions + * are accessed from. For example, extensions could be accessed + * from a desktop application or a web browser. + */ + export const uiKind: UIKind; + + /** + * Opens a link externally using the default application. Depending on the + * used scheme this can be: + * * a browser (`http:`, `https:`) + * * a mail client (`mailto:`) + * * VSCode itself (`vscode:` from `vscode.env.uriScheme`) * * *Note* that [`showTextDocument`](#window.showTextDocument) is the right * way to open a text document inside the editor, not this function. @@ -6246,6 +6431,57 @@ declare module 'vscode' { * @returns A promise indicating if open was successful. */ export function openExternal(target: Uri): Thenable; + + /** + * Resolves a uri to form that is accessible externally. Currently only supports `https:`, `http:` and + * `vscode.env.uriScheme` uris. + * + * #### `http:` or `https:` scheme + * + * Resolves an *external* uri, such as a `http:` or `https:` link, from where the extension is running to a + * uri to the same resource on the client machine. + * + * This is a no-op if the extension is running on the client machine. + * + * If the extension is running remotely, this function automatically establishes a port forwarding tunnel + * from the local machine to `target` on the remote and returns a local uri to the tunnel. The lifetime of + * the port fowarding tunnel is managed by VS Code and the tunnel can be closed by the user. + * + * *Note* that uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` on them. + * + * #### `vscode.env.uriScheme` + * + * Creates a uri that - if opened in a browser (e.g. via `openExternal`) - will result in a registered [UriHandler](#UriHandler) + * to trigger. + * + * Extensions should not make any assumptions about the resulting uri and should not alter it in anyway. + * Rather, extensions can e.g. use this uri in an authentication flow, by adding the uri as callback query + * argument to the server to authenticate to. + * + * *Note* that if the server decides to add additional query parameters to the uri (e.g. a token or secret), it + * will appear in the uri that is passed to the [UriHandler](#UriHandler). + * + * **Example** of an authentication flow: + * ```typescript + * vscode.window.registerUriHandler({ + * handleUri(uri: vscode.Uri): vscode.ProviderResult { + * if (uri.path === '/did-authenticate') { + * console.log(uri.toString()); + * } + * } + * }); + * + * const callableUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://my.extension/did-authenticate`)); + * await vscode.env.openExternal(callableUri); + * ``` + * + * *Note* that extensions should not cache the result of `asExternalUri` as the resolved uri may become invalid due to + * a system or user action — for example, in remote cases, a user may close a port forwarding tunnel that was opened by + * `asExternalUri`. + * + * @return A uri that can be used on the client machine. + */ + export function asExternalUri(target: Uri): Thenable; } /** @@ -6333,7 +6569,7 @@ declare module 'vscode' { export function executeCommand(command: string, ...rest: any[]): Thenable; /** - * Retrieve the list of all available commands. Commands starting an underscore are + * Retrieve the list of all available commands. Commands starting with an underscore are * treated as internal commands. * * @param filterInternal Set `true` to not see internal commands (starting with an underscore) @@ -7016,6 +7252,7 @@ declare module 'vscode' { /** * An optional human-readable message that will be rendered in the view. + * Setting the message to null, undefined, or empty string will remove the message from the view. */ message?: string; @@ -7297,7 +7534,7 @@ declare module 'vscode' { * A number can be used to provide an exit code for the terminal. Exit codes must be * positive and a non-zero exit codes signals failure which shows a notification for a * regular terminal and allows dependent tasks to proceed when used with the - * `CustomExecution2` API. + * `CustomExecution` API. * * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. * ```typescript @@ -8628,6 +8865,15 @@ declare module 'vscode' { */ export function registerSelectionRangeProvider(selector: DocumentSelector, provider: SelectionRangeProvider): Disposable; + /** + * Register a call hierarchy provider. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A call hierarchy provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyProvider): Disposable; + /** * Set a [language configuration](#LanguageConfiguration) for a language. * @@ -9217,6 +9463,41 @@ declare module 'vscode' { constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string); } + /** + * Debug console mode used by debug session, see [options](#DebugSessionOptions). + */ + export enum DebugConsoleMode { + /** + * Debug session should have a separate debug console. + */ + Separate = 0, + + /** + * Debug session should share debug console with its parent session. + * This value has no effect for sessions which do not have a parent session. + */ + MergeWithParent = 1 + } + + /** + * Options for [starting a debug session](#debug.startDebugging). + */ + export interface DebugSessionOptions { + + /** + * When specified the newly created debug session is registered as a "child" session of this + * "parent" debug session. + */ + parentSession?: DebugSession; + + /** + * Controls whether this session should have a separate debug console or share it + * with the parent session. Has no effect for sessions which do not have a parent session. + * Defaults to Separate. + */ + consoleMode?: DebugConsoleMode; + } + /** * Namespace for debug functionality. */ @@ -9307,10 +9588,10 @@ declare module 'vscode' { * Folder specific variables used in the configuration (e.g. '${workspaceFolder}') are resolved against the given folder. * @param folder The [workspace folder](#WorkspaceFolder) for looking up named configurations and resolving variables or `undefined` for a non-folder setup. * @param nameOrConfiguration Either the name of a debug or compound configuration or a [DebugConfiguration](#DebugConfiguration) object. - * @param parent If specified the newly created debug session is registered as a "child" session of a "parent" debug session. + * @param parentSessionOrOptions Debug sesison options. When passed a parent [debug session](#DebugSession), assumes options with just this parent session. * @return A thenable that resolves when debugging could be successfully started. */ - export function startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, parentSession?: DebugSession): Thenable; + export function startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, parentSessionOrOptions?: DebugSession | DebugSessionOptions): Thenable; /** * Add breakpoints. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ebae08b5d87..bf94a721b2b 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -16,89 +16,6 @@ declare module 'vscode' { - //#region Joh - call hierarchy - - export class CallHierarchyItem { - /** - * The name of this item. - */ - name: string; - - /** - * The kind of this item. - */ - kind: SymbolKind; - - /** - * Tags for this item. - */ - tags?: ReadonlyArray; - - /** - * More detail for this item, e.g. the signature of a function. - */ - detail?: string; - - /** - * The resource identifier of this item. - */ - uri: Uri; - - /** - * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. - */ - range: Range; - - /** - * The range that should be selected and reveal when this symbol is being picked, e.g. the name of a function. - * Must be contained by the [`range`](#CallHierarchyItem.range). - */ - selectionRange: Range; - - constructor(kind: SymbolKind, name: string, detail: string, uri: Uri, range: Range, selectionRange: Range); - } - - export class CallHierarchyIncomingCall { - source: CallHierarchyItem; - sourceRanges: Range[]; - constructor(item: CallHierarchyItem, sourceRanges: Range[]); - } - - export class CallHierarchyOutgoingCall { - sourceRanges: Range[]; - target: CallHierarchyItem; - constructor(item: CallHierarchyItem, sourceRanges: Range[]); - } - - export interface CallHierarchyItemProvider { - - /** - * Provide a list of callers for the provided item, e.g. all function calling a function. - */ - provideCallHierarchyIncomingCalls(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; - - /** - * Provide a list of calls for the provided item, e.g. all functions call from a function. - */ - provideCallHierarchyOutgoingCalls(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; - - // todo@joh this could return as 'prepareCallHierarchy' (similar to the RenameProvider#prepareRename) - // - // /** - // * - // * Given a document and position compute a call hierarchy item. This is justed as - // * anchor for call hierarchy and then `resolveCallHierarchyItem` is being called. - // */ - // resolveCallHierarchyItem(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; - } - - export namespace languages { - export function registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyItemProvider): Disposable; - } - - //#endregion - - //#region Alex - resolvers export interface RemoteAuthorityResolverContext { @@ -673,56 +590,6 @@ declare module 'vscode' { debugAdapterExecutable?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult; } - /** - * Debug console mode used by debug session, see [options](#DebugSessionOptions). - */ - export enum DebugConsoleMode { - /** - * Debug session should have a separate debug console. - */ - Separate = 0, - - /** - * Debug session should share debug console with its parent session. - * This value has no effect for sessions which do not have a parent session. - */ - MergeWithParent = 1 - } - - /** - * Options for [starting a debug session](#debug.startDebugging). - */ - export interface DebugSessionOptions { - - /** - * When specified the newly created debug session is registered as a "child" session of this - * "parent" debug session. - */ - parentSession?: DebugSession; - - /** - * Controls whether this session should have a separate debug console or share it - * with the parent session. Has no effect for sessions which do not have a parent session. - * Defaults to Separate. - */ - consoleMode?: DebugConsoleMode; - } - - export namespace debug { - /** - * Start debugging by using either a named launch or named compound configuration, - * or by directly passing a [DebugConfiguration](#DebugConfiguration). - * The named configurations are looked up in '.vscode/launch.json' found in the given folder. - * Before debugging starts, all unsaved files are saved and the launch configurations are brought up-to-date. - * Folder specific variables used in the configuration (e.g. '${workspaceFolder}') are resolved against the given folder. - * @param folder The [workspace folder](#WorkspaceFolder) for looking up named configurations and resolving variables or `undefined` for a non-folder setup. - * @param nameOrConfiguration Either the name of a debug or compound configuration or a [DebugConfiguration](#DebugConfiguration) object. - * @param parentSessionOrOptions Debug sesison options. When passed a parent [debug session](#DebugSession), assumes options with just this parent session. - * @return A thenable that resolves when debugging could be successfully started. - */ - export function startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, parentSessionOrOptions?: DebugSession | DebugSessionOptions): Thenable; - } - //#endregion //#region Rob, Matt: logging @@ -898,20 +765,45 @@ declare module 'vscode' { //#endregion //#region mjbvz,joh: https://github.com/Microsoft/vscode/issues/43768 + + export interface FileCreateEvent { + readonly created: ReadonlyArray; + } + + export interface FileWillCreateEvent { + readonly creating: ReadonlyArray; + waitUntil(thenable: Thenable): void; + } + + export interface FileDeleteEvent { + readonly deleted: ReadonlyArray; + } + + export interface FileWillDeleteEvent { + readonly deleting: ReadonlyArray; + waitUntil(thenable: Thenable): void; + } + export interface FileRenameEvent { - readonly oldUri: Uri; - readonly newUri: Uri; + readonly renamed: ReadonlyArray<{ oldUri: Uri, newUri: Uri }>; } export interface FileWillRenameEvent { - readonly oldUri: Uri; - readonly newUri: Uri; - waitUntil(thenable: Thenable): void; + readonly renaming: ReadonlyArray<{ oldUri: Uri, newUri: Uri }>; + waitUntil(thenable: Thenable): void; // TODO@joh support sync/async } export namespace workspace { - export const onWillRenameFile: Event; - export const onDidRenameFile: Event; + + export const onWillCreateFiles: Event; + export const onDidCreateFiles: Event; + + export const onWillDeleteFiles: Event; + export const onDidDeleteFiles: Event; + + export const onWillRenameFiles: Event; + export const onDidRenameFiles: Event; + } //#endregion @@ -928,7 +820,8 @@ declare module 'vscode' { export interface TreeView { /** - * The name of the tree view. It is set from the extension package.json and can be changed later. + * The tree view title is initially taken from the extension package.json + * Changes to the title property will be properly reflected in the UI in the title of the view. */ title?: string; } @@ -966,50 +859,15 @@ declare module 'vscode' { //#endregion //#region CustomExecution - /** - * Class used to execute an extension callback as a task. - */ - export class CustomExecution2 { - /** - * @param process The [Pseudoterminal](#Pseudoterminal) to be used by the task to display output. - * @param callback The callback that will be called when the task is started by a user. - */ - constructor(callback: () => Thenable); - /** - * The callback used to execute the task. Cancellation should be handled using - * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire - * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). - */ - callback: () => Thenable; - } /** * A task to execute */ export class Task2 extends Task { - /** - * Creates a new task. - * - * @param definition The task definition as defined in the taskDefinitions extension point. - * @param scope Specifies the task's scope. It is either a global or a workspace task or a task for a specific workspace folder. - * @param name The task's name. Is presented in the user interface. - * @param source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface. - * @param execution The process or shell execution. - * @param problemMatchers the names of problem matchers to use, like '$tsc' - * or '$eslint'. Problem matchers can be contributed by an extension using - * the `problemMatchers` extension point. - */ - constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution2, problemMatchers?: string | string[]); - - /** - * The task's execution engine - */ - execution2?: ProcessExecution | ShellExecution | CustomExecution2; + detail?: string; } - //#endregion - //#region Tasks export interface TaskPresentationOptions { /** * Controls whether the task is executed in a specific terminal group using split panes. @@ -1079,146 +937,119 @@ declare module 'vscode' { export namespace env { /** - * Creates a Uri that - if opened in a browser - will result in a - * registered [UriHandler](#UriHandler) to fire. The handler's - * Uri will be configured with the path, query and fragment of - * [AppUriOptions](#AppUriOptions) if provided, otherwise it will be empty. - * - * Extensions should not make any assumptions about the resulting - * Uri and should not alter it in anyway. Rather, extensions can e.g. - * use this Uri in an authentication flow, by adding the Uri as - * callback query argument to the server to authenticate to. - * - * Note: If the server decides to add additional query parameters to the Uri - * (e.g. a token or secret), it will appear in the Uri that is passed - * to the [UriHandler](#UriHandler). - * - * **Example** of an authentication flow: - * ```typescript - * vscode.window.registerUriHandler({ - * handleUri(uri: vscode.Uri): vscode.ProviderResult { - * if (uri.path === '/did-authenticate') { - * console.log(uri.toString()); - * } - * } - * }); - * - * const callableUri = await vscode.env.createAppUri({ payload: { path: '/did-authenticate' } }); - * await vscode.env.openExternal(callableUri); - * ``` + * @deprecated use `vscode.env.asExternalUri` instead. */ export function createAppUri(options?: AppUriOptions): Thenable; } //#endregion - // #region Ben - UIKind - - /** - * Possible kinds of UI that can use extensions. - */ - export enum UIKind { - - /** - * Extensions are accessed from a desktop application. - */ - Desktop = 1, - - /** - * Extensions are accessed from a web browser. - */ - Web = 2 - } - - export namespace env { - - /** - * The UI kind property indicates from which UI extensions - * are accessed from. For example, extensions could be accessed - * from a desktop application or a web browser. - */ - export const uiKind: UIKind; - } - - //#endregion - //#region Custom editors, mjbvz - export enum WebviewEditorState { + /** + * + */ + interface WebviewEditorCapabilities { /** - * The webview editor's content cannot be modified. + * Invoked when the resource has been renamed in VS Code. * - * This disables save + * This is called when the resource's new name also matches the custom editor selector. + * + * If this is not implemented—or if the new resource name does not match the existing selector—then VS Code + * will close and reopen the editor on rename. + * + * @param newResource Full path to the resource. + * + * @return Thenable that signals the save is complete. */ - Readonly = 1, + rename?(newResource: Uri): Thenable; - /** - * The webview editor's content has not been changed but they can be modified and saved. - */ - Unchanged = 2, - - /** - * The webview editor's content has been changed and can be saved. - */ - Dirty = 3, + readonly editingCapability?: WebviewEditorEditingCapability; } - export interface WebviewEditor extends WebviewPanel { - state: WebviewEditorState; + interface WebviewEditorEditingCapability { + /** + * Persist the resource. + */ + save(resource: Uri): Thenable; /** - * Fired when the webview editor is saved. - * - * Both `Unchanged` and `Dirty` editors can be saved. - * - * Extensions should call `waitUntil` to signal when the save operation complete + * Called when the editor exits. */ - readonly onWillSave: Event<{ waitUntil: (thenable: Thenable) => void }>; + hotExit(hotExitPath: Uri): Thenable; + + /** + * Signal to VS Code that an edit has occurred. + * + * Edits must be a json serilizable object. + */ + readonly onEdit: Event; + + /** + * Apply a set of edits. + * + * This is triggered on redo and when restoring a custom editor after restart. Note that is not invoked + * when `onEdit` is called as `onEdit` implies also updating the view to reflect the edit. + * + * @param edit Array of edits. Sorted from oldest to most recent. + */ + applyEdits(edits: any[]): Thenable; + + /** + * Undo a set of edits. + * + * This is triggered when a user undoes an edit or when revert is called on a file. + * + * @param edit Array of edits. Sorted from most recent to oldest. + */ + undoEdits(edits: any[]): Thenable; } export interface WebviewEditorProvider { /** - * Fills out a `WebviewEditor` for a given resource. - * - * The provider should take ownership of passed in `editor`. - */ + * Fills out a `WebviewEditor` for a given resource. + * + * @param input Information about the resource being resolved. + * @param webview Webview being resolved. The provider should take ownership of this webview. + * + * @return Thenable to a `WebviewEditorCapabilities` indicating that the webview editor has been resolved. + * The `WebviewEditorCapabilities` defines how the custom editor interacts with VS Code. + * **❗️Note**: `WebviewEditorCapabilities` is not actually implemented... yet! + */ resolveWebviewEditor( - resource: Uri, - editor: WebviewEditor - ): Thenable; + input: { + readonly resource: Uri + }, + webview: WebviewPanel, + ): Thenable; } namespace window { export function registerWebviewEditorProvider( viewType: string, provider: WebviewEditorProvider, + options?: WebviewPanelOptions, ): Disposable; } //#endregion - // #region resolveExternalUri — mjbvz + //#region joh, insert/replace completions: https://github.com/microsoft/vscode/issues/10266 + + export interface CompletionItem { - namespace env { /** - * Resolves an *external* uri, such as a `http:` or `https:` link, from where the extension is running to a - * uri to the same resource on the client machine. + * A range or a insert and replace range selecting the text that should be replaced by this completion item. * - * This is a no-op if the extension is running locally. Currently only supports `https:` and `http:`. + * When omitted, the range of the [current word](#TextDocument.getWordRangeAtPosition) is used as replace-range + * and as insert-range the start of the [current word](#TextDocument.getWordRangeAtPosition) to the + * current position is used. * - * If the extension is running remotely, this function automatically establishes port forwarding from - * the local machine to `target` on the remote and returns a local uri that can be used to for this connection. - * - * Extensions should not store the result of `resolveExternalUri` as the resolved uri may become invalid due to - * a system or user action — for example, in remote cases, a user may close a port that was forwarded by - * `resolveExternalUri`. - * - * Note: uris passed through `openExternal` are automatically resolved and you should not call `resolveExternalUri` - * on them. - * - * @return A uri that can be used on the client machine. + * *Note 1:* A range must be a [single line](#Range.isSingleLine) and it must + * [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems). + * *Note 2:* A insert range must be a prefix of a replace range, that means it must be contained and starting at the same position. */ - export function resolveExternalUri(target: Uri): Thenable; + range2?: Range | { inserting: Range; replacing: Range; }; } //#endregion diff --git a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts index 859e9b337e8..b504c55e3b2 100644 --- a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts +++ b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts @@ -12,6 +12,7 @@ import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/br import { DisposableStore } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { isEqual } from 'vs/base/common/resources'; // todo@joh move these things back into something like contrib/insets class EditorWebviewZone implements IViewZone { @@ -75,7 +76,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { id = id.substr(0, id.indexOf(',')); //todo@joh HACK for (const candidate of this._editorService.listCodeEditors()) { - if (candidate.getId() === id && candidate.hasModel() && candidate.getModel()!.uri.toString() === URI.revive(uri).toString()) { + if (candidate.getId() === id && candidate.hasModel() && isEqual(candidate.getModel().uri, URI.revive(uri))) { editor = candidate; break; } @@ -90,11 +91,11 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { const webview = this._webviewService.createWebview('' + handle, { enableFindWidget: false, - extension: { id: extensionId, location: URI.revive(extensionLocation) } }, { allowScripts: options.enableScripts, localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined }); + webview.extension = { id: extensionId, location: URI.revive(extensionLocation) }; const webviewZone = new EditorWebviewZone(editor, line, height, webview); diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index 658199aebaa..3f18e9c1a05 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -18,7 +18,7 @@ import { Extensions as PanelExtensions, PanelDescriptor, PanelRegistry } from 'v import { ICommentInfo, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService'; import { CommentsPanel } from 'vs/workbench/contrib/comments/browser/commentsPanel'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../common/extHost.protocol'; +import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape, CommentThreadChanges } from '../common/extHost.protocol'; import { COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer'; @@ -116,17 +116,15 @@ export class MainThreadCommentThread implements modes.CommentThread { this._isDisposed = false; } - batchUpdate( - range: IRange, - label: string, - contextValue: string | undefined, - comments: modes.Comment[], - collapsibleState: modes.CommentThreadCollapsibleState) { - this._range = range; - this._label = label; - this._contextValue = contextValue; - this._comments = comments; - this._collapsibleState = collapsibleState; + batchUpdate(changes: CommentThreadChanges) { + const modified = (value: keyof CommentThreadChanges): boolean => + Object.prototype.hasOwnProperty.call(changes, value); + + if (modified('range')) { this._range = changes.range!; } + if (modified('label')) { this._label = changes.label; } + if (modified('contextValue')) { this._contextValue = changes.contextValue; } + if (modified('comments')) { this._comments = changes.comments; } + if (modified('collapseState')) { this._collapsibleState = changes.collapseState; } } dispose() { @@ -228,13 +226,9 @@ export class MainThreadCommentController { updateCommentThread(commentThreadHandle: number, threadId: string, resource: UriComponents, - range: IRange, - label: string, - contextValue: string | undefined, - comments: modes.Comment[], - collapsibleState: modes.CommentThreadCollapsibleState): void { + changes: CommentThreadChanges): void { let thread = this.getKnownThread(commentThreadHandle); - thread.batchUpdate(range, label, contextValue, comments, collapsibleState); + thread.batchUpdate(changes); this._commentService.updateComments(this._uniqueId, { added: [], @@ -430,18 +424,14 @@ export class MainThreadComments extends Disposable implements MainThreadComments commentThreadHandle: number, threadId: string, resource: UriComponents, - range: IRange, - label: string, - contextValue: string | undefined, - comments: modes.Comment[], - collapsibleState: modes.CommentThreadCollapsibleState): void { + changes: CommentThreadChanges): void { let provider = this._commentControllers.get(handle); if (!provider) { return undefined; } - return provider.updateCommentThread(commentThreadHandle, threadId, resource, range, label, contextValue, comments, collapsibleState); + return provider.updateCommentThread(commentThreadHandle, threadId, resource, changes); } $deleteCommentThread(handle: number, commentThreadHandle: number) { diff --git a/src/vs/workbench/api/browser/mainThreadEditor.ts b/src/vs/workbench/api/browser/mainThreadEditor.ts index 520801babe6..239f87096f1 100644 --- a/src/vs/workbench/api/browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/browser/mainThreadEditor.ts @@ -16,6 +16,7 @@ import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2 import { IApplyEditsOptions, IEditorPropertiesChangeData, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, IUndoStopOptions, TextEditorRevealType } from 'vs/workbench/api/common/extHost.protocol'; import { IEditor } from 'vs/workbench/common/editor'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { equals } from 'vs/base/common/arrays'; export interface IFocusTracker { onGainedFocus(): void; @@ -124,28 +125,12 @@ export class MainThreadTextEditorProperties { return null; } - private static _selectionsEqual(a: Selection[], b: Selection[]): boolean { - if (a.length !== b.length) { - return false; - } - for (let i = 0; i < a.length; i++) { - if (!a[i].equalsSelection(b[i])) { - return false; - } - } - return true; + private static _selectionsEqual(a: readonly Selection[], b: readonly Selection[]): boolean { + return equals(a, b, (aValue, bValue) => aValue.equalsSelection(bValue)); } - private static _rangesEqual(a: Range[], b: Range[]): boolean { - if (a.length !== b.length) { - return false; - } - for (let i = 0; i < a.length; i++) { - if (!a[i].equalsRange(b[i])) { - return false; - } - } - return true; + private static _rangesEqual(a: readonly Range[], b: readonly Range[]): boolean { + return equals(a, b, (aValue, bValue) => aValue.equalsRange(bValue)); } private static _optionsEqual(a: IResolvedTextEditorConfiguration, b: IResolvedTextEditorConfiguration): boolean { diff --git a/src/vs/workbench/api/browser/mainThreadFileSystem.ts b/src/vs/workbench/api/browser/mainThreadFileSystem.ts index 0d232f2870d..3407a420ca7 100644 --- a/src/vs/workbench/api/browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystem.ts @@ -6,7 +6,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode } from 'vs/platform/files/common/files'; +import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability } from 'vs/platform/files/common/files'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -67,7 +67,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { err.name = FileSystemProviderErrorCode.FileNotADirectory; throw err; } - return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._getFileType(child)]); + return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._getFileType(child)] as [string, FileType]); }).catch(MainThreadFileSystem._handleError); } @@ -80,19 +80,23 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } $writeFile(uri: UriComponents, content: VSBuffer): Promise { - return this._fileService.writeFile(URI.revive(uri), content).catch(MainThreadFileSystem._handleError); + return this._fileService.writeFile(URI.revive(uri), content) + .then(() => undefined).catch(MainThreadFileSystem._handleError); } $rename(source: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise { - return this._fileService.move(URI.revive(source), URI.revive(target), opts.overwrite).catch(MainThreadFileSystem._handleError); + return this._fileService.move(URI.revive(source), URI.revive(target), opts.overwrite) + .then(() => undefined).catch(MainThreadFileSystem._handleError); } $copy(source: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise { - return this._fileService.copy(URI.revive(source), URI.revive(target), opts.overwrite).catch(MainThreadFileSystem._handleError); + return this._fileService.copy(URI.revive(source), URI.revive(target), opts.overwrite) + .then(() => undefined).catch(MainThreadFileSystem._handleError); } $mkdir(uri: UriComponents): Promise { - return this._fileService.createFolder(URI.revive(uri)).catch(MainThreadFileSystem._handleError); + return this._fileService.createFolder(URI.revive(uri)) + .then(() => undefined).catch(MainThreadFileSystem._handleError); } $delete(uri: UriComponents, opts: FileDeleteOptions): Promise { @@ -121,12 +125,12 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } } -class RemoteFileSystemProvider implements IFileSystemProvider { +class RemoteFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileFolderCopyCapability { - private readonly _onDidChange = new Emitter(); + private readonly _onDidChange = new Emitter(); private readonly _registration: IDisposable; - readonly onDidChangeFile: Event = this._onDidChange.event; + readonly onDidChangeFile: Event = this._onDidChange.event; readonly capabilities: FileSystemProviderCapabilities; readonly onDidChangeCapabilities: Event = Event.None; diff --git a/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts b/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts index e35329a9dba..295bd0d8c9e 100644 --- a/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts @@ -3,21 +3,24 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { FileChangeType, IFileService, FileOperation } from 'vs/platform/files/common/files'; import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ExtHostContext, FileSystemEvents, IExtHostContext } from '../common/extHost.protocol'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { localize } from 'vs/nls'; @extHostCustomer export class MainThreadFileSystemEventService { - private readonly _listener = new Array(); + private readonly _listener = new DisposableStore(); constructor( extHostContext: IExtHostContext, @IFileService fileService: IFileService, - @ITextFileService textfileService: ITextFileService, + @ITextFileService textFileService: ITextFileService, + @IProgressService progressService: IProgressService ) { const proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemEventService); @@ -28,7 +31,7 @@ export class MainThreadFileSystemEventService { changed: [], deleted: [] }; - fileService.onFileChanges(event => { + this._listener.add(fileService.onFileChanges(event => { for (let change of event.changes) { switch (change.type) { case FileChangeType.ADDED: @@ -47,22 +50,35 @@ export class MainThreadFileSystemEventService { events.created.length = 0; events.changed.length = 0; events.deleted.length = 0; - }, undefined, this._listener); + })); - // file operation events - (changes the editor makes) - fileService.onAfterOperation(e => { - if (e.isOperation(FileOperation.MOVE)) { - proxy.$onFileRename(e.resource, e.target.resource); - } - }, undefined, this._listener); - textfileService.onWillMove(e => { - const promise = proxy.$onWillRename(e.oldResource, e.newResource); - e.waitUntil(promise); - }, undefined, this._listener); + // BEFORE file operation + const messages = new Map(); + messages.set(FileOperation.CREATE, localize('msg-create', "Running 'File Create' participants...")); + messages.set(FileOperation.DELETE, localize('msg-delete', "Running 'File Delete' participants...")); + messages.set(FileOperation.MOVE, localize('msg-rename', "Running 'File Rename' participants...")); + + this._listener.add(textFileService.onWillRunOperation(e => { + const p = progressService.withProgress({ location: ProgressLocation.Window }, progress => { + + progress.report({ message: messages.get(e.operation) }); + + const p1 = proxy.$onWillRunFileOperation(e.operation, e.target, e.source); + const p2 = new Promise((_resolve, reject) => { + setTimeout(() => reject(new Error('timeout')), 5000); + }); + return Promise.race([p1, p2]); + }); + + e.waitUntil(p); + })); + + // AFTER file operation + this._listener.add(textFileService.onDidRunOperation(e => proxy.$onDidRunFileOperation(e.operation, e.target, e.source))); } dispose(): void { - dispose(this._listener); + this._listener.dispose(); } } diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 03236d9db16..3bf1c91f082 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Position as EditorPosition } from 'vs/editor/common/core/position'; import { Range as EditorRange, IRange } from 'vs/editor/common/core/range'; -import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol'; +import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField } from '../common/extHost.protocol'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -333,22 +333,23 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- suggest - private static _inflateSuggestDto(defaultRange: IRange, data: ISuggestDataDto): modes.CompletionItem { + private static _inflateSuggestDto(defaultRange: IRange | { insert: IRange, replace: IRange }, data: ISuggestDataDto): modes.CompletionItem { + return { - label: data.a, - kind: data.b, - tags: data.n, - detail: data.c, - documentation: data.d, - sortText: data.e, - filterText: data.f, - preselect: data.g, - insertText: typeof data.h === 'undefined' ? data.a : data.h, - insertTextRules: data.i, - range: data.j || defaultRange, - commitCharacters: data.k, - additionalTextEdits: data.l, - command: data.m, + label: data[ISuggestDataDtoField.label], + kind: data[ISuggestDataDtoField.kind], + tags: data[ISuggestDataDtoField.kindModifier], + detail: data[ISuggestDataDtoField.detail], + documentation: data[ISuggestDataDtoField.documentation], + sortText: data[ISuggestDataDtoField.sortText], + filterText: data[ISuggestDataDtoField.filterText], + preselect: data[ISuggestDataDtoField.preselect], + insertText: typeof data.h === 'undefined' ? data[ISuggestDataDtoField.label] : data.h, + range: data[ISuggestDataDtoField.range] || defaultRange, + insertTextRules: data[ISuggestDataDtoField.insertTextRules], + commitCharacters: data[ISuggestDataDtoField.commitCharacters], + additionalTextEdits: data[ISuggestDataDtoField.additionalTextEdits], + command: data[ISuggestDataDtoField.command], // not-standard _id: data.x, }; @@ -377,6 +378,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha if (!result) { return suggestion; } + let newSuggestion = MainThreadLanguageFeatures._inflateSuggestDto(suggestion.range, result); return mixin(suggestion, newSuggestion, true); }); @@ -501,27 +503,39 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void { this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, { - provideOutgoingCalls: async (model, position, token) => { - const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, model.uri, position, token); + + prepareCallHierarchy: async (document, position, token) => { + const result = await this._proxy.$prepareCallHierarchy(handle, document.uri, position, token); + if (!result) { + return undefined; + } + return { + dispose: () => this._proxy.$releaseCallHierarchy(handle, result.sessionId), + root: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(result.root) + }; + }, + + provideOutgoingCalls: async (item, token) => { + const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, item.id, token); if (!outgoing) { return outgoing; } - return outgoing.map(([item, sourceRanges]): callh.OutgoingCall => { + return outgoing.map(([item, fromRanges]): callh.OutgoingCall => { return { - target: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item), - sourceRanges + to: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item), + fromRanges }; }); }, - provideIncomingCalls: async (model, position, token) => { - const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, model.uri, position, token); + provideIncomingCalls: async (item, token) => { + const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, item.id, token); if (!incoming) { return incoming; } - return incoming.map(([item, sourceRanges]): callh.IncomingCall => { + return incoming.map(([item, fromRanges]): callh.IncomingCall => { return { - source: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item), - sourceRanges + from: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item), + fromRanges }; }); } diff --git a/src/vs/workbench/api/browser/mainThreadSCM.ts b/src/vs/workbench/api/browser/mainThreadSCM.ts index 4488720cf9a..d8d861b8bb7 100644 --- a/src/vs/workbench/api/browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/browser/mainThreadSCM.ts @@ -114,7 +114,7 @@ class MainThreadSCMProvider implements ISCMProvider { get rootUri(): URI | undefined { return this._rootUri; } get contextValue(): string { return this._contextValue; } - get commitTemplate(): string | undefined { return this.features.commitTemplate; } + get commitTemplate(): string { return this.features.commitTemplate || ''; } get acceptInputCommand(): Command | undefined { return this.features.acceptInputCommand; } get statusBarCommands(): Command[] | undefined { return this.features.statusBarCommands; } get count(): number | undefined { return this.features.count; } @@ -288,7 +288,7 @@ export class MainThreadSCM implements MainThreadSCMShape { } $registerSourceControl(handle: number, id: string, label: string, rootUri: UriComponents | undefined): void { - const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri && URI.revive(rootUri), this.scmService); + const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri ? URI.revive(rootUri) : undefined, this.scmService); const repository = this.scmService.registerSCMProvider(provider); this._repositories.set(handle, repository); diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index c849ba99630..9bf1db3fe1c 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -50,7 +50,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant { // Nothing } - async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { + async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO); } @@ -112,7 +112,7 @@ export class FinalNewLineParticipant implements ISaveParticipantParticipant { // Nothing } - async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { + async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { this.doInsertFinalNewLine(model.textEditorModel); } @@ -146,7 +146,7 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipantParticipant // Nothing } - async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { + async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { this.doTrimFinalNewLines(model.textEditorModel, env.reason === SaveReason.AUTO); } @@ -216,7 +216,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant { // Nothing } - async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { + async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { const model = editorModel.textEditorModel; const overrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri }; @@ -250,7 +250,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { } - async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { + async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { if (env.reason === SaveReason.AUTO) { return undefined; } @@ -333,7 +333,7 @@ class ExtHostSaveParticipant implements ISaveParticipantParticipant { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentSaveParticipant); } - async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { + async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { if (!shouldSynchronizeModel(editorModel.textEditorModel)) { // the model never made it to the extension @@ -344,10 +344,8 @@ class ExtHostSaveParticipant implements ISaveParticipantParticipant { return new Promise((resolve, reject) => { setTimeout(() => reject(localize('timeout.onWillSave', "Aborted onWillSaveTextDocument-event after 1750ms")), 1750); this._proxy.$participateInSave(editorModel.getResource(), env.reason).then(values => { - for (const success of values) { - if (!success) { - return Promise.reject(new Error('listener failed')); - } + if (!values.every(success => success)) { + return Promise.reject(new Error('listener failed')); } return undefined; }).then(resolve, reject); @@ -384,7 +382,7 @@ export class SaveParticipant implements ISaveParticipant { this._saveParticipants.dispose(); } - async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise { + async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { return this._progressService.withProgress({ location: ProgressLocation.Window }, progress => { progress.report({ message: localize('saveParticipants', "Running Save Participants...") }); const promiseFactory = this._saveParticipants.getValue().map(p => () => { diff --git a/src/vs/workbench/api/browser/mainThreadStatusBar.ts b/src/vs/workbench/api/browser/mainThreadStatusBar.ts index fa6f8127595..91a9ba1419f 100644 --- a/src/vs/workbench/api/browser/mainThreadStatusBar.ts +++ b/src/vs/workbench/api/browser/mainThreadStatusBar.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; @@ -24,9 +24,13 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape { this.entries.clear(); } - $setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void { + $setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: string | undefined, color: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined): void { const entry: IStatusbarEntry = { text, tooltip, command, color }; + if (typeof priority === 'undefined') { + priority = 0; + } + // Reset existing entry if alignment or priority changed let existingEntry = this.entries.get(id); if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) { diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index 9e5763d0614..5e9120d8360 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -29,7 +29,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { TaskDefinitionDTO, TaskExecutionDTO, ProcessExecutionOptionsDTO, TaskPresentationOptionsDTO, - ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, CustomExecution2DTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO, + ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, CustomExecutionDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO, RunOptionsDTO } from 'vs/workbench/api/common/shared/tasks'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -131,7 +131,7 @@ namespace ProcessExecutionOptionsDTO { } namespace ProcessExecutionDTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecution2DTO): value is ProcessExecutionDTO { + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is ProcessExecutionDTO { const candidate = value as ProcessExecutionDTO; return candidate && !!candidate.process; } @@ -199,7 +199,7 @@ namespace ShellExecutionOptionsDTO { } namespace ShellExecutionDTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecution2DTO): value is ShellExecutionDTO { + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is ShellExecutionDTO { const candidate = value as ShellExecutionDTO; return candidate && (!!candidate.commandLine || !!candidate.command); } @@ -230,21 +230,21 @@ namespace ShellExecutionDTO { } } -namespace CustomExecution2DTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecution2DTO): value is CustomExecution2DTO { - const candidate = value as CustomExecution2DTO; - return candidate && candidate.customExecution === 'customExecution2'; +namespace CustomExecutionDTO { + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is CustomExecutionDTO { + const candidate = value as CustomExecutionDTO; + return candidate && candidate.customExecution === 'customExecution'; } - export function from(value: CommandConfiguration): CustomExecution2DTO { + export function from(value: CommandConfiguration): CustomExecutionDTO { return { - customExecution: 'customExecution2' + customExecution: 'customExecution' }; } - export function to(value: CustomExecution2DTO): CommandConfiguration { + export function to(value: CustomExecutionDTO): CommandConfiguration { return { - runtime: RuntimeType.CustomExecution2, + runtime: RuntimeType.CustomExecution, presentation: undefined }; } @@ -264,7 +264,7 @@ namespace TaskSourceDTO { } } else if (value.kind === TaskSourceKind.Workspace) { result.extensionId = '$core'; - result.scope = value.config.workspaceFolder.uri; + result.scope = value.config.workspaceFolder ? value.config.workspaceFolder.uri : TaskScope.Global; } return result; } @@ -311,7 +311,7 @@ namespace TaskDTO { const result: TaskDTO = { _id: task._id, name: task.configurationProperties.name, - definition: TaskDefinitionDTO.from(task.getDefinition()), + definition: TaskDefinitionDTO.from(task.getDefinition(true)), source: TaskSourceDTO.from(task._source), execution: undefined, presentationOptions: !ConfiguringTask.is(task) && task.command ? TaskPresentationOptionsDTO.from(task.command.presentation) : undefined, @@ -323,6 +323,9 @@ namespace TaskDTO { if (task.configurationProperties.group) { result.group = task.configurationProperties.group; } + if (task.configurationProperties.detail) { + result.detail = task.configurationProperties.detail; + } if (!ConfiguringTask.is(task) && task.command) { if (task.command.runtime === RuntimeType.Process) { result.execution = ProcessExecutionDTO.from(task.command); @@ -351,8 +354,8 @@ namespace TaskDTO { command = ShellExecutionDTO.to(task.execution); } else if (ProcessExecutionDTO.is(task.execution)) { command = ProcessExecutionDTO.to(task.execution); - } else if (CustomExecution2DTO.is(task.execution)) { - command = CustomExecution2DTO.to(task.execution); + } else if (CustomExecutionDTO.is(task.execution)) { + command = CustomExecutionDTO.to(task.execution); } } @@ -380,6 +383,7 @@ namespace TaskDTO { group: task.group, isBackground: !!task.isBackground, problemMatchers: task.problemMatchers.slice(), + detail: task.detail } ); return result; diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index cce3bcfa8cc..8344b323c7e 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -12,6 +12,7 @@ import { StopWatch } from 'vs/base/common/stopwatch'; import { ITerminalInstanceService, ITerminalService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering'; @extHostNamedCustomer(MainContext.MainThreadTerminalService) export class MainThreadTerminalService implements MainThreadTerminalServiceShape { @@ -327,16 +328,23 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape * listeners are removed. */ class TerminalDataEventTracker extends Disposable { + private readonly _bufferer: TerminalDataBufferer; + constructor( private readonly _callback: (id: number, data: string) => void, @ITerminalService private readonly _terminalService: ITerminalService ) { super(); + + this._register(this._bufferer = new TerminalDataBufferer()); + this._terminalService.terminalInstances.forEach(instance => this._registerInstance(instance)); this._register(this._terminalService.onInstanceCreated(instance => this._registerInstance(instance))); + this._register(this._terminalService.onInstanceDisposed(instance => this._bufferer.stopBuffering(instance.id))); } private _registerInstance(instance: ITerminalInstance): void { - this._register(instance.onData(e => this._callback(instance.id, e))); + // Buffer data events to reduce the amount of messages going to the extension host + this._register(this._bufferer.startBuffering(instance.id, instance.onData, this._callback)); } } diff --git a/src/vs/workbench/api/browser/mainThreadUrls.ts b/src/vs/workbench/api/browser/mainThreadUrls.ts index c5f54274e72..beda98076af 100644 --- a/src/vs/workbench/api/browser/mainThreadUrls.ts +++ b/src/vs/workbench/api/browser/mainThreadUrls.ts @@ -5,7 +5,7 @@ import { ExtHostContext, IExtHostContext, MainContext, MainThreadUrlsShape, ExtHostUrlsShape } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from '../common/extHostCustomers'; -import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; +import { IURLService, IURLHandler, IOpenURLOptions } from 'vs/platform/url/common/url'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/browser/extensionUrlHandler'; @@ -19,7 +19,7 @@ class ExtensionUrlHandler implements IURLHandler { readonly extensionId: ExtensionIdentifier ) { } - handleURL(uri: URI): Promise { + handleURL(uri: URI, options?: IOpenURLOptions): Promise { if (!ExtensionIdentifier.equals(this.extensionId, uri.authority)) { return Promise.resolve(false); } @@ -68,7 +68,11 @@ export class MainThreadUrls implements MainThreadUrlsShape { return Promise.resolve(undefined); } - async $createAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial }): Promise { + async $createAppUri(uri: UriComponents): Promise { + return this.urlService.create(uri); + } + + async $proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial }): Promise { const payload: Partial = options && options.payload ? options.payload : Object.create(null); // we define the authority to be the extension ID to ensure diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/browser/mainThreadWebview.ts index 2b6d4c71199..1ce660a06e8 100644 --- a/src/vs/workbench/api/browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/browser/mainThreadWebview.ts @@ -5,23 +5,24 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Schemas } from 'vs/base/common/network'; import { isWeb } from 'vs/base/common/platform'; import { startsWith } from 'vs/base/common/strings'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { generateUuid } from 'vs/base/common/uuid'; import * as modes from 'vs/editor/common/modes'; import { localize } from 'vs/nls'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IProductService } from 'vs/platform/product/common/productService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions, WebviewPanelViewStateData } from 'vs/workbench/api/common/extHost.protocol'; +import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor'; import { IEditorInput } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { CustomFileEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; +import { WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; -import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; +import { ICreateWebViewShowOptions, IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -30,7 +31,7 @@ import { extHostNamedCustomer } from '../common/extHostCustomers'; /** * Bi-directional map between webview handles and inputs. */ -class WebviewHandleStore { +class WebviewInputStore { private readonly _handlesToInputs = new Map(); private readonly _inputsToHandles = new Map(); @@ -60,47 +61,66 @@ class WebviewHandleStore { } } -@extHostNamedCustomer(MainContext.MainThreadWebviews) -export class MainThreadWebviews extends Disposable implements MainThreadWebviewsShape { +class WebviewViewTypeTransformer { + public constructor( + public readonly prefix: string, + ) { } + + public fromExternal(viewType: string): string { + return this.prefix + viewType; + } + + public toExternal(viewType: string): string | undefined { + return startsWith(viewType, this.prefix) + ? viewType.substr(this.prefix.length) + : undefined; + } +} + +const webviewPanelViewType = new WebviewViewTypeTransformer('mainThreadWebview-'); + +@extHostNamedCustomer(extHostProtocol.MainContext.MainThreadWebviews) +export class MainThreadWebviews extends Disposable implements extHostProtocol.MainThreadWebviewsShape { private static readonly standardSupportedLinkSchemes = new Set([ - 'http', - 'https', - 'mailto', - 'vscode', + Schemas.http, + Schemas.https, + Schemas.mailto, + Schemas.vscode, 'vscode-insider', ]); - private readonly _proxy: ExtHostWebviewsShape; - private readonly _webviewEditorInputs = new WebviewHandleStore(); + private readonly _proxy: extHostProtocol.ExtHostWebviewsShape; + private readonly _webviewInputs = new WebviewInputStore(); private readonly _revivers = new Map(); private readonly _editorProviders = new Map(); constructor( - context: IExtHostContext, + context: extHostProtocol.IExtHostContext, @IExtensionService extensionService: IExtensionService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, @IEditorService private readonly _editorService: IEditorService, - @IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService, @IOpenerService private readonly _openerService: IOpenerService, - @ITelemetryService private readonly _telemetryService: ITelemetryService, @IProductService private readonly _productService: IProductService, + @ITelemetryService private readonly _telemetryService: ITelemetryService, + @IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService, ) { super(); - this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews); + this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviews); this._register(_editorService.onDidActiveEditorChange(this.updateWebviewViewStates, this)); this._register(_editorService.onDidVisibleEditorsChange(this.updateWebviewViewStates, this)); // This reviver's only job is to activate webview panel extensions // This should trigger the real reviver to be registered from the extension host side. - this._register(_webviewEditorService.registerResolver({ + this._register(_webviewWorkbenchService.registerResolver({ canResolve: (webview: WebviewInput) => { - if (webview.getTypeId() === CustomFileEditorInput.typeId) { + if (webview instanceof CustomFileEditorInput) { + extensionService.activateByEvent(`onWebviewEditor:${webview.viewType}`); return false; } - const viewType = this.fromInternalWebviewViewType(webview.viewType); + const viewType = webviewPanelViewType.toExternal(webview.viewType); if (typeof viewType === 'string') { extensionService.activateByEvent(`onWebviewPanel:${viewType}`); } @@ -111,13 +131,12 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } public $createWebviewPanel( - handle: WebviewPanelHandle, + extensionData: extHostProtocol.WebviewExtensionDescription, + handle: extHostProtocol.WebviewPanelHandle, viewType: string, title: string, - showOptions: { viewColumn?: EditorViewColumn, preserveFocus?: boolean }, - options: WebviewInputOptions, - extensionId: ExtensionIdentifier, - extensionLocation: UriComponents + showOptions: { viewColumn?: EditorViewColumn, preserveFocus?: boolean; }, + options: WebviewInputOptions ): void { const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null); if (showOptions) { @@ -125,68 +144,59 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn); } - const webview = this._webviewEditorService.createWebview(handle, this.getInternalWebviewViewType(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), { - location: URI.revive(extensionLocation), - id: extensionId - }); + const extension = reviveWebviewExtension(extensionData); + const webview = this._webviewWorkbenchService.createWebview(handle, webviewPanelViewType.fromExternal(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), extension); this.hookupWebviewEventDelegate(handle, webview); - this._webviewEditorInputs.add(handle, webview); + this._webviewInputs.add(handle, webview); /* __GDPR__ "webviews:createWebviewPanel" : { "extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ - this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId.value }); + this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extension.id.value }); } - public $disposeWebview(handle: WebviewPanelHandle): void { - const webview = this.getWebviewEditorInput(handle); + public $disposeWebview(handle: extHostProtocol.WebviewPanelHandle): void { + const webview = this.getWebviewInput(handle); webview.dispose(); } - public $setTitle(handle: WebviewPanelHandle, value: string): void { - const webview = this.getWebviewEditorInput(handle); + public $setTitle(handle: extHostProtocol.WebviewPanelHandle, value: string): void { + const webview = this.getWebviewInput(handle); webview.setName(value); } - public $setState(handle: WebviewPanelHandle, state: modes.WebviewEditorState): void { - const webview = this.getWebviewEditorInput(handle); - if (webview instanceof CustomFileEditorInput) { - webview.setState(state); - } - } - - public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void { - const webview = this.getWebviewEditorInput(handle); + public $setIconPath(handle: extHostProtocol.WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents; } | undefined): void { + const webview = this.getWebviewInput(handle); webview.iconPath = reviveWebviewIcon(value); } - public $setHtml(handle: WebviewPanelHandle, value: string): void { - const webview = this.getWebviewEditorInput(handle); + public $setHtml(handle: extHostProtocol.WebviewPanelHandle, value: string): void { + const webview = this.getWebviewInput(handle); webview.webview.html = value; } - public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void { - const webview = this.getWebviewEditorInput(handle); - webview.webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */); + public $setOptions(handle: extHostProtocol.WebviewPanelHandle, options: modes.IWebviewOptions): void { + const webview = this.getWebviewInput(handle); + webview.webview.contentOptions = reviveWebviewOptions(options); } - public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void { - const webview = this.getWebviewEditorInput(handle); + public $reveal(handle: extHostProtocol.WebviewPanelHandle, showOptions: extHostProtocol.WebviewPanelShowOptions): void { + const webview = this.getWebviewInput(handle); if (webview.isDisposed()) { return; } const targetGroup = this._editorGroupService.getGroup(viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn)) || this._editorGroupService.getGroup(webview.group || 0); if (targetGroup) { - this._webviewEditorService.revealWebview(webview, targetGroup, !!showOptions.preserveFocus); + this._webviewWorkbenchService.revealWebview(webview, targetGroup, !!showOptions.preserveFocus); } } - public async $postMessage(handle: WebviewPanelHandle, message: any): Promise { - const webview = this.getWebviewEditorInput(handle); + public async $postMessage(handle: extHostProtocol.WebviewPanelHandle, message: any): Promise { + const webview = this.getWebviewInput(handle); webview.webview.sendMessage(message); return true; } @@ -196,35 +206,35 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews throw new Error(`Reviver for ${viewType} already registered`); } - this._revivers.set(viewType, this._webviewEditorService.registerResolver({ - canResolve: (webviewEditorInput) => { - return webviewEditorInput.viewType === this.getInternalWebviewViewType(viewType); + this._revivers.set(viewType, this._webviewWorkbenchService.registerResolver({ + canResolve: (webviewInput) => { + return webviewInput.viewType === webviewPanelViewType.fromExternal(viewType); }, - resolveWebview: async (webviewEditorInput): Promise => { - const viewType = this.fromInternalWebviewViewType(webviewEditorInput.viewType); + resolveWebview: async (webviewInput): Promise => { + const viewType = webviewPanelViewType.toExternal(webviewInput.viewType); if (!viewType) { - webviewEditorInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewEditorInput.viewType); + webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewInput.viewType); return; } - const handle = webviewEditorInput.id; - this._webviewEditorInputs.add(handle, webviewEditorInput); - this.hookupWebviewEventDelegate(handle, webviewEditorInput); + const handle = webviewInput.id; + this._webviewInputs.add(handle, webviewInput); + this.hookupWebviewEventDelegate(handle, webviewInput); let state = undefined; - if (webviewEditorInput.webview.state) { + if (webviewInput.webview.state) { try { - state = JSON.parse(webviewEditorInput.webview.state); + state = JSON.parse(webviewInput.webview.state); } catch { // noop } } try { - await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewEditorInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewEditorInput.group || 0), webviewEditorInput.webview.options); + await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options); } catch (error) { onUnexpectedError(error); - webviewEditorInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType); + webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType); } } })); @@ -240,39 +250,37 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews this._revivers.delete(viewType); } - public $registerEditorProvider(viewType: string): void { + public $registerEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions): void { if (this._editorProviders.has(viewType)) { throw new Error(`Provider for ${viewType} already registered`); } - this._editorProviders.set(viewType, this._webviewEditorService.registerResolver({ - canResolve: (webviewEditorInput) => { - return webviewEditorInput.getTypeId() !== WebviewInput.typeId && webviewEditorInput.viewType === viewType; - }, - resolveWebview: async (webview) => { - const handle = generateUuid(); - this._webviewEditorInputs.add(handle, webview); - this.hookupWebviewEventDelegate(handle, webview); + const extension = reviveWebviewExtension(extensionData); - if (webview instanceof CustomFileEditorInput) { - webview.onWillSave(e => { - e.waitUntil(this._proxy.$save(handle)); - }); - } + this._editorProviders.set(viewType, this._webviewWorkbenchService.registerResolver({ + canResolve: (webviewInput) => { + return webviewInput instanceof CustomFileEditorInput && webviewInput.viewType === viewType; + }, + resolveWebview: async (webviewInput) => { + const handle = webviewInput.id; + this._webviewInputs.add(handle, webviewInput); + this.hookupWebviewEventDelegate(handle, webviewInput); + + webviewInput.webview.options = options; + webviewInput.webview.extension = extension; try { await this._proxy.$resolveWebviewEditor( - webview.getResource(), + webviewInput.getResource(), handle, viewType, - webview.getTitle(), - webview.webview.state, - editorGroupToViewColumn(this._editorGroupService, webview.group || 0), - webview.webview.options + webviewInput.getTitle(), + editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), + webviewInput.webview.options ); } catch (error) { onUnexpectedError(error); - webview.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType); + webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType); } } })); @@ -288,42 +296,24 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews this._editorProviders.delete(viewType); } - private getInternalWebviewViewType(viewType: string): string { - return `mainThreadWebview-${viewType}`; - } - - private fromInternalWebviewViewType(viewType: string): string | undefined { - if (!startsWith(viewType, 'mainThreadWebview-')) { - return undefined; - } - return viewType.replace(/^mainThreadWebview-/, ''); - } - - private hookupWebviewEventDelegate(handle: WebviewPanelHandle, input: WebviewInput) { + private hookupWebviewEventDelegate(handle: extHostProtocol.WebviewPanelHandle, input: WebviewInput) { input.webview.onDidClickLink((uri: URI) => this.onDidClickLink(handle, uri)); input.webview.onMessage((message: any) => this._proxy.$onMessage(handle, message)); input.onDispose(() => { this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => { - this._webviewEditorInputs.delete(handle); + this._webviewInputs.delete(handle); }); }); - input.webview.onDidUpdateState((newState: any) => { - const webview = this.tryGetWebviewEditorInput(handle); - if (!webview || webview.isDisposed()) { - return; - } - webview.webview.state = newState; - }); input.webview.onMissingCsp((extension: ExtensionIdentifier) => this._proxy.$onMissingCsp(handle, extension.value)); } private updateWebviewViewStates() { - if (!this._webviewEditorInputs.size) { + if (!this._webviewInputs.size) { return; } const activeInput = this._editorService.activeControl && this._editorService.activeControl.input; - const viewStates: WebviewPanelViewStateData = {}; + const viewStates: extHostProtocol.WebviewPanelViewStateData = {}; const updateViewStatesForInput = (group: IEditorGroup, topLevelInput: IEditorInput, editorInput: IEditorInput) => { if (!(editorInput instanceof WebviewInput)) { @@ -332,11 +322,11 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews editorInput.updateGroup(group.id); - const handle = this._webviewEditorInputs.getHandleForInput(editorInput); + const handle = this._webviewInputs.getHandleForInput(editorInput); if (handle) { viewStates[handle] = { - visible: topLevelInput.matches(group.activeEditor), - active: topLevelInput.matches(activeInput), + visible: topLevelInput === group.activeEditor, + active: topLevelInput === activeInput, position: editorGroupToViewColumn(this._editorGroupService, group.id), }; } @@ -358,10 +348,10 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } } - private onDidClickLink(handle: WebviewPanelHandle, link: URI): void { - const webview = this.getWebviewEditorInput(handle); + private onDidClickLink(handle: extHostProtocol.WebviewPanelHandle, link: URI): void { + const webview = this.getWebviewInput(handle); if (this.isSupportedLink(webview, link)) { - this._openerService.open(link); + this._openerService.open(link, { fromUserGesture: true }); } } @@ -372,19 +362,19 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews if (!isWeb && this._productService.urlProtocol === link.scheme) { return true; } - return !!webview.webview.contentOptions.enableCommandUris && link.scheme === 'command'; + return !!webview.webview.contentOptions.enableCommandUris && link.scheme === Schemas.command; } - private getWebviewEditorInput(handle: WebviewPanelHandle): WebviewInput { - const webview = this.tryGetWebviewEditorInput(handle); + private getWebviewInput(handle: extHostProtocol.WebviewPanelHandle): WebviewInput { + const webview = this.tryGetWebviewInput(handle); if (!webview) { throw new Error('Unknown webview handle:' + handle); } return webview; } - private tryGetWebviewEditorInput(handle: WebviewPanelHandle): WebviewInput | undefined { - return this._webviewEditorInputs.getInputForHandle(handle); + private tryGetWebviewInput(handle: extHostProtocol.WebviewPanelHandle): WebviewInput | undefined { + return this._webviewInputs.getInputForHandle(handle); } private static getDeserializationFailedContents(viewType: string) { @@ -399,6 +389,10 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } } +function reviveWebviewExtension(extensionData: extHostProtocol.WebviewExtensionDescription): WebviewExtensionDescription { + return { id: extensionData.id, location: URI.revive(extensionData.location) }; +} + function reviveWebviewOptions(options: modes.IWebviewOptions): WebviewInputOptions { return { ...options, @@ -407,10 +401,9 @@ function reviveWebviewOptions(options: modes.IWebviewOptions): WebviewInputOptio }; } - function reviveWebviewIcon( - value: { light: UriComponents, dark: UriComponents } | undefined -): { light: URI, dark: URI } | undefined { + value: { light: UriComponents, dark: UriComponents; } | undefined +): { light: URI, dark: URI; } | undefined { if (!value) { return undefined; } diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index 2fb07578e85..bbce19a3388 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -7,9 +7,9 @@ import { Event } from 'vs/base/common/event'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ExtHostContext, ExtHostWindowShape, IExtHostContext, IOpenUriOptions, MainContext, MainThreadWindowShape } from '../common/extHost.protocol'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; @extHostNamedCustomer(MainContext.MainThreadWindow) export class MainThreadWindow implements MainThreadWindowShape { @@ -20,12 +20,12 @@ export class MainThreadWindow implements MainThreadWindowShape { constructor( extHostContext: IExtHostContext, - @IWindowService private readonly windowService: IWindowService, + @IHostService private readonly hostService: IHostService, @IOpenerService private readonly openerService: IOpenerService, ) { this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostWindow); - Event.latch(windowService.onDidChangeFocus) + Event.latch(hostService.onDidChangeFocus) (this.proxy.$onDidChangeWindowFocus, this.proxy, this.disposables); } @@ -39,7 +39,7 @@ export class MainThreadWindow implements MainThreadWindowShape { } $getWindowVisibility(): Promise { - return this.windowService.isFocused(); + return Promise.resolve(this.hostService.hasFocus); } async $openUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { @@ -47,7 +47,7 @@ export class MainThreadWindow implements MainThreadWindowShape { return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling }); } - async $resolveExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { + async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { const uri = URI.revive(uriComponents); const result = await this.openerService.resolveExternalUri(uri, options); return result.resolved; diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index f26b4091428..b41e21a9cad 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -16,10 +16,10 @@ import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platfor import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData, ITextSearchComplete } from '../common/extHost.protocol'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { isEqualOrParent } from 'vs/base/common/resources'; +import { isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { withNullAsUndefined } from 'vs/base/common/types'; import { IFileService } from 'vs/platform/files/common/files'; @@ -121,7 +121,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { } return { configuration: workspace.configuration || undefined, - isUntitled: workspace.configuration ? isEqualOrParent(workspace.configuration, this._environmentService.untitledWorkspacesHome) : false, + isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false, folders: workspace.folders, id: workspace.id, name: this._labelService.getWorkspaceLabel(workspace) diff --git a/src/vs/workbench/api/browser/media/test.svg b/src/vs/workbench/api/browser/media/test.svg index 57cd408942d..569947a033e 100644 --- a/src/vs/workbench/api/browser/media/test.svg +++ b/src/vs/workbench/api/browser/media/test.svg @@ -1,10 +1,3 @@ - - - - - - - - + + - diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index 06e521040c9..0f1fe0a1eee 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -83,7 +83,7 @@ interface IUserFriendlyViewDescriptor { // From 'remoteViewDescriptor' type group?: string; - remoteAuthority?: string; + remoteName?: string | string[]; } const viewDescriptor: IJSONSchema = { @@ -123,9 +123,12 @@ const remoteViewDescriptor: IJSONSchema = { description: localize('vscode.extension.contributes.view.group', 'Nested group in the viewlet'), type: 'string' }, - remoteAuthority: { - description: localize('vscode.extension.contributes.view.remoteAuthority', 'The remote authority associated with this view'), - type: 'string' + remoteName: { + description: localize('vscode.extension.contributes.view.remoteName', 'The name of the remote type associated with this view'), + type: ['string', 'array'], + items: { + type: 'string' + } } } }; @@ -363,7 +366,12 @@ class ViewsExtensionHandler implements IWorkbenchContribution { // Generate CSS to show the icon in the activity bar const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${cssClass}`; - createCSSRule(iconClass, `-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%; -webkit-mask-size: 24px;`); + createCSSRule(iconClass, ` + mask: ${asCSSUrl(icon)} no-repeat 50% 50%; + mask-size: 24px; + -webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%; + -webkit-mask-size: 24px;` + ); } return viewContainer; @@ -435,7 +443,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { extensionId: extension.description.identifier, originalContainerId: entry.key, group: item.group, - remoteAuthority: item.remoteAuthority + remoteAuthority: item.remoteName || (item).remoteAuthority // TODO@roblou - delete after remote extensions are updated }; viewIds.push(viewDescriptor.id); diff --git a/src/vs/workbench/api/common/apiCommands.ts b/src/vs/workbench/api/common/apiCommands.ts index 78a7febe888..01581c2c7c2 100644 --- a/src/vs/workbench/api/common/apiCommands.ts +++ b/src/vs/workbench/api/common/apiCommands.ts @@ -11,9 +11,8 @@ import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IWindowService, IOpenInWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/windows'; -import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; -import { IRecent } from 'vs/platform/history/common/history'; +import { IOpenWindowOptions, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWorkspacesService, hasWorkspaceFileExtension, IRecent } from 'vs/platform/workspaces/common/workspaces'; import { Schemas } from 'vs/base/common/network'; // ----------------------------------------------------------------- @@ -40,7 +39,7 @@ interface IOpenFolderAPICommandOptions { } export class OpenFolderAPICommand { - public static ID = 'vscode.openFolder'; + public static readonly ID = 'vscode.openFolder'; public static execute(executor: ICommandsExecutor, uri?: URI, forceNewWindow?: boolean): Promise; public static execute(executor: ICommandsExecutor, uri?: URI, options?: IOpenFolderAPICommandOptions): Promise; public static execute(executor: ICommandsExecutor, uri?: URI, arg: boolean | IOpenFolderAPICommandOptions = {}): Promise { @@ -50,7 +49,7 @@ export class OpenFolderAPICommand { if (!uri) { return executor.executeCommand('_files.pickFolderAndOpen', { forceNewWindow: arg.forceNewWindow }); } - const options: IOpenInWindowOptions = { forceNewWindow: arg.forceNewWindow, forceReuseWindow: arg.forceReuseWindow, noRecentEntry: arg.noRecentEntry }; + const options: IOpenWindowOptions = { forceNewWindow: arg.forceNewWindow, forceReuseWindow: arg.forceReuseWindow, noRecentEntry: arg.noRecentEntry }; uri = URI.revive(uri); const uriToOpen: IWindowOpenable = (hasWorkspaceFileExtension(uri) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri }; return executor.executeCommand('_files.windowOpen', [uriToOpen], options); @@ -74,12 +73,14 @@ interface INewWindowAPICommandOptions { } export class NewWindowAPICommand { - public static ID = 'vscode.newWindow'; + public static readonly ID = 'vscode.newWindow'; public static execute(executor: ICommandsExecutor, options?: INewWindowAPICommandOptions): Promise { - return executor.executeCommand('_files.newWindow', { - reuse: options && options.reuseWindow, + const commandOptions: IOpenEmptyWindowOptions = { + forceReuseWindow: options && options.reuseWindow, remoteAuthority: options && options.remoteAuthority - }); + }; + + return executor.executeCommand('_files.newWindow', commandOptions); } } CommandsRegistry.registerCommand({ @@ -93,7 +94,7 @@ CommandsRegistry.registerCommand({ }); export class DiffAPICommand { - public static ID = 'vscode.diff'; + public static readonly ID = 'vscode.diff'; public static execute(executor: ICommandsExecutor, left: URI, right: URI, label: string, options?: vscode.TextDocumentShowOptions): Promise { return executor.executeCommand('_workbench.diff', [ left, right, @@ -107,7 +108,7 @@ export class DiffAPICommand { CommandsRegistry.registerCommand(DiffAPICommand.ID, adjustHandler(DiffAPICommand.execute)); export class OpenAPICommand { - public static ID = 'vscode.open'; + public static readonly ID = 'vscode.open'; public static execute(executor: ICommandsExecutor, resource: URI, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, label?: string): Promise { let options: ITextEditorOptions | undefined; let position: EditorViewColumn | undefined; @@ -132,12 +133,12 @@ export class OpenAPICommand { CommandsRegistry.registerCommand(OpenAPICommand.ID, adjustHandler(OpenAPICommand.execute)); CommandsRegistry.registerCommand('_workbench.removeFromRecentlyOpened', function (accessor: ServicesAccessor, uri: URI) { - const windowService = accessor.get(IWindowService); - return windowService.removeFromRecentlyOpened([uri]); + const workspacesService = accessor.get(IWorkspacesService); + return workspacesService.removeFromRecentlyOpened([uri]); }); export class RemoveFromRecentlyOpenedAPICommand { - public static ID = 'vscode.removeFromRecentlyOpened'; + public static readonly ID = 'vscode.removeFromRecentlyOpened'; public static execute(executor: ICommandsExecutor, path: string | URI): Promise { if (typeof path === 'string') { path = path.match(/^[^:/?#]+:\/\//) ? URI.parse(path) : URI.file(path); @@ -150,7 +151,7 @@ export class RemoveFromRecentlyOpenedAPICommand { CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute)); export class OpenIssueReporter { - public static ID = 'vscode.openIssueReporter'; + public static readonly ID = 'vscode.openIssueReporter'; public static execute(executor: ICommandsExecutor, extensionId: string): Promise { return executor.executeCommand('workbench.action.openIssueReporter', [extensionId]); } @@ -163,7 +164,6 @@ interface RecentEntry { } CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async function (accessor: ServicesAccessor, recentEntry: RecentEntry) { - const windowService = accessor.get(IWindowService); const workspacesService = accessor.get(IWorkspacesService); let recent: IRecent | undefined = undefined; const uri = recentEntry.uri; @@ -176,16 +176,16 @@ CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async functio } else { recent = { fileUri: uri, label }; } - return windowService.addRecentlyOpened([recent]); + return workspacesService.addRecentlyOpened([recent]); }); CommandsRegistry.registerCommand('_workbench.getRecentlyOpened', async function (accessor: ServicesAccessor) { - const windowService = accessor.get(IWindowService); - return windowService.getRecentlyOpened(); + const workspacesService = accessor.get(IWorkspacesService); + return workspacesService.getRecentlyOpened(); }); export class SetEditorLayoutAPICommand { - public static ID = 'vscode.setEditorLayout'; + public static readonly ID = 'vscode.setEditorLayout'; public static execute(executor: ICommandsExecutor, layout: EditorGroupLayout): Promise { return executor.executeCommand('layoutEditorGroups', layout); } diff --git a/src/vs/workbench/api/common/configurationExtensionPoint.ts b/src/vs/workbench/api/common/configurationExtensionPoint.ts index 871ae0f28ff..65e5d6cf070 100644 --- a/src/vs/workbench/api/common/configurationExtensionPoint.ts +++ b/src/vs/workbench/api/common/configurationExtensionPoint.ts @@ -10,7 +10,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { IConfigurationNode, IConfigurationRegistry, Extensions, editorConfigurationSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; -import { workspaceSettingsSchemaId, launchSchemaId } from 'vs/workbench/services/configuration/common/configuration'; +import { workspaceSettingsSchemaId, launchSchemaId, tasksSchemaId } from 'vs/workbench/services/configuration/common/configuration'; import { isObject } from 'vs/base/common/types'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -296,6 +296,12 @@ jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', { description: nls.localize('workspaceConfig.launch.description', "Workspace launch configurations"), $ref: launchSchemaId }, + 'tasks': { + type: 'object', + default: { version: '2.0.0', tasks: [] }, + description: nls.localize('workspaceConfig.tasks.description', "Workspace task configurations"), + $ref: tasksSchemaId + }, 'extensions': { type: 'object', default: {}, diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index d8e9b0b82d1..ef9cea185a6 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -105,7 +105,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, accessor.get(IExtHostOutputService)); // manually create and register addressable instances - const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment)); + const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace)); const extHostUrls = rpcProtocol.set(ExtHostContext.ExtHostUrls, new ExtHostUrls(rpcProtocol)); const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors)); const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService)); @@ -228,7 +228,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I get uriScheme() { return initData.environment.appUriScheme; }, createAppUri(options?) { checkProposedApiEnabled(extension); - return extHostUrls.createAppUri(extension.identifier, options); + return extHostUrls.proposedCreateAppUri(extension.identifier, options); }, get logLevel() { checkProposedApiEnabled(extension); @@ -247,15 +247,17 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I openExternal(uri: URI) { return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote }); }, - resolveExternalUri(uri: URI) { - checkProposedApiEnabled(extension); - return extHostWindow.resolveExternalUri(uri, { allowTunneling: !!initData.remote.isRemote }); + asExternalUri(uri: URI) { + if (uri.scheme === initData.environment.appUriScheme) { + return extHostUrls.createAppUri(uri); + } + + return extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.isRemote }); }, get remoteName() { return getRemoteName(initData.remote.authority); }, get uiKind() { - checkProposedApiEnabled(extension); return initData.uiKind; } }; @@ -375,8 +377,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I registerSelectionRangeProvider(selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable { return extHostLanguageFeatures.registerSelectionRangeProvider(extension, selector, provider); }, - registerCallHierarchyProvider(selector: vscode.DocumentSelector, provider: vscode.CallHierarchyItemProvider): vscode.Disposable { - checkProposedApiEnabled(extension); + registerCallHierarchyProvider(selector: vscode.DocumentSelector, provider: vscode.CallHierarchyProvider): vscode.Disposable { return extHostLanguageFeatures.registerCallHierarchyProvider(extension, selector, provider); }, setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => { @@ -532,11 +533,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostTreeViews.createTreeView(viewId, options, extension); }, registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => { - return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer); + return extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializer); }, - registerWebviewEditorProvider: (viewType: string, provider: vscode.WebviewEditorProvider) => { + registerWebviewEditorProvider: (viewType: string, provider: vscode.WebviewEditorProvider, options?: vscode.WebviewPanelOptions) => { checkProposedApiEnabled(extension); - return extHostWebviews.registerWebviewEditorProvider(viewType, provider); + return extHostWebviews.registerWebviewEditorProvider(extension, viewType, provider, options); }, registerDecorationProvider(provider: vscode.DecorationProvider) { checkProposedApiEnabled(extension); @@ -634,7 +635,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const options = uriOrFileNameOrOptions as { language?: string; content?: string; }; if (typeof uriOrFileNameOrOptions === 'string') { uriPromise = Promise.resolve(URI.file(uriOrFileNameOrOptions)); - } else if (uriOrFileNameOrOptions instanceof URI) { + } else if (URI.isUri(uriOrFileNameOrOptions)) { uriPromise = Promise.resolve(uriOrFileNameOrOptions); } else if (!options || typeof options === 'object') { uriPromise = extHostDocuments.createDocumentData(options); @@ -698,11 +699,27 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension); return extHostLabelService.$registerResourceLabelFormatter(formatter); }, - onDidRenameFile: (listener: (e: vscode.FileRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => { + onDidCreateFiles: (listener, thisArg, disposables) => { + checkProposedApiEnabled(extension); + return extHostFileSystemEvent.onDidCreateFile(listener, thisArg, disposables); + }, + onDidDeleteFiles: (listener, thisArg, disposables) => { + checkProposedApiEnabled(extension); + return extHostFileSystemEvent.onDidDeleteFile(listener, thisArg, disposables); + }, + onDidRenameFiles: (listener, thisArg, disposables) => { checkProposedApiEnabled(extension); return extHostFileSystemEvent.onDidRenameFile(listener, thisArg, disposables); }, - onWillRenameFile: (listener: (e: vscode.FileWillRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => { + onWillCreateFiles: (listener: (e: vscode.FileWillCreateEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => { + checkProposedApiEnabled(extension); + return extHostFileSystemEvent.getOnWillCreateFileEvent(extension)(listener, thisArg, disposables); + }, + onWillDeleteFiles: (listener: (e: vscode.FileWillDeleteEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => { + checkProposedApiEnabled(extension); + return extHostFileSystemEvent.getOnWillDeleteFileEvent(extension)(listener, thisArg, disposables); + }, + onWillRenameFiles: (listener: (e: vscode.FileWillRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => { checkProposedApiEnabled(extension); return extHostFileSystemEvent.getOnWillRenameFileEvent(extension)(listener, thisArg, disposables); } @@ -851,7 +868,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I EndOfLine: extHostTypes.EndOfLine, EventEmitter: Emitter, ExtensionKind: extHostTypes.ExtensionKind, - CustomExecution2: extHostTypes.CustomExecution2, + CustomExecution: extHostTypes.CustomExecution, FileChangeType: extHostTypes.FileChangeType, FileSystemError: extHostTypes.FileSystemError, FileType: files.FileType, @@ -916,7 +933,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I CallHierarchyItem: extHostTypes.CallHierarchyItem, DebugConsoleMode: extHostTypes.DebugConsoleMode, Decoration: extHostTypes.Decoration, - WebviewEditorState: extHostTypes.WebviewEditorState, + WebviewContentState: extHostTypes.WebviewContentState, UIKind: UIKind }; }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 2aa49fe19ce..e8cb867835c 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -32,7 +32,7 @@ import { IMarkerData } from 'vs/platform/markers/common/markers'; import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress'; import * as quickInput from 'vs/platform/quickinput/common/quickInput'; import { RemoteAuthorityResolverErrorCode, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import * as statusbar from 'vs/platform/statusbar/common/statusbar'; +import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; @@ -131,12 +131,20 @@ export interface CommentProviderFeatures { reactionHandler?: boolean; } +export type CommentThreadChanges = Partial<{ + range: IRange, + label: string, + contextValue: string, + comments: modes.Comment[], + collapseState: modes.CommentThreadCollapsibleState +}>; + export interface MainThreadCommentsShape extends IDisposable { $registerCommentController(handle: number, id: string, label: string): void; $unregisterCommentController(handle: number): void; $updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void; $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, extensionId: ExtensionIdentifier): modes.CommentThread | undefined; - $updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, label: string | undefined, contextValue: string | undefined, comments: modes.Comment[], collapseState: modes.CommentThreadCollapsibleState): void; + $updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, changes: CommentThreadChanges): void; $deleteCommentThread(handle: number, commentThreadHandle: number): void; $onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent): void; } @@ -506,7 +514,7 @@ export interface MainThreadQuickOpenShape extends IDisposable { } export interface MainThreadStatusBarShape extends IDisposable { - $setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void; + $setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: string | undefined, color: string | ThemeColor | undefined, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void; $dispose(id: number): void; } @@ -541,22 +549,27 @@ export interface WebviewPanelShowOptions { readonly preserveFocus?: boolean; } +export interface WebviewExtensionDescription { + readonly id: ExtensionIdentifier; + readonly location: UriComponents; +} + export interface MainThreadWebviewsShape extends IDisposable { - $createWebviewPanel(handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: modes.IWebviewPanelOptions & modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): void; + $createWebviewPanel(extension: WebviewExtensionDescription, handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: modes.IWebviewPanelOptions & modes.IWebviewOptions): void; $disposeWebview(handle: WebviewPanelHandle): void; $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void; $setTitle(handle: WebviewPanelHandle, value: string): void; - $setState(handle: WebviewPanelHandle, state: modes.WebviewEditorState): void; $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void; $setHtml(handle: WebviewPanelHandle, value: string): void; $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void; + $postMessage(handle: WebviewPanelHandle, value: any): Promise; $registerSerializer(viewType: string): void; $unregisterSerializer(viewType: string): void; - $registerEditorProvider(viewType: string): void; + $registerEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions): void; $unregisterEditorProvider(viewType: string): void; } @@ -574,14 +587,14 @@ export interface ExtHostWebviewsShape { $onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void; $onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise; $deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise; - $resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise; - $save(handle: WebviewPanelHandle): Promise; + $resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise; } export interface MainThreadUrlsShape extends IDisposable { $registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise; $unregisterUriHandler(handle: number): Promise; - $createAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial }): Promise; + $createAppUri(uri: UriComponents): Promise; + $proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial }): Promise; } export interface ExtHostUrlsShape { @@ -745,7 +758,7 @@ export interface IOpenUriOptions { export interface MainThreadWindowShape extends IDisposable { $getWindowVisibility(): Promise; $openUri(uri: UriComponents, options: IOpenUriOptions): Promise; - $resolveExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; + $asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; } // -- extension host @@ -900,10 +913,11 @@ export interface FileSystemEvents { changed: UriComponents[]; deleted: UriComponents[]; } + export interface ExtHostFileSystemEventServiceShape { $onFileEvent(events: FileSystemEvents): void; - $onFileRename(oldUri: UriComponents, newUri: UriComponents): void; - $onWillRename(oldUri: UriComponents, newUri: UriComponents): Promise; + $onWillRunFileOperation(operation: files.FileOperation, target: UriComponents, source: UriComponents | undefined): Promise; + $onDidRunFileOperation(operation: files.FileOperation, target: UriComponents, source: UriComponents | undefined): void; } export interface ObjectIdentifier { @@ -938,28 +952,45 @@ export class IdObject { } } +export const enum ISuggestDataDtoField { + label = 'a', + kind = 'b', + detail = 'c', + documentation = 'd', + sortText = 'e', + filterText = 'f', + preselect = 'g', + insertText = 'h', + insertTextRules = 'i', + range = 'j', + commitCharacters = 'k', + additionalTextEdits = 'l', + command = 'm', + kindModifier = 'n', +} + export interface ISuggestDataDto { - a/* label */: string; - b/* kind */: modes.CompletionItemKind; - c/* detail */?: string; - d/* documentation */?: string | IMarkdownString; - e/* sortText */?: string; - f/* filterText */?: string; - g/* preselect */?: boolean; - h/* insertText */?: string; - i/* insertTextRules */?: modes.CompletionItemInsertTextRule; - j/* range */?: IRange; - k/* commitCharacters */?: string[]; - l/* additionalTextEdits */?: ISingleEditOperation[]; - m/* command */?: modes.Command; - n/* kindModifier */?: modes.CompletionItemTag[]; + [ISuggestDataDtoField.label]: string; + [ISuggestDataDtoField.kind]: modes.CompletionItemKind; + [ISuggestDataDtoField.detail]?: string; + [ISuggestDataDtoField.documentation]?: string | IMarkdownString; + [ISuggestDataDtoField.sortText]?: string; + [ISuggestDataDtoField.filterText]?: string; + [ISuggestDataDtoField.preselect]?: boolean; + [ISuggestDataDtoField.insertText]?: string; + [ISuggestDataDtoField.insertTextRules]?: modes.CompletionItemInsertTextRule; + [ISuggestDataDtoField.range]?: IRange | { insert: IRange, replace: IRange }; + [ISuggestDataDtoField.commitCharacters]?: string[]; + [ISuggestDataDtoField.additionalTextEdits]?: ISingleEditOperation[]; + [ISuggestDataDtoField.command]?: modes.Command; + [ISuggestDataDtoField.kindModifier]?: modes.CompletionItemTag[]; // not-standard x?: ChainedCacheId; } export interface ISuggestResultDto { x?: number; - a: IRange; + a: { insert: IRange, replace: IRange }; b: ISuggestDataDto[]; c?: boolean; } @@ -1082,6 +1113,7 @@ export interface ICodeLensDto { } export interface ICallHierarchyItemDto { + id: string; kind: modes.SymbolKind; name: string; detail?: string; @@ -1125,8 +1157,10 @@ export interface ExtHostLanguageFeaturesShape { $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise; $provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise; $provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise; - $provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>; - $provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>; + $prepareCallHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<{ sessionId: string, root: ICallHierarchyItemDto } | undefined>; + $provideCallHierarchyIncomingCalls(handle: number, itemId: string, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>; + $provideCallHierarchyOutgoingCalls(handle: number, itemId: string, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>; + $releaseCallHierarchy(handle: number, sessionId: string): void; } export interface ExtHostQuickOpenShape { @@ -1172,7 +1206,7 @@ export interface ExtHostTerminalServiceShape { $acceptTerminalTitleChange(id: number, name: string): void; $acceptTerminalDimensions(id: number, cols: number, rows: number): void; $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void; - $spawnExtHostProcess(id: number, shellLaunchConfig: IShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + $spawnExtHostProcess(id: number, shellLaunchConfig: IShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void; $acceptProcessInput(id: number, data: string): void; $acceptProcessResize(id: number, cols: number, rows: number): void; diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index e9022a259d5..e0ae9e2f5f9 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -4,11 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import * as vscode from 'vscode'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as types from 'vs/workbench/api/common/extHostTypes'; -import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto } from 'vs/workbench/api/common/extHost.protocol'; +import { IRawColorInfo, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol'; import { ISingleEditOperation } from 'vs/editor/common/model'; import * as modes from 'vs/editor/common/modes'; import * as search from 'vs/workbench/contrib/search/common/search'; @@ -27,7 +27,7 @@ export class ExtHostApiCommands { } private _commands: ExtHostCommands; - private _disposables: IDisposable[] = []; + private readonly _disposables = new DisposableStore(); private constructor(commands: ExtHostCommands) { this._commands = commands; @@ -182,22 +182,6 @@ export class ExtHostApiCommands { ], returns: 'A promise that resolves to an array of DocumentLink-instances.' }); - this._register('vscode.executeCallHierarchyProviderIncomingCalls', this._executeCallHierarchyIncomingCallsProvider, { - description: 'Execute call hierarchy provider for incoming calls', - args: [ - { name: 'uri', description: 'Uri of a text document', constraint: URI }, - { name: 'position', description: 'Position in a text document', constraint: types.Position }, - ], - returns: 'A promise that resolves to an array of CallHierarchyIncomingCall-instances.' - }); - this._register('vscode.executeCallHierarchyProviderOutgoingCalls', this._executeCallHierarchyOutgoingCallsProvider, { - description: 'Execute call hierarchy provider for outgoing calls', - args: [ - { name: 'uri', description: 'Uri of a text document', constraint: URI }, - { name: 'position', description: 'Position in a text document', constraint: types.Position }, - ], - returns: 'A promise that resolves to an array of CallHierarchyOutgoingCall-instances.' - }); this._register('vscode.executeDocumentColorProvider', this._executeDocumentColorProvider, { description: 'Execute document color provider.', args: [ @@ -239,7 +223,7 @@ export class ExtHostApiCommands { this._register(OpenFolderAPICommand.ID, adjustHandler(OpenFolderAPICommand.execute), { description: 'Open a folder or workspace in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder/workspace unless the newWindow parameter is set to true.', args: [ - { name: 'uri', description: '(optional) Uri of the folder or workspace file to open. If not provided, a native dialog will ask the user for the folder', constraint: (value: any) => value === undefined || value instanceof URI }, + { name: 'uri', description: '(optional) Uri of the folder or workspace file to open. If not provided, a native dialog will ask the user for the folder', constraint: (value: any) => value === undefined || URI.isUri(value) }, { name: 'options', description: '(optional) Options. Object with the following properties: `forceNewWindow `: Whether to open the folder/workspace in a new window or the same. Defaults to opening in the same window. `noRecentEntry`: Whether the opened URI will appear in the \'Open Recent\' list. Defaults to true. Note, for backward compatibility, options can also be of type boolean, representing the `forceNewWindow` setting.', constraint: (value: any) => value === undefined || typeof value === 'object' || typeof value === 'boolean' } ] }); @@ -288,7 +272,7 @@ export class ExtHostApiCommands { private _register(id: string, handler: (...args: any[]) => any, description?: ICommandHandlerDescription): void { const disposable = this._commands.registerCommand(false, id, handler, this, description); - this._disposables.push(disposable); + this._disposables.add(disposable); } /** @@ -573,36 +557,6 @@ export class ExtHostApiCommands { return this._commands.executeCommand('_executeLinkProvider', resource) .then(tryMapWith(typeConverters.DocumentLink.to)); } - - private async _executeCallHierarchyIncomingCallsProvider(resource: URI, position: types.Position): Promise { - type IncomingCallDto = { - source: ICallHierarchyItemDto; - sourceRanges: IRange[]; - }; - const args = { resource, position: typeConverters.Position.from(position) }; - const calls = await this._commands.executeCommand('_executeCallHierarchyIncomingCalls', args); - - const result: vscode.CallHierarchyIncomingCall[] = []; - for (const call of calls) { - result.push(new types.CallHierarchyIncomingCall(typeConverters.CallHierarchyItem.to(call.source), call.sourceRanges.map(typeConverters.Range.to))); - } - return result; - } - - private async _executeCallHierarchyOutgoingCallsProvider(resource: URI, position: types.Position): Promise { - type OutgoingCallDto = { - sourceRanges: IRange[]; - target: ICallHierarchyItemDto; - }; - const args = { resource, position: typeConverters.Position.from(position) }; - const calls = await this._commands.executeCommand('_executeCallHierarchyOutgoingCalls', args); - - const result: vscode.CallHierarchyOutgoingCall[] = []; - for (const call of calls) { - result.push(new types.CallHierarchyOutgoingCall(typeConverters.CallHierarchyItem.to(call.target), call.sourceRanges.map(typeConverters.Range.to))); - } - return result; - } } function tryMapWith(f: (x: T) => R) { diff --git a/src/vs/workbench/api/common/extHostComments.ts b/src/vs/workbench/api/common/extHostComments.ts index 5fac49d7eda..20e85761638 100644 --- a/src/vs/workbench/api/common/extHostComments.ts +++ b/src/vs/workbench/api/common/extHostComments.ts @@ -16,7 +16,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters'; import * as types from 'vs/workbench/api/common/extHostTypes'; import * as vscode from 'vscode'; -import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape } from './extHost.protocol'; +import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape, CommentThreadChanges } from './extHost.protocol'; import { ExtHostCommands } from './extHostCommands'; type ProviderHandle = number; @@ -213,12 +213,21 @@ export class ExtHostComments implements ExtHostCommentsShape, IDisposable { } } +type CommentThreadModification = Partial<{ + range: vscode.Range, + label: string | undefined, + contextValue: string | undefined, + comments: vscode.Comment[], + collapsibleState: vscode.CommentThreadCollapsibleState +}>; export class ExtHostCommentThread implements vscode.CommentThread { private static _handlePool: number = 0; readonly handle = ExtHostCommentThread._handlePool++; public commentHandle: number = 0; + private modifications: CommentThreadModification = Object.create(null); + set threadId(id: string) { this._id = id; } @@ -245,6 +254,7 @@ export class ExtHostCommentThread implements vscode.CommentThread { set range(range: vscode.Range) { if (!range.isEqual(this._range)) { this._range = range; + this.modifications.range = range; this._onDidUpdateCommentThread.fire(); } } @@ -261,6 +271,7 @@ export class ExtHostCommentThread implements vscode.CommentThread { set label(label: string | undefined) { this._label = label; + this.modifications.label = label; this._onDidUpdateCommentThread.fire(); } @@ -272,6 +283,7 @@ export class ExtHostCommentThread implements vscode.CommentThread { set contextValue(context: string | undefined) { this._contextValue = context; + this.modifications.contextValue = context; this._onDidUpdateCommentThread.fire(); } @@ -281,6 +293,7 @@ export class ExtHostCommentThread implements vscode.CommentThread { set comments(newComments: vscode.Comment[]) { this._comments = newComments; + this.modifications.comments = newComments; this._onDidUpdateCommentThread.fire(); } @@ -292,6 +305,7 @@ export class ExtHostCommentThread implements vscode.CommentThread { set collapsibleState(newState: vscode.CommentThreadCollapsibleState) { this._collapseState = newState; + this.modifications.collapsibleState = newState; this._onDidUpdateCommentThread.fire(); } @@ -353,22 +367,34 @@ export class ExtHostCommentThread implements vscode.CommentThread { this._acceptInputDisposables.value = new DisposableStore(); } - const commentThreadRange = extHostTypeConverter.Range.from(this._range); - const label = this.label; - const contextValue = this.contextValue; - const comments = this._comments.map(cmt => { return convertToModeComment(this, this._commentController, cmt, this._commentsMap); }); - const collapsibleState = convertToCollapsibleState(this._collapseState); + const modified = (value: keyof CommentThreadModification): boolean => + Object.prototype.hasOwnProperty.call(this.modifications, value); + + const formattedModifications: CommentThreadChanges = {}; + if (modified('range')) { + formattedModifications.range = extHostTypeConverter.Range.from(this._range); + } + if (modified('label')) { + formattedModifications.label = this.label; + } + if (modified('contextValue')) { + formattedModifications.contextValue = this.contextValue; + } + if (modified('comments')) { + formattedModifications.comments = + this._comments.map(cmt => convertToModeComment(this, this._commentController, cmt, this._commentsMap)); + } + if (modified('collapsibleState')) { + formattedModifications.collapseState = convertToCollapsibleState(this._collapseState); + } + this.modifications = {}; this._proxy.$updateCommentThread( this._commentController.handle, this.handle, this._id!, this._uri, - commentThreadRange, - label, - contextValue, - comments, - collapsibleState + formattedModifications ); } diff --git a/src/vs/workbench/api/common/extHostDiagnostics.ts b/src/vs/workbench/api/common/extHostDiagnostics.ts index d654408346b..1455bb030d8 100644 --- a/src/vs/workbench/api/common/extHostDiagnostics.ts +++ b/src/vs/workbench/api/common/extHostDiagnostics.ts @@ -64,7 +64,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { this._checkDisposed(); let toSync: vscode.Uri[] = []; - if (first instanceof URI) { + if (URI.isUri(first)) { if (!diagnostics) { // remove this entry diff --git a/src/vs/workbench/api/common/extHostDocumentData.ts b/src/vs/workbench/api/common/extHostDocumentData.ts index b44527a2b51..3a166503923 100644 --- a/src/vs/workbench/api/common/extHostDocumentData.ts +++ b/src/vs/workbench/api/common/extHostDocumentData.ts @@ -12,6 +12,7 @@ import { ensureValidWordDefinition, getWordAtText } from 'vs/editor/common/model import { MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol'; import { EndOfLine, Position, Range } from 'vs/workbench/api/common/extHostTypes'; import * as vscode from 'vscode'; +import { equals } from 'vs/base/common/arrays'; const _modeId2WordDefinition = new Map(); export function setWordDefinitionFor(modeId: string, wordDefinition: RegExp | undefined): void { @@ -48,17 +49,8 @@ export class ExtHostDocumentData extends MirrorTextModel { this._isDirty = false; } - equalLines(lines: string[]): boolean { - const len = lines.length; - if (len !== this._lines.length) { - return false; - } - for (let i = 0; i < len; i++) { - if (lines[i] !== this._lines[i]) { - return false; - } - } - return true; + equalLines(lines: readonly string[]): boolean { + return equals(this._lines, lines); } get document(): vscode.TextDocument { diff --git a/src/vs/workbench/api/common/extHostDocuments.ts b/src/vs/workbench/api/common/extHostDocuments.ts index ea9e189ce51..60a0e162e36 100644 --- a/src/vs/workbench/api/common/extHostDocuments.ts +++ b/src/vs/workbench/api/common/extHostDocuments.ts @@ -12,6 +12,7 @@ import { ExtHostDocumentData, setWordDefinitionFor } from 'vs/workbench/api/comm import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as vscode from 'vscode'; +import { assertIsDefined } from 'vs/base/common/types'; export class ExtHostDocuments implements ExtHostDocumentsShape { @@ -84,7 +85,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape { if (!promise) { promise = this._proxy.$tryOpenDocument(uri).then(() => { this._documentLoader.delete(uri.toString()); - return this._documentsAndEditors.getDocument(uri); + return assertIsDefined(this._documentsAndEditors.getDocument(uri)); }, err => { this._documentLoader.delete(uri.toString()); return Promise.reject(err); diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index 9e6734e8e3a..b5ce835e074 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -327,6 +327,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio } this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`); + this._logService.flush(); const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup); return Promise.all([ diff --git a/src/vs/workbench/api/common/extHostFileSystemEventService.ts b/src/vs/workbench/api/common/extHostFileSystemEventService.ts index 8658c24bb14..a290fb0cc0f 100644 --- a/src/vs/workbench/api/common/extHostFileSystemEventService.ts +++ b/src/vs/workbench/api/common/extHostFileSystemEventService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { flatten } from 'vs/base/common/arrays'; -import { AsyncEmitter, Emitter, Event } from 'vs/base/common/event'; +import { AsyncEmitter, Emitter, Event, IWaitUntil } from 'vs/base/common/event'; import { IRelativePattern, parse } from 'vs/base/common/glob'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; @@ -13,6 +13,7 @@ import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, Mai import * as typeConverter from './extHostTypeConverters'; import { Disposable, WorkspaceEdit } from './extHostTypes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { FileOperation } from 'vs/platform/files/common/files'; class FileSystemWatcher implements vscode.FileSystemWatcher { @@ -96,18 +97,26 @@ class FileSystemWatcher implements vscode.FileSystemWatcher { } } -interface WillRenameListener { +interface IExtensionListener { extension: IExtensionDescription; - (e: vscode.FileWillRenameEvent): any; + (e: E): any; } export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServiceShape { - private readonly _onFileEvent = new Emitter(); + private readonly _onFileSystemEvent = new Emitter(); + private readonly _onDidRenameFile = new Emitter(); + private readonly _onDidCreateFile = new Emitter(); + private readonly _onDidDeleteFile = new Emitter(); private readonly _onWillRenameFile = new AsyncEmitter(); + private readonly _onWillCreateFile = new AsyncEmitter(); + private readonly _onWillDeleteFile = new AsyncEmitter(); readonly onDidRenameFile: Event = this._onDidRenameFile.event; + readonly onDidCreateFile: Event = this._onDidCreateFile.event; + readonly onDidDeleteFile: Event = this._onDidDeleteFile.event; + constructor( mainContext: IMainContext, @@ -117,37 +126,78 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ // } - public createFileSystemWatcher(globPattern: string | IRelativePattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): vscode.FileSystemWatcher { - return new FileSystemWatcher(this._onFileEvent.event, globPattern, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents); + //--- file events + + createFileSystemWatcher(globPattern: string | IRelativePattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): vscode.FileSystemWatcher { + return new FileSystemWatcher(this._onFileSystemEvent.event, globPattern, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents); } $onFileEvent(events: FileSystemEvents) { - this._onFileEvent.fire(events); + this._onFileSystemEvent.fire(events); } - $onFileRename(oldUri: UriComponents, newUri: UriComponents) { - this._onDidRenameFile.fire(Object.freeze({ oldUri: URI.revive(oldUri), newUri: URI.revive(newUri) })); + + //--- file operations + + $onDidRunFileOperation(operation: FileOperation, target: UriComponents, source: UriComponents | undefined): void { + switch (operation) { + case FileOperation.MOVE: + this._onDidRenameFile.fire(Object.freeze({ renamed: [{ oldUri: URI.revive(source!), newUri: URI.revive(target) }] })); + break; + case FileOperation.DELETE: + this._onDidDeleteFile.fire(Object.freeze({ deleted: [URI.revive(target)] })); + break; + case FileOperation.CREATE: + this._onDidCreateFile.fire(Object.freeze({ created: [URI.revive(target)] })); + break; + default: + //ignore, dont send + } } + getOnWillRenameFileEvent(extension: IExtensionDescription): Event { + return this._createWillExecuteEvent(extension, this._onWillRenameFile); + } + + getOnWillCreateFileEvent(extension: IExtensionDescription): Event { + return this._createWillExecuteEvent(extension, this._onWillCreateFile); + } + + getOnWillDeleteFileEvent(extension: IExtensionDescription): Event { + return this._createWillExecuteEvent(extension, this._onWillDeleteFile); + } + + private _createWillExecuteEvent(extension: IExtensionDescription, emitter: AsyncEmitter): Event { return (listener, thisArg, disposables) => { - const wrappedListener: WillRenameListener = ((e: vscode.FileWillRenameEvent) => { - listener.call(thisArg, e); - }); + const wrappedListener: IExtensionListener = function wrapped(e: E) { listener.call(thisArg, e); }; wrappedListener.extension = extension; - return this._onWillRenameFile.event(wrappedListener, undefined, disposables); + return emitter.event(wrappedListener, undefined, disposables); }; } - $onWillRename(oldUriDto: UriComponents, newUriDto: UriComponents): Promise { - const oldUri = URI.revive(oldUriDto); - const newUri = URI.revive(newUriDto); + async $onWillRunFileOperation(operation: FileOperation, target: UriComponents, source: UriComponents | undefined): Promise { + switch (operation) { + case FileOperation.MOVE: + await this._fireWillRename(URI.revive(source!), URI.revive(target)); + break; + case FileOperation.DELETE: + this._onWillDeleteFile.fireAsync(thenables => ({ deleting: [URI.revive(target)], waitUntil: p => thenables.push(Promise.resolve(p)) })); + break; + case FileOperation.CREATE: + this._onWillCreateFile.fireAsync(thenables => ({ creating: [URI.revive(target)], waitUntil: p => thenables.push(Promise.resolve(p)) })); + break; + default: + //ignore, dont send + } + } + + private async _fireWillRename(oldUri: URI, newUri: URI): Promise { const edits: WorkspaceEdit[] = []; - return Promise.resolve(this._onWillRenameFile.fireAsync((bucket, _listener) => { + await Promise.resolve(this._onWillRenameFile.fireAsync(bucket => { return { - oldUri, - newUri, + renaming: [{ oldUri, newUri }], waitUntil: (thenable: Promise): void => { if (Object.isFrozen(bucket)) { throw new TypeError('waitUntil cannot be called async'); @@ -163,20 +213,23 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ bucket.push(wrappedThenable); } }; - }).then((): any => { - if (edits.length === 0) { - return undefined; - } - // flatten all WorkspaceEdits collected via waitUntil-call - // and apply them in one go. - const allEdits = new Array>(); - for (let edit of edits) { - if (edit) { // sparse array - let { edits } = typeConverter.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors); - allEdits.push(edits); - } - } - return this._mainThreadTextEditors.$tryApplyWorkspaceEdit({ edits: flatten(allEdits) }); })); + + if (edits.length === 0) { + return undefined; + } + + // flatten all WorkspaceEdits collected via waitUntil-call + // and apply them in one go. + const allEdits = new Array>(); + for (let edit of edits) { + if (edit) { // sparse array + let { edits } = typeConverter.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors); + allEdits.push(edits); + } + } + return this._mainThreadTextEditors.$tryApplyWorkspaceEdit({ edits: flatten(allEdits) }); } + + } diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 5143e8c9435..9d0780b5de0 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -350,7 +350,7 @@ class CodeActionAdapter { only: context.only ? new CodeActionKind(context.only) : undefined }; - return asPromise(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then(commandsOrActions => { + return asPromise(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then((commandsOrActions): extHostProtocol.ICodeActionListDto | undefined => { if (!isNonEmptyArray(commandsOrActions) || token.isCancellationRequested) { return undefined; } @@ -392,7 +392,7 @@ class CodeActionAdapter { } } - return { cacheId, actions }; + return { cacheId, actions }; }); } @@ -473,8 +473,8 @@ class OnTypeFormattingAdapter { class NavigateTypeAdapter { - private readonly _symbolCache: { [id: number]: vscode.SymbolInformation } = Object.create(null); - private readonly _resultCache: { [id: number]: [number, number] } = Object.create(null); + private readonly _symbolCache = new Map(); + private readonly _resultCache = new Map(); private readonly _provider: vscode.WorkspaceSymbolProvider; constructor(provider: vscode.WorkspaceSymbolProvider) { @@ -495,40 +495,38 @@ class NavigateTypeAdapter { continue; } const symbol = extHostProtocol.IdObject.mixin(typeConvert.WorkspaceSymbol.from(item)); - this._symbolCache[symbol._id!] = item; + this._symbolCache.set(symbol._id!, item); result.symbols.push(symbol); } } }).then(() => { if (result.symbols.length > 0) { - this._resultCache[result._id!] = [result.symbols[0]._id!, result.symbols[result.symbols.length - 1]._id!]; + this._resultCache.set(result._id!, [result.symbols[0]._id!, result.symbols[result.symbols.length - 1]._id!]); } return result; }); } - resolveWorkspaceSymbol(symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise { - + async resolveWorkspaceSymbol(symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise { if (typeof this._provider.resolveWorkspaceSymbol !== 'function') { - return Promise.resolve(symbol); + return symbol; } - const item = this._symbolCache[symbol._id!]; + const item = this._symbolCache.get(symbol._id!); if (item) { - return asPromise(() => this._provider.resolveWorkspaceSymbol!(item, token)).then(value => { - return value && mixin(symbol, typeConvert.WorkspaceSymbol.from(value), true); - }); + const value = await asPromise(() => this._provider.resolveWorkspaceSymbol!(item, token)); + return value && mixin(symbol, typeConvert.WorkspaceSymbol.from(value), true); } - return Promise.resolve(undefined); + return undefined; } releaseWorkspaceSymbols(id: number): any { - const range = this._resultCache[id]; + const range = this._resultCache.get(id); if (range) { for (let [from, to] = range; from <= to; from++) { - delete this._symbolCache[from]; + this._symbolCache.delete(from); } - delete this._resultCache[id]; + this._resultCache.delete(id); } } } @@ -729,6 +727,12 @@ class SuggestAdapter { const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); + // The default insert/replace ranges. It's important to compute them + // before asynchronously asking the provider for its results. See + // https://github.com/microsoft/vscode/issues/83400#issuecomment-546851421 + const replaceRange = doc.getWordRangeAtPosition(pos) || new Range(pos, pos); + const insertRange = replaceRange.with({ end: pos }); + return asPromise(() => this._provider.provideCompletionItems(doc, pos, token, typeConvert.CompletionContext.to(context))).then(value => { if (!value) { @@ -749,14 +753,10 @@ class SuggestAdapter { const disposables = new DisposableStore(); this._disposables.set(pid, disposables); - // the default text edit range - const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos)) - .with({ end: pos }); - const result: extHostProtocol.ISuggestResultDto = { x: pid, b: [], - a: typeConvert.Range.from(wordRangeBeforePos), + a: { replace: typeConvert.Range.from(replaceRange), insert: typeConvert.Range.from(insertRange) }, c: list.isIncomplete || undefined }; @@ -816,48 +816,73 @@ class SuggestAdapter { // x: id, // - a: item.label, - b: typeConvert.CompletionItemKind.from(item.kind), - n: item.tags && item.tags.map(typeConvert.CompletionItemTag.from), - c: item.detail, - d: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation), - e: item.sortText, - f: item.filterText, - g: item.preselect, - i: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0, - k: item.commitCharacters, - l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), - m: this._commands.toInternal(item.command, disposables), + [extHostProtocol.ISuggestDataDtoField.label]: item.label, + [extHostProtocol.ISuggestDataDtoField.kind]: typeConvert.CompletionItemKind.from(item.kind), + [extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from), + [extHostProtocol.ISuggestDataDtoField.detail]: item.detail, + [extHostProtocol.ISuggestDataDtoField.documentation]: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation), + [extHostProtocol.ISuggestDataDtoField.sortText]: item.sortText, + [extHostProtocol.ISuggestDataDtoField.filterText]: item.filterText, + [extHostProtocol.ISuggestDataDtoField.preselect]: item.preselect, + [extHostProtocol.ISuggestDataDtoField.insertTextRules]: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0, + [extHostProtocol.ISuggestDataDtoField.commitCharacters]: item.commitCharacters, + [extHostProtocol.ISuggestDataDtoField.additionalTextEdits]: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), + [extHostProtocol.ISuggestDataDtoField.command]: this._commands.toInternal(item.command, disposables), }; // 'insertText'-logic if (item.textEdit) { - result.h = item.textEdit.newText; + result[extHostProtocol.ISuggestDataDtoField.insertText] = item.textEdit.newText; } else if (typeof item.insertText === 'string') { - result.h = item.insertText; + result[extHostProtocol.ISuggestDataDtoField.insertText] = item.insertText; } else if (item.insertText instanceof SnippetString) { - result.h = item.insertText.value; - result.i! |= modes.CompletionItemInsertTextRule.InsertAsSnippet; + result[extHostProtocol.ISuggestDataDtoField.insertText] = item.insertText.value; + result[extHostProtocol.ISuggestDataDtoField.insertTextRules]! |= modes.CompletionItemInsertTextRule.InsertAsSnippet; } // 'overwrite[Before|After]'-logic - let range: vscode.Range | undefined; + let range: vscode.Range | { inserting: vscode.Range, replacing: vscode.Range } | undefined; if (item.textEdit) { range = item.textEdit.range; } else if (item.range) { range = item.range; + } else if (item.range2) { + range = item.range2; } - result.j = typeConvert.Range.from(range); - if (range && (!range.isSingleLine || range.start.line !== position.line)) { - console.warn('INVALID text edit -> must be single line and on the same line'); - return undefined; + if (range) { + if (Range.isRange(range)) { + if (!SuggestAdapter._isValidRangeForCompletion(range, position)) { + console.trace('INVALID range -> must be single line and on the same line'); + return undefined; + } + result[extHostProtocol.ISuggestDataDtoField.range] = typeConvert.Range.from(range); + + } else { + if ( + !SuggestAdapter._isValidRangeForCompletion(range.inserting, position) + || !SuggestAdapter._isValidRangeForCompletion(range.replacing, position) + || !range.inserting.start.isEqual(range.replacing.start) + || !range.replacing.contains(range.inserting) + ) { + console.trace('INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range'); + return undefined; + } + result[extHostProtocol.ISuggestDataDtoField.range] = { + insert: typeConvert.Range.from(range.inserting), + replace: typeConvert.Range.from(range.replacing) + }; + } } return result; } + + private static _isValidRangeForCompletion(range: vscode.Range, position: vscode.Position): boolean { + return range.isSingleLine || range.start.line === position.line; + } } @@ -1102,29 +1127,78 @@ class SelectionRangeAdapter { class CallHierarchyAdapter { + private _idPool: number = 0; + private readonly _cache = new Map(); + constructor( private readonly _documents: ExtHostDocuments, - private readonly _provider: vscode.CallHierarchyItemProvider + private readonly _provider: vscode.CallHierarchyProvider ) { } - async provideCallsTo(uri: URI, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + async prepareSession(uri: URI, position: IPosition, token: CancellationToken): Promise<{ sessionId: string, root: extHostProtocol.ICallHierarchyItemDto } | undefined> { const doc = this._documents.getDocument(uri); const pos = typeConvert.Position.to(position); - const calls = await this._provider.provideCallHierarchyIncomingCalls(doc, pos, token); - if (!calls) { + + const item = await this._provider.prepareCallHierarchy(doc, pos, token); + if (!item) { return undefined; } - return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[typeConvert.CallHierarchyItem.from(call.source), call.sourceRanges.map(typeConvert.Range.from)])); + const sessionId = String.fromCharCode(this._idPool++); + this._cache.set(sessionId, []); + return { sessionId, root: this._cacheAndConvertItem(sessionId, item) }; } - async provideCallsFrom(uri: URI, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { - const doc = this._documents.getDocument(uri); - const pos = typeConvert.Position.to(position); - const calls = await this._provider.provideCallHierarchyOutgoingCalls(doc, pos, token); + async provideCallsTo(itemId: string, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + const item = this._itemFromCache(itemId); + if (!item) { + throw new Error('missing call hierarchy item'); + } + const calls = await this._provider.provideCallHierarchyIncomingCalls(item, token); if (!calls) { return undefined; } - return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[typeConvert.CallHierarchyItem.from(call.target), call.sourceRanges.map(typeConvert.Range.from)])); + return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[this._cacheAndConvertItem(itemId, call.from), call.fromRanges.map(typeConvert.Range.from)])); + } + + async provideCallsFrom(itemId: string, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + const item = this._itemFromCache(itemId); + if (!item) { + throw new Error('missing call hierarchy item'); + } + const calls = await this._provider.provideCallHierarchyOutgoingCalls(item, token); + if (!calls) { + return undefined; + } + return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[this._cacheAndConvertItem(itemId, call.to), call.fromRanges.map(typeConvert.Range.from)])); + } + + releaseSession(sessionId: string): void { + this._cache.delete(sessionId.charAt(0)); + } + + private _cacheAndConvertItem(itemOrSessionId: string, item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto { + const sessionId = itemOrSessionId.charAt(0); + const array = this._cache.get(sessionId)!; + const dto: extHostProtocol.ICallHierarchyItemDto = { + id: sessionId + String.fromCharCode(array.length), + name: item.name, + detail: item.detail, + kind: typeConvert.SymbolKind.from(item.kind), + uri: item.uri, + range: typeConvert.Range.from(item.range), + selectionRange: typeConvert.Range.from(item.selectionRange), + }; + array.push(item); + return dto; + } + + private _itemFromCache(itemId: string): vscode.CallHierarchyItem | undefined { + const sessionId = itemId.charAt(0); + const array = this._cache.get(sessionId); + if (!array) { + return undefined; + } + return array[itemId.charCodeAt(1)]; } } @@ -1570,18 +1644,26 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- call hierarchy - registerCallHierarchyProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CallHierarchyItemProvider): vscode.Disposable { + registerCallHierarchyProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CallHierarchyProvider): vscode.Disposable { const handle = this._addNewAdapter(new CallHierarchyAdapter(this._documents, provider), extension); this._proxy.$registerCallHierarchyProvider(handle, this._transformDocumentSelector(selector)); return this._createDisposable(handle); } - $provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { - return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsTo(URI.revive(resource), position, token), undefined); + $prepareCallHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<{ sessionId: string, root: extHostProtocol.ICallHierarchyItemDto } | undefined> { + return this._withAdapter(handle, CallHierarchyAdapter, adapter => Promise.resolve(adapter.prepareSession(URI.revive(resource), position, token)), undefined); } - $provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { - return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsFrom(URI.revive(resource), position, token), undefined); + $provideCallHierarchyIncomingCalls(handle: number, itemId: string, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsTo(itemId, token), undefined); + } + + $provideCallHierarchyOutgoingCalls(handle: number, itemId: string, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> { + return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsFrom(itemId, token), undefined); + } + + $releaseCallHierarchy(handle: number, sessionId: string): void { + this._withAdapter(handle, CallHierarchyAdapter, adapter => Promise.resolve(adapter.releaseSession(sessionId)), undefined); } // --- configuration diff --git a/src/vs/workbench/api/common/extHostQuickOpen.ts b/src/vs/workbench/api/common/extHostQuickOpen.ts index 3d790f26276..65f94310001 100644 --- a/src/vs/workbench/api/common/extHostQuickOpen.ts +++ b/src/vs/workbench/api/common/extHostQuickOpen.ts @@ -234,16 +234,16 @@ class ExtHostQuickInput implements QuickInput { private static _nextId = 1; _id = ExtHostQuickPick._nextId++; - private _title: string; - private _steps: number; - private _totalSteps: number; + private _title: string | undefined; + private _steps: number | undefined; + private _totalSteps: number | undefined; private _visible = false; private _expectingHide = false; private _enabled = true; private _busy = false; private _ignoreFocusOut = true; private _value = ''; - private _placeholder: string; + private _placeholder: string | undefined; private _buttons: QuickInputButton[] = []; private _handlesToButtons = new Map(); private readonly _onDidAcceptEmitter = new Emitter(); @@ -268,7 +268,7 @@ class ExtHostQuickInput implements QuickInput { return this._title; } - set title(title: string) { + set title(title: string | undefined) { this._title = title; this.update({ title }); } @@ -277,7 +277,7 @@ class ExtHostQuickInput implements QuickInput { return this._steps; } - set step(step: number) { + set step(step: number | undefined) { this._steps = step; this.update({ step }); } @@ -286,7 +286,7 @@ class ExtHostQuickInput implements QuickInput { return this._totalSteps; } - set totalSteps(totalSteps: number) { + set totalSteps(totalSteps: number | undefined) { this._totalSteps = totalSteps; this.update({ totalSteps }); } @@ -331,7 +331,7 @@ class ExtHostQuickInput implements QuickInput { return this._placeholder; } - set placeholder(placeholder: string) { + set placeholder(placeholder: string | undefined) { this._placeholder = placeholder; this.update({ placeholder }); } @@ -398,7 +398,7 @@ class ExtHostQuickInput implements QuickInput { } } - public dispose(): void { + dispose(): void { if (this._disposed) { return; } @@ -455,7 +455,7 @@ function getIconUris(iconPath: QuickInputButton['iconPath']): { dark: URI, light function getLightIconUri(iconPath: QuickInputButton['iconPath']) { if (iconPath && !(iconPath instanceof ThemeIcon)) { if (typeof iconPath === 'string' - || iconPath instanceof URI) { + || URI.isUri(iconPath)) { return getIconUri(iconPath); } return getIconUri((iconPath as any).light); @@ -471,7 +471,7 @@ function getDarkIconUri(iconPath: QuickInputButton['iconPath']) { } function getIconUri(iconPath: string | URI) { - if (iconPath instanceof URI) { + if (URI.isUri(iconPath)) { return iconPath; } return URI.file(iconPath); @@ -587,9 +587,9 @@ class ExtHostQuickPick extends ExtHostQuickInput implem class ExtHostInputBox extends ExtHostQuickInput implements InputBox { - private _password: boolean; - private _prompt: string; - private _validationMessage: string; + private _password = false; + private _prompt: string | undefined; + private _validationMessage: string | undefined; constructor(proxy: MainThreadQuickOpenShape, extensionId: ExtensionIdentifier, onDispose: () => void) { super(proxy, extensionId, onDispose); @@ -609,7 +609,7 @@ class ExtHostInputBox extends ExtHostQuickInput implements InputBox { return this._prompt; } - set prompt(prompt: string) { + set prompt(prompt: string | undefined) { this._prompt = prompt; this.update({ prompt }); } @@ -618,7 +618,7 @@ class ExtHostInputBox extends ExtHostQuickInput implements InputBox { return this._validationMessage; } - set validationMessage(validationMessage: string) { + set validationMessage(validationMessage: string | undefined) { this._validationMessage = validationMessage; this.update({ validationMessage }); } diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index 9e4cdb09361..158239df616 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -57,7 +57,7 @@ export abstract class RequireInterceptor { this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider)); this.register(this._instaService.createInstance(KeytarNodeModuleFactory)); if (this._initData.remote.isRemote) { - this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths)); + this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths, this._initData.environment.appUriScheme)); } } @@ -228,6 +228,7 @@ class OpenNodeModuleFactory implements INodeModuleFactory { constructor( private readonly _extensionPaths: TernarySearchTree, + private readonly _appUriScheme: string, @IExtHostRpcService rpcService: IExtHostRpcService, ) { @@ -242,7 +243,7 @@ class OpenNodeModuleFactory implements INodeModuleFactory { } if (uri.scheme === 'http' || uri.scheme === 'https') { return mainThreadWindow.$openUri(uri, { allowTunneling: true }); - } else if (uri.scheme === 'mailto') { + } else if (uri.scheme === 'mailto' || uri.scheme === this._appUriScheme) { return mainThreadWindow.$openUri(uri, {}); } return this.callOriginal(target, options); diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 80c0c007f65..2cca3f54ca5 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -10,7 +10,7 @@ import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { asPromise } from 'vs/base/common/async'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, ICommandDto } from './extHost.protocol'; -import { sortedDiff } from 'vs/base/common/arrays'; +import { sortedDiff, equals } from 'vs/base/common/arrays'; import { comparePaths } from 'vs/base/common/comparers'; import * as vscode from 'vscode'; import { ISplice } from 'vs/base/common/sequence'; @@ -126,18 +126,8 @@ function commandEquals(a: vscode.Command, b: vscode.Command): boolean { && (a.arguments && b.arguments ? compareArgs(a.arguments, b.arguments) : a.arguments === b.arguments); } -function commandListEquals(a: vscode.Command[], b: vscode.Command[]): boolean { - if (a.length !== b.length) { - return false; - } - - for (let i = 0; i < a.length; i++) { - if (!commandEquals(a[i], b[i])) { - return false; - } - } - - return true; +function commandListEquals(a: readonly vscode.Command[], b: readonly vscode.Command[]): boolean { + return equals(a, b, commandEquals); } export interface IValidateInput { @@ -174,9 +164,9 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox { this._placeholder = placeholder; } - private _validateInput: IValidateInput; + private _validateInput: IValidateInput | undefined; - get validateInput(): IValidateInput { + get validateInput(): IValidateInput | undefined { if (!this._extension.enableProposedApi) { throw new Error(`[${this._extension.identifier.value}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${this._extension.identifier.value}`); } @@ -184,7 +174,7 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox { return this._validateInput; } - set validateInput(fn: IValidateInput) { + set validateInput(fn: IValidateInput | undefined) { if (!this._extension.enableProposedApi) { throw new Error(`[${this._extension.identifier.value}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${this._extension.identifier.value}`); } @@ -405,6 +395,10 @@ class ExtHostSourceControl implements vscode.SourceControl { } set commitTemplate(commitTemplate: string | undefined) { + if (commitTemplate === this._commitTemplate) { + return; + } + this._commitTemplate = commitTemplate; this._proxy.$updateSourceControl(this.handle, { commitTemplate }); } @@ -667,7 +661,7 @@ export class ExtHostSCM implements ExtHostSCMShape { return Promise.resolve(undefined); } - return asPromise(() => sourceControl.inputBox.validateInput(value, cursorPosition)).then(result => { + return asPromise(() => sourceControl.inputBox.validateInput!(value, cursorPosition)).then(result => { if (!result) { return Promise.resolve(undefined); } diff --git a/src/vs/workbench/api/common/extHostStatusBar.ts b/src/vs/workbench/api/common/extHostStatusBar.ts index 02c388a51e4..02c89a6e89e 100644 --- a/src/vs/workbench/api/common/extHostStatusBar.ts +++ b/src/vs/workbench/api/common/extHostStatusBar.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar'; +import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/workbench/services/statusbar/common/statusbar'; import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes'; import { StatusBarItem, StatusBarAlignment } from 'vscode'; import { MainContext, MainThreadStatusBarShape, IMainContext } from './extHost.protocol'; @@ -15,16 +15,16 @@ export class ExtHostStatusBarEntry implements StatusBarItem { private _id: number; private _alignment: number; private _priority?: number; - private _disposed: boolean; - private _visible: boolean; + private _disposed: boolean = false; + private _visible: boolean = false; private _statusId: string; private _statusName: string; - private _text: string; - private _tooltip: string; - private _color: string | ThemeColor; - private _command: string; + private _text: string = ''; + private _tooltip?: string; + private _color?: string | ThemeColor; + private _command?: string; private _timeoutHandle: any; private _proxy: MainThreadStatusBarShape; @@ -54,15 +54,15 @@ export class ExtHostStatusBarEntry implements StatusBarItem { return this._text; } - public get tooltip(): string { + public get tooltip(): string | undefined { return this._tooltip; } - public get color(): string | ThemeColor { + public get color(): string | ThemeColor | undefined { return this._color; } - public get command(): string { + public get command(): string | undefined { return this._command; } @@ -71,17 +71,17 @@ export class ExtHostStatusBarEntry implements StatusBarItem { this.update(); } - public set tooltip(tooltip: string) { + public set tooltip(tooltip: string | undefined) { this._tooltip = tooltip; this.update(); } - public set color(color: string | ThemeColor) { + public set color(color: string | ThemeColor | undefined) { this._color = color; this.update(); } - public set command(command: string) { + public set command(command: string | undefined) { this._command = command; this.update(); } diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index 7667465f6bd..da3e935aaeb 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -88,7 +88,7 @@ export namespace ProcessExecutionOptionsDTO { } export namespace ProcessExecutionDTO { - export function is(value: tasks.ShellExecutionDTO | tasks.ProcessExecutionDTO | tasks.CustomExecution2DTO | undefined): value is tasks.ProcessExecutionDTO { + export function is(value: tasks.ShellExecutionDTO | tasks.ProcessExecutionDTO | tasks.CustomExecutionDTO | undefined): value is tasks.ProcessExecutionDTO { if (value) { const candidate = value as tasks.ProcessExecutionDTO; return candidate && !!candidate.process; @@ -133,7 +133,7 @@ export namespace ShellExecutionOptionsDTO { } export namespace ShellExecutionDTO { - export function is(value: tasks.ShellExecutionDTO | tasks.ProcessExecutionDTO | tasks.CustomExecution2DTO | undefined): value is tasks.ShellExecutionDTO { + export function is(value: tasks.ShellExecutionDTO | tasks.ProcessExecutionDTO | tasks.CustomExecutionDTO | undefined): value is tasks.ShellExecutionDTO { if (value) { const candidate = value as tasks.ShellExecutionDTO; return candidate && (!!candidate.commandLine || !!candidate.command); @@ -170,19 +170,19 @@ export namespace ShellExecutionDTO { } } -export namespace CustomExecution2DTO { - export function is(value: tasks.ShellExecutionDTO | tasks.ProcessExecutionDTO | tasks.CustomExecution2DTO | undefined): value is tasks.CustomExecution2DTO { +export namespace CustomExecutionDTO { + export function is(value: tasks.ShellExecutionDTO | tasks.ProcessExecutionDTO | tasks.CustomExecutionDTO | undefined): value is tasks.CustomExecutionDTO { if (value) { - let candidate = value as tasks.CustomExecution2DTO; - return candidate && candidate.customExecution === 'customExecution2'; + let candidate = value as tasks.CustomExecutionDTO; + return candidate && candidate.customExecution === 'customExecution'; } else { return false; } } - export function from(value: vscode.CustomExecution2): tasks.CustomExecution2DTO { + export function from(value: vscode.CustomExecution): tasks.CustomExecutionDTO { return { - customExecution: 'customExecution2' + customExecution: 'customExecution' }; } } @@ -220,13 +220,13 @@ export namespace TaskDTO { if (value === undefined || value === null) { return undefined; } - let execution: tasks.ShellExecutionDTO | tasks.ProcessExecutionDTO | tasks.CustomExecution2DTO | undefined; + let execution: tasks.ShellExecutionDTO | tasks.ProcessExecutionDTO | tasks.CustomExecutionDTO | undefined; if (value.execution instanceof types.ProcessExecution) { execution = ProcessExecutionDTO.from(value.execution); } else if (value.execution instanceof types.ShellExecution) { execution = ShellExecutionDTO.from(value.execution); - } else if ((value).execution2 && (value).execution2 instanceof types.CustomExecution2) { - execution = CustomExecution2DTO.from((value).execution2); + } else if (value.execution && value.execution instanceof types.CustomExecution) { + execution = CustomExecutionDTO.from(value.execution); } const definition: tasks.TaskDefinitionDTO | undefined = TaskDefinitionDTO.from(value.definition); @@ -261,6 +261,7 @@ export namespace TaskDTO { problemMatchers: value.problemMatchers, hasDefinedMatchers: (value as types.Task).hasDefinedMatchers, runOptions: (value).runOptions ? (value).runOptions : { reevaluateOnRerun: true }, + detail: (value).detail }; return result; } @@ -303,6 +304,9 @@ export namespace TaskDTO { if (value._id) { result._id = value._id; } + if (value.detail) { + result.detail = value.detail; + } return result; } } @@ -373,9 +377,9 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { protected _handleCounter: number; protected _handlers: Map; protected _taskExecutions: Map; - protected _providedCustomExecutions2: Map; + protected _providedCustomExecutions2: Map; private _notProvidedCustomExecutions: Set; // Used for custom executions tasks that are created and run through executeTask. - protected _activeCustomExecutions2: Map; + protected _activeCustomExecutions2: Map; private _lastStartedTask: string | undefined; protected readonly _onDidExecuteTask: Emitter = new Emitter(); protected readonly _onDidTerminateTask: Emitter = new Emitter(); @@ -399,9 +403,9 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { this._handleCounter = 0; this._handlers = new Map(); this._taskExecutions = new Map(); - this._providedCustomExecutions2 = new Map(); + this._providedCustomExecutions2 = new Map(); this._notProvidedCustomExecutions = new Set(); - this._activeCustomExecutions2 = new Map(); + this._activeCustomExecutions2 = new Map(); } public registerTaskProvider(extension: IExtensionDescription, type: string, provider: vscode.TaskProvider): vscode.Disposable { @@ -454,15 +458,15 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { } public async $onDidStartTask(execution: tasks.TaskExecutionDTO, terminalId: number): Promise { - const execution2: vscode.CustomExecution2 | undefined = this._providedCustomExecutions2.get(execution.id); - if (execution2) { + const customExecution: types.CustomExecution | undefined = this._providedCustomExecutions2.get(execution.id); + if (customExecution) { if (this._activeCustomExecutions2.get(execution.id) !== undefined) { throw new Error('We should not be trying to start the same custom task executions twice.'); } // Clone the custom execution to keep the original untouched. This is important for multiple runs of the same task. - this._activeCustomExecutions2.set(execution.id, execution2); - this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback()); + this._activeCustomExecutions2.set(execution.id, customExecution); + this._terminalService.attachPtyToTerminal(terminalId, await customExecution.callback()); } this._lastStartedTask = execution.id; @@ -573,8 +577,8 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { throw new Error('Unexpected: The resolved task definition must be the same object as the original task definition. The task definition cannot be changed.'); } - if (CustomExecution2DTO.is(resolvedTaskDTO.execution)) { - await this.addCustomExecution2(resolvedTaskDTO, resolvedTask, true); + if (CustomExecutionDTO.is(resolvedTaskDTO.execution)) { + await this.addCustomExecution(resolvedTaskDTO, resolvedTask, true); } return await this.resolveTaskInternal(resolvedTaskDTO); @@ -588,12 +592,12 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { return this._handleCounter++; } - protected async addCustomExecution2(taskDTO: tasks.TaskDTO, task: vscode.Task2, isProvided: boolean): Promise { + protected async addCustomExecution(taskDTO: tasks.TaskDTO, task: vscode.Task, isProvided: boolean): Promise { const taskId = await this._proxy.$createTaskId(taskDTO); if (!isProvided && !this._providedCustomExecutions2.has(taskId)) { this._notProvidedCustomExecutions.add(taskId); } - this._providedCustomExecutions2.set(taskId, (task).execution2); + this._providedCustomExecutions2.set(taskId, task.execution); } protected async getTaskExecution(execution: tasks.TaskExecutionDTO | string, task?: vscode.Task): Promise { @@ -619,7 +623,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { } private customExecutionComplete(execution: tasks.TaskExecutionDTO): void { - const extensionCallback2: vscode.CustomExecution2 | undefined = this._activeCustomExecutions2.get(execution.id); + const extensionCallback2: vscode.CustomExecution | undefined = this._activeCustomExecutions2.get(execution.id); if (extensionCallback2) { this._activeCustomExecutions2.delete(execution.id); } @@ -674,8 +678,8 @@ export class WorkerExtHostTask extends ExtHostTaskBase { // If this task is a custom execution, then we need to save it away // in the provided custom execution map that is cleaned up after the // task is executed. - if (CustomExecution2DTO.is(dto.execution)) { - await this.addCustomExecution2(dto, task, false); + if (CustomExecutionDTO.is(dto.execution)) { + await this.addCustomExecution(dto, task, false); } else { throw new Error('Not implemented'); } @@ -692,12 +696,12 @@ export class WorkerExtHostTask extends ExtHostTaskBase { } const taskDTO: tasks.TaskDTO | undefined = TaskDTO.from(task, handler.extension); - if (taskDTO && CustomExecution2DTO.is(taskDTO.execution)) { + if (taskDTO && CustomExecutionDTO.is(taskDTO.execution)) { taskDTOs.push(taskDTO); // The ID is calculated on the main thread task side, so, let's call into it here. // We need the task id's pre-computed for custom task executions because when OnDidStartTask // is invoked, we have to be able to map it back to our data. - taskIdPromises.push(this.addCustomExecution2(taskDTO, task, true)); + taskIdPromises.push(this.addCustomExecution(taskDTO, task, true)); } else { console.warn('Only custom execution tasks supported.'); } @@ -710,7 +714,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { } protected async resolveTaskInternal(resolvedTaskDTO: tasks.TaskDTO): Promise { - if (CustomExecution2DTO.is(resolvedTaskDTO.execution)) { + if (CustomExecutionDTO.is(resolvedTaskDTO.execution)) { return resolvedTaskDTO; } else { console.warn('Only custom execution tasks supported.'); diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index 368f057d8d8..40ecebf643b 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -12,6 +12,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { EXT_HOST_CREATION_DELAY, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; import { timeout } from 'vs/base/common/async'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering'; export interface IExtHostTerminalService extends ExtHostTerminalServiceShape { @@ -286,9 +287,13 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ protected readonly _onDidWriteTerminalData: Emitter; public get onDidWriteTerminalData(): Event { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; } + private readonly _bufferer: TerminalDataBufferer; + constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService ) { + this._bufferer = new TerminalDataBufferer(); + this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService); this._onDidWriteTerminalData = new Emitter({ onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(), @@ -364,7 +369,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ if (this._terminalProcesses[id]) { // Extension pty terminal only - when virtual process resize fires it means that the // terminal's maximum dimensions changed - this._terminalProcesses[id].resize(cols, rows); + this._terminalProcesses[id]?.resize(cols, rows); } } @@ -464,8 +469,11 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ protected _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void { p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd)); p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title)); - p.onProcessData(data => this._proxy.$sendProcessData(id, data)); + + // Buffer data events to reduce the amount of messages going to the renderer + this._bufferer.startBuffering(id, p.onProcessData, this._proxy.$sendProcessData); p.onProcessExit(exitCode => this._onProcessExit(id, exitCode)); + if (p.onProcessOverrideDimensions) { p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e)); } @@ -473,12 +481,12 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ } public $acceptProcessInput(id: number, data: string): void { - this._terminalProcesses[id].input(data); + this._terminalProcesses[id]?.input(data); } public $acceptProcessResize(id: number, cols: number, rows: number): void { try { - this._terminalProcesses[id].resize(cols, rows); + this._terminalProcesses[id]?.resize(cols, rows); } catch (error) { // We tried to write to a closed pipe / channel. if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') { @@ -488,15 +496,15 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ } public $acceptProcessShutdown(id: number, immediate: boolean): void { - this._terminalProcesses[id].shutdown(immediate); + this._terminalProcesses[id]?.shutdown(immediate); } public $acceptProcessRequestInitialCwd(id: number): void { - this._terminalProcesses[id].getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd)); + this._terminalProcesses[id]?.getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd)); } public $acceptProcessRequestCwd(id: number): void { - this._terminalProcesses[id].getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd)); + this._terminalProcesses[id]?.getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd)); } public $acceptProcessRequestLatency(id: number): number { @@ -504,6 +512,8 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ } private _onProcessExit(id: number, exitCode: number): void { + this._bufferer.stopBuffering(id); + // Remove process reference delete this._terminalProcesses[id]; diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index 7c462183bc7..24b55f765df 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -166,8 +166,8 @@ interface TreeNode extends IDisposable { class ExtHostTreeView extends Disposable { - private static LABEL_HANDLE_PREFIX = '0'; - private static ID_HANDLE_PREFIX = '1'; + private static readonly LABEL_HANDLE_PREFIX = '0'; + private static readonly ID_HANDLE_PREFIX = '1'; private readonly dataProvider: vscode.TreeDataProvider; @@ -540,7 +540,7 @@ class ExtHostTreeView extends Disposable { private getLightIconPath(extensionTreeItem: vscode.TreeItem): URI | undefined { if (extensionTreeItem.iconPath && !(extensionTreeItem.iconPath instanceof ThemeIcon)) { if (typeof extensionTreeItem.iconPath === 'string' - || extensionTreeItem.iconPath instanceof URI) { + || URI.isUri(extensionTreeItem.iconPath)) { return this.getIconPath(extensionTreeItem.iconPath); } return this.getIconPath((<{ light: string | URI; dark: string | URI }>extensionTreeItem.iconPath).light); @@ -556,7 +556,7 @@ class ExtHostTreeView extends Disposable { } private getIconPath(iconPath: string | URI): URI { - if (iconPath instanceof URI) { + if (URI.isUri(iconPath)) { return iconPath; } return URI.file(iconPath); diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index b27a42256c0..ea12d55450e 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -15,7 +15,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { IPosition } from 'vs/editor/common/core/position'; -import { IRange } from 'vs/editor/common/core/range'; +import * as editorRange from 'vs/editor/common/core/range'; import { ISelection } from 'vs/editor/common/core/selection'; import * as htmlContent from 'vs/base/common/htmlContent'; import * as languageSelector from 'vs/editor/common/modes/languageSelector'; @@ -68,9 +68,9 @@ export namespace Selection { export namespace Range { export function from(range: undefined): undefined; - export function from(range: RangeLike): IRange; - export function from(range: RangeLike | undefined): IRange | undefined; - export function from(range: RangeLike | undefined): IRange | undefined { + export function from(range: RangeLike): editorRange.IRange; + export function from(range: RangeLike | undefined): editorRange.IRange | undefined; + export function from(range: RangeLike | undefined): editorRange.IRange | undefined { if (!range) { return undefined; } @@ -84,9 +84,9 @@ export namespace Range { } export function to(range: undefined): types.Range; - export function to(range: IRange): types.Range; - export function to(range: IRange | undefined): types.Range | undefined; - export function to(range: IRange | undefined): types.Range | undefined { + export function to(range: editorRange.IRange): types.Range; + export function to(range: editorRange.IRange | undefined): types.Range | undefined; + export function to(range: editorRange.IRange | undefined): types.Range | undefined { if (!range) { return undefined; } @@ -283,7 +283,7 @@ export namespace MarkdownString { } let data: any; try { - data = parse(decodeURIComponent(part)); + data = parse(part); } catch (e) { // ignore } @@ -291,7 +291,7 @@ export namespace MarkdownString { return part; } data = cloneAndChange(data, value => { - if (value instanceof URI) { + if (URI.isUri(value)) { const key = `__uri_${Math.random().toString(16).slice(2, 8)}`; bucket[key] = value; return key; @@ -303,9 +303,7 @@ export namespace MarkdownString { } export function to(value: htmlContent.IMarkdownString): vscode.MarkdownString { - const ret = new htmlContent.MarkdownString(value.value); - ret.isTrusted = value.isTrusted; - return ret; + return new htmlContent.MarkdownString(value.value, value.isTrusted); } export function fromStrict(value: string | types.MarkdownString): undefined | string | htmlContent.IMarkdownString { @@ -629,17 +627,6 @@ export namespace DocumentSymbol { export namespace CallHierarchyItem { - export function from(item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto { - return { - name: item.name, - detail: item.detail, - kind: SymbolKind.from(item.kind), - uri: item.uri, - range: Range.from(item.range), - selectionRange: Range.from(item.selectionRange), - }; - } - export function to(item: extHostProtocol.ICallHierarchyItemDto): vscode.CallHierarchyItem { return new types.CallHierarchyItem( SymbolKind.to(item.kind), @@ -823,14 +810,15 @@ export namespace CompletionItem { result.filterText = suggestion.filterText; result.preselect = suggestion.preselect; result.commitCharacters = suggestion.commitCharacters; - result.range = Range.to(suggestion.range); + result.range = editorRange.Range.isIRange(suggestion.range) ? Range.to(suggestion.range) : undefined; + result.range2 = editorRange.Range.isIRange(suggestion.range) ? undefined : { inserting: Range.to(suggestion.range.insert), replacing: Range.to(suggestion.range.replace) }; result.keepWhitespace = typeof suggestion.insertTextRules === 'undefined' ? false : Boolean(suggestion.insertTextRules & modes.CompletionItemInsertTextRule.KeepWhitespace); // 'inserText'-logic if (typeof suggestion.insertTextRules !== 'undefined' && suggestion.insertTextRules & modes.CompletionItemInsertTextRule.InsertAsSnippet) { result.insertText = new types.SnippetString(suggestion.insertText); } else { result.insertText = suggestion.insertText; - result.textEdit = new types.TextEdit(result.range, result.insertText); + result.textEdit = result.range instanceof types.Range ? new types.TextEdit(result.range, result.insertText) : undefined; } // TODO additionalEdits, command @@ -859,7 +847,7 @@ export namespace SignatureInformation { return { label: info.label, documentation: info.documentation ? MarkdownString.fromStrict(info.documentation) : undefined, - parameters: info.parameters && info.parameters.map(ParameterInformation.from) + parameters: Array.isArray(info.parameters) ? info.parameters.map(ParameterInformation.from) : [] }; } @@ -867,7 +855,7 @@ export namespace SignatureInformation { return { label: info.label, documentation: htmlContent.isMarkdownString(info.documentation) ? MarkdownString.to(info.documentation) : info.documentation, - parameters: info.parameters && info.parameters.map(ParameterInformation.to) + parameters: Array.isArray(info.parameters) ? info.parameters.map(ParameterInformation.to) : [] }; } } @@ -878,7 +866,7 @@ export namespace SignatureHelp { return { activeSignature: help.activeSignature, activeParameter: help.activeParameter, - signatures: help.signatures && help.signatures.map(SignatureInformation.from) + signatures: Array.isArray(help.signatures) ? help.signatures.map(SignatureInformation.from) : [], }; } @@ -886,7 +874,7 @@ export namespace SignatureHelp { return { activeSignature: help.activeSignature, activeParameter: help.activeParameter, - signatures: help.signatures && help.signatures.map(SignatureInformation.to) + signatures: Array.isArray(help.signatures) ? help.signatures.map(SignatureInformation.to) : [], }; } } @@ -1163,13 +1151,3 @@ export namespace LogLevel { return types.LogLevel.Info; } } -export namespace WebviewEditorState { - export function from(state: vscode.WebviewEditorState): modes.WebviewEditorState { - switch (state) { - case types.WebviewEditorState.Readonly: return modes.WebviewEditorState.Readonly; - case types.WebviewEditorState.Unchanged: return modes.WebviewEditorState.Unchanged; - case types.WebviewEditorState.Dirty: return modes.WebviewEditorState.Dirty; - default: throw new Error('Unknown vscode.WebviewEditorState'); - } - } -} diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index d8a91af0024..e4a765c9d38 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -614,12 +614,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { } has(uri: URI): boolean { - for (const edit of this._edits) { - if (edit._type === 2 && edit.uri.toString() === uri.toString()) { - return true; - } - } - return false; + return this._edits.some(edit => edit._type === 2 && edit.uri.toString() === uri.toString()); } set(uri: URI, edits: TextEdit[]): void { @@ -1166,22 +1161,22 @@ export class CallHierarchyItem { export class CallHierarchyIncomingCall { - source: vscode.CallHierarchyItem; - sourceRanges: vscode.Range[]; + from: vscode.CallHierarchyItem; + fromRanges: vscode.Range[]; - constructor(item: vscode.CallHierarchyItem, sourceRanges: vscode.Range[]) { - this.sourceRanges = sourceRanges; - this.source = item; + constructor(item: vscode.CallHierarchyItem, fromRanges: vscode.Range[]) { + this.fromRanges = fromRanges; + this.from = item; } } export class CallHierarchyOutgoingCall { - target: vscode.CallHierarchyItem; - sourceRanges: vscode.Range[]; + to: vscode.CallHierarchyItem; + fromRanges: vscode.Range[]; - constructor(item: vscode.CallHierarchyItem, sourceRanges: vscode.Range[]) { - this.sourceRanges = sourceRanges; - this.target = item; + constructor(item: vscode.CallHierarchyItem, fromRanges: vscode.Range[]) { + this.fromRanges = fromRanges; + this.to = item; } } @@ -1227,7 +1222,9 @@ export class MarkdownString { appendText(value: string): MarkdownString { // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash - this.value += value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&'); + this.value += value + .replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&') + .replace('\n', '\n\n'); return this; } @@ -1347,6 +1344,7 @@ export class CompletionItem implements vscode.CompletionItem { insertText?: string | SnippetString; keepWhitespace?: boolean; range?: Range; + range2?: Range | { inserting: Range; replacing: Range; }; commitCharacters?: string[]; textEdit?: TextEdit; additionalTextEdits?: TextEdit[]; @@ -1472,7 +1470,7 @@ export class DocumentLink { tooltip?: string; constructor(range: Range, target: URI | undefined) { - if (target && !(target instanceof URI)) { + if (target && !(URI.isUri(target))) { throw illegalArgument('target'); } if (!Range.isRange(range) || range.isEmpty) { @@ -1624,6 +1622,7 @@ export class ProcessExecution implements vscode.ProcessExecution { if (typeof process !== 'string') { throw illegalArgument('process'); } + this._args = []; this._process = process; if (varg1 !== undefined) { if (Array.isArray(varg1)) { @@ -1633,9 +1632,6 @@ export class ProcessExecution implements vscode.ProcessExecution { this._options = varg1; } } - if (this._args === undefined) { - this._args = []; - } } @@ -1687,9 +1683,9 @@ export class ProcessExecution implements vscode.ProcessExecution { @es5ClassCompat export class ShellExecution implements vscode.ShellExecution { - private _commandLine: string; - private _command: string | vscode.ShellQuotedString; - private _args: (string | vscode.ShellQuotedString)[]; + private _commandLine: string | undefined; + private _command: string | vscode.ShellQuotedString | undefined; + private _args: (string | vscode.ShellQuotedString)[] = []; private _options: vscode.ShellExecutionOptions | undefined; constructor(commandLine: string, options?: vscode.ShellExecutionOptions); @@ -1714,11 +1710,11 @@ export class ShellExecution implements vscode.ShellExecution { } } - get commandLine(): string { + get commandLine(): string | undefined { return this._commandLine; } - set commandLine(value: string) { + set commandLine(value: string | undefined) { if (typeof value !== 'string') { throw illegalArgument('commandLine'); } @@ -1726,7 +1722,7 @@ export class ShellExecution implements vscode.ShellExecution { } get command(): string | vscode.ShellQuotedString { - return this._command; + return this._command ? this._command : ''; } set command(value: string | vscode.ShellQuotedString) { @@ -1781,7 +1777,7 @@ export enum TaskScope { Workspace = 2 } -export class CustomExecution2 implements vscode.CustomExecution2 { +export class CustomExecution implements vscode.CustomExecution { private _callback: () => Thenable; constructor(callback: () => Thenable) { this._callback = callback; @@ -1812,7 +1808,7 @@ export class Task implements vscode.Task2 { private _definition: vscode.TaskDefinition; private _scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined; private _name: string; - private _execution: ProcessExecution | ShellExecution | CustomExecution2 | undefined; + private _execution: ProcessExecution | ShellExecution | CustomExecution | undefined; private _problemMatchers: string[]; private _hasDefinedMatchers: boolean; private _isBackground: boolean; @@ -1820,27 +1816,28 @@ export class Task implements vscode.Task2 { private _group: TaskGroup | undefined; private _presentationOptions: vscode.TaskPresentationOptions; private _runOptions: vscode.RunOptions; + private _detail: string | undefined; - constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution2, problemMatchers?: string | string[]); - constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution2, problemMatchers?: string | string[]); + constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); + constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); constructor(definition: vscode.TaskDefinition, arg2: string | (vscode.TaskScope.Global | vscode.TaskScope.Workspace) | vscode.WorkspaceFolder, arg3: any, arg4?: any, arg5?: any, arg6?: any) { - this.definition = definition; + this._definition = this.definition = definition; let problemMatchers: string | string[]; if (typeof arg2 === 'string') { - this.name = arg2; - this.source = arg3; + this._name = this.name = arg2; + this._source = this.source = arg3; this.execution = arg4; problemMatchers = arg5; } else if (arg2 === TaskScope.Global || arg2 === TaskScope.Workspace) { this.target = arg2; - this.name = arg3; - this.source = arg4; + this._name = this.name = arg3; + this._source = this.source = arg4; this.execution = arg5; problemMatchers = arg6; } else { this.target = arg2; - this.name = arg3; - this.source = arg4; + this._name = this.name = arg3; + this._source = this.source = arg4; this.execution = arg5; problemMatchers = arg6; } @@ -1887,7 +1884,7 @@ export class Task implements vscode.Task2 { type: Task.ShellType, id: this._execution.computeId() }; - } else if (this._execution instanceof CustomExecution2) { + } else if (this._execution instanceof CustomExecution) { this._definition = { type: Task.ExtensionCallbackType, id: this._execution.computeId() @@ -1933,19 +1930,11 @@ export class Task implements vscode.Task2 { this._name = value; } - get execution(): ProcessExecution | ShellExecution | undefined { - return (this._execution instanceof CustomExecution2) ? undefined : this._execution; - } - - set execution(value: ProcessExecution | ShellExecution | undefined) { - this.execution2 = value; - } - - get execution2(): ProcessExecution | ShellExecution | CustomExecution2 | undefined { + get execution(): ProcessExecution | ShellExecution | CustomExecution | undefined { return this._execution; } - set execution2(value: ProcessExecution | ShellExecution | CustomExecution2 | undefined) { + set execution(value: ProcessExecution | ShellExecution | CustomExecution | undefined) { if (value === null) { value = undefined; } @@ -2014,6 +2003,17 @@ export class Task implements vscode.Task2 { this._group = value; } + get detail(): string | undefined { + return this._detail; + } + + set detail(value: string | undefined) { + if (value === null) { + value = undefined; + } + this._detail = value; + } + get presentationOptions(): vscode.TaskPresentationOptions { return this._presentationOptions; } @@ -2059,7 +2059,7 @@ export class TreeItem { constructor(label: string | vscode.TreeItemLabel, collapsibleState?: vscode.TreeItemCollapsibleState) constructor(resourceUri: URI, collapsibleState?: vscode.TreeItemCollapsibleState) constructor(arg1: string | vscode.TreeItemLabel | URI, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) { - if (arg1 instanceof URI) { + if (URI.isUri(arg1)) { this.resourceUri = arg1; } else { this.label = arg1; @@ -2431,7 +2431,7 @@ export class Decoration { bubble?: boolean; } -export enum WebviewEditorState { +export enum WebviewContentState { Readonly = 1, Unchanged = 2, Dirty = 3, diff --git a/src/vs/workbench/api/common/extHostUrls.ts b/src/vs/workbench/api/common/extHostUrls.ts index 6b6f8081ae5..0a4480a63e8 100644 --- a/src/vs/workbench/api/common/extHostUrls.ts +++ b/src/vs/workbench/api/common/extHostUrls.ts @@ -56,7 +56,11 @@ export class ExtHostUrls implements ExtHostUrlsShape { return Promise.resolve(undefined); } - async createAppUri(extensionId: ExtensionIdentifier, options?: vscode.AppUriOptions): Promise { - return URI.revive(await this._proxy.$createAppUri(extensionId, options)); + async createAppUri(uri: URI): Promise { + return URI.revive(await this._proxy.$createAppUri(uri)); + } + + async proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: vscode.AppUriOptions): Promise { + return URI.revive(await this._proxy.$proposedCreateAppUri(extensionId, options)); } } diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 7d43a551a1c..50fdaec003e 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -9,17 +9,19 @@ import { generateUuid } from 'vs/base/common/uuid'; import * as modes from 'vs/editor/common/modes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; +import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; import * as vscode from 'vscode'; import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol'; -import { Disposable, WebviewEditorState } from './extHostTypes'; +import { Disposable } from './extHostTypes'; type IconPath = URI | { light: URI, dark: URI }; export class ExtHostWebview implements vscode.Webview { - private _html: string; + private _html: string = ''; private _isDisposed: boolean = false; + private _hasCalledAsWebviewUri = false; public readonly _onMessageEmitter = new Emitter(); public readonly onDidReceiveMessage: Event = this._onMessageEmitter.event; @@ -28,7 +30,9 @@ export class ExtHostWebview implements vscode.Webview { private readonly _handle: WebviewPanelHandle, private readonly _proxy: MainThreadWebviewsShape, private _options: vscode.WebviewOptions, - private readonly _initData: WebviewInitData + private readonly _initData: WebviewInitData, + private readonly _workspace: IExtHostWorkspace | undefined, + private readonly _extension: IExtensionDescription, ) { } public dispose() { @@ -36,6 +40,7 @@ export class ExtHostWebview implements vscode.Webview { } public asWebviewUri(resource: vscode.Uri): vscode.Uri { + this._hasCalledAsWebviewUri = true; return asWebviewUri(this._initData, this._handle, resource); } @@ -53,6 +58,12 @@ export class ExtHostWebview implements vscode.Webview { this.assertNotDisposed(); if (this._html !== value) { this._html = value; + if (this._initData.isExtensionDevelopmentDebug && !this._hasCalledAsWebviewUri) { + if (/(["'])vscode-resource:([^\s'"]+?)(["'])/i.test(value)) { + this._hasCalledAsWebviewUri = true; + console.warn(`${this._extension.identifier.value} created a webview that appears to use the vscode-resource scheme directly. Please migrate to use the 'webview.asWebviewUri' api instead: https://aka.ms/vscode-webview-use-aswebviewuri`); + } + } this._proxy.$setHtml(this._handle, value); } } @@ -64,7 +75,7 @@ export class ExtHostWebview implements vscode.Webview { public set options(newOptions: vscode.WebviewOptions) { this.assertNotDisposed(); - this._proxy.$setOptions(this._handle, convertWebviewOptions(newOptions)); + this._proxy.$setOptions(this._handle, convertWebviewOptions(this._extension, this._workspace, newOptions)); this._options = newOptions; } @@ -80,7 +91,7 @@ export class ExtHostWebview implements vscode.Webview { } } -export class ExtHostWebviewEditor implements vscode.WebviewEditor { +export class ExtHostWebviewEditor implements vscode.WebviewPanel { private readonly _handle: WebviewPanelHandle; private readonly _proxy: MainThreadWebviewsShape; @@ -93,7 +104,6 @@ export class ExtHostWebviewEditor implements vscode.WebviewEditor { private _viewColumn: vscode.ViewColumn | undefined; private _visible: boolean = true; private _active: boolean = true; - private _state = WebviewEditorState.Readonly; _isDisposed: boolean = false; @@ -103,7 +113,6 @@ export class ExtHostWebviewEditor implements vscode.WebviewEditor { readonly _onDidChangeViewStateEmitter = new Emitter(); public readonly onDidChangeViewState: Event = this._onDidChangeViewStateEmitter.event; - constructor( handle: WebviewPanelHandle, proxy: MainThreadWebviewsShape, @@ -214,27 +223,6 @@ export class ExtHostWebviewEditor implements vscode.WebviewEditor { this._visible = value; } - public get state(): vscode.WebviewEditorState { - return this._state; - } - - public set state(newState: vscode.WebviewEditorState) { - this._state = newState; - this._proxy.$setState(this._handle, typeConverters.WebviewEditorState.from(newState)); - } - - private readonly _onWillSave = new Emitter<{ waitUntil: (thenable: Thenable) => void }>(); - public readonly onWillSave = this._onWillSave.event; - - async _save(): Promise { - const waitingOn: Thenable[] = []; - this._onWillSave.fire({ - waitUntil: (thenable: Thenable): void => { waitingOn.push(thenable); }, - }); - const result = await Promise.all(waitingOn); - return result.every(x => x); - } - public postMessage(message: any): Promise { this.assertNotDisposed(); return this._proxy.$postMessage(this._handle, message); @@ -263,12 +251,13 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { private readonly _proxy: MainThreadWebviewsShape; private readonly _webviewPanels = new Map(); - private readonly _serializers = new Map(); - private readonly _editorProviders = new Map(); + private readonly _serializers = new Map(); + private readonly _editorProviders = new Map(); constructor( mainContext: IMainContext, - private readonly initData: WebviewInitData + private readonly initData: WebviewInitData, + private readonly workspace: IExtHostWorkspace | undefined, ) { this._proxy = mainContext.getProxy(MainContext.MainThreadWebviews); } @@ -287,15 +276,16 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { }; const handle = ExtHostWebviews.newHandle(); - this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, convertWebviewOptions(options), extension.identifier, extension.extensionLocation); + this._proxy.$createWebviewPanel({ id: extension.identifier, location: extension.extensionLocation }, handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options)); - const webview = new ExtHostWebview(handle, this._proxy, options, this.initData); + const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, this.workspace, extension); const panel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, viewColumn, options, webview); this._webviewPanels.set(handle, panel); return panel; } public registerWebviewPanelSerializer( + extension: IExtensionDescription, viewType: string, serializer: vscode.WebviewPanelSerializer ): vscode.Disposable { @@ -303,7 +293,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { throw new Error(`Serializer for '${viewType}' already registered`); } - this._serializers.set(viewType, serializer); + this._serializers.set(viewType, { serializer, extension }); this._proxy.$registerSerializer(viewType); return new Disposable(() => { @@ -313,15 +303,17 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { } public registerWebviewEditorProvider( + extension: IExtensionDescription, viewType: string, - provider: vscode.WebviewEditorProvider + provider: vscode.WebviewEditorProvider, + options?: vscode.WebviewPanelOptions, ): vscode.Disposable { if (this._editorProviders.has(viewType)) { throw new Error(`Editor provider for '${viewType}' already registered`); } - this._editorProviders.set(viewType, provider); - this._proxy.$registerEditorProvider(viewType); + this._editorProviders.set(viewType, { extension, provider, }); + this._proxy.$registerEditorProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType, options || {}); return new Disposable(() => { this._editorProviders.delete(viewType); @@ -398,12 +390,13 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions ): Promise { - const serializer = this._serializers.get(viewType); - if (!serializer) { + const entry = this._serializers.get(viewType); + if (!entry) { return Promise.reject(new Error(`No serializer found for '${viewType}'`)); } + const { serializer, extension } = entry; - const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData); + const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData, this.workspace, extension); const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); this._webviewPanels.set(webviewHandle, revivedPanel); return Promise.resolve(serializer.deserializeWebviewPanel(revivedPanel, state)); @@ -415,46 +408,41 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { async $resolveWebviewEditor( resource: UriComponents, - webviewHandle: WebviewPanelHandle, + handle: WebviewPanelHandle, viewType: string, title: string, - state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions ): Promise { - const provider = this._editorProviders.get(viewType); - if (!provider) { + const entry = this._editorProviders.get(viewType); + if (!entry) { return Promise.reject(new Error(`No provider found for '${viewType}'`)); } - - const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData); - const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); - this._webviewPanels.set(webviewHandle, revivedPanel); - return Promise.resolve(provider.resolveWebviewEditor(URI.revive(resource), revivedPanel)); - } - - async $save(handle: WebviewPanelHandle): Promise { - const panel = this.getWebviewPanel(handle); - if (panel) { - return panel._save(); - } - return false; + const { provider, extension } = entry; + const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, this.workspace, extension); + const revivedPanel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); + this._webviewPanels.set(handle, revivedPanel); + await Promise.resolve(provider.resolveWebviewEditor({ resource: URI.revive(resource) }, revivedPanel)); } } function convertWebviewOptions( - options: vscode.WebviewPanelOptions & vscode.WebviewOptions + extension: IExtensionDescription, + workspace: IExtHostWorkspace | undefined, + options: vscode.WebviewPanelOptions & vscode.WebviewOptions, ): modes.IWebviewOptions { return { ...options, - portMapping: options.portMapping - ? options.portMapping.map((x): modes.IWebviewPortMapping => { - // Handle old proposed api - if ('port' in x) { - return { webviewPort: (x as any).port, extensionHostPort: (x as any).resolvedPort }; - } - return { webviewPort: x.webviewPort, extensionHostPort: x.extensionHostPort }; - }) - : undefined, + localResourceRoots: options.localResourceRoots || getDefaultLocalResourceRoots(extension, workspace) }; } + +function getDefaultLocalResourceRoots( + extension: IExtensionDescription, + workspace: IExtHostWorkspace | undefined, +): URI[] { + return [ + ...(workspace && workspace.getWorkspaceFolders() || []).map(x => x.uri), + extension.extensionLocation, + ]; +} diff --git a/src/vs/workbench/api/common/extHostWindow.ts b/src/vs/workbench/api/common/extHostWindow.ts index 7017c29788e..8ce82ac8b2d 100644 --- a/src/vs/workbench/api/common/extHostWindow.ts +++ b/src/vs/workbench/api/common/extHostWindow.ts @@ -54,14 +54,14 @@ export class ExtHostWindow implements ExtHostWindowShape { return this._proxy.$openUri(stringOrUri, options); } - async resolveExternalUri(uri: URI, options: IOpenUriOptions): Promise { + async asExternalUri(uri: URI, options: IOpenUriOptions): Promise { if (isFalsyOrWhitespace(uri.scheme)) { return Promise.reject('Invalid scheme - cannot be empty'); } else if (!new Set([Schemas.http, Schemas.https]).has(uri.scheme)) { return Promise.reject(`Invalid scheme '${uri.scheme}'`); } - const result = await this._proxy.$resolveExternalUri(uri, options); + const result = await this._proxy.$asExternalUri(uri, options); return URI.from(result); } } diff --git a/src/vs/workbench/api/common/menusExtensionPoint.ts b/src/vs/workbench/api/common/menusExtensionPoint.ts index 0dd6facb692..3133acfba2c 100644 --- a/src/vs/workbench/api/common/menusExtensionPoint.ts +++ b/src/vs/workbench/api/common/menusExtensionPoint.ts @@ -12,7 +12,7 @@ import { IExtensionPointUser, ExtensionMessageCollector, ExtensionsRegistry } fr import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { MenuId, MenuRegistry, ILocalizedString, IMenuItem } from 'vs/platform/actions/common/actions'; import { URI } from 'vs/base/common/uri'; -import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; namespace schema { @@ -387,7 +387,7 @@ commandsExtensionPoint.setHandler(extensions => { } }); -let _menuRegistrations: IDisposable[] = []; +const _menuRegistrations = new DisposableStore(); ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyMenuItem[] }>({ extensionPoint: 'menus', @@ -395,7 +395,7 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM }).setHandler(extensions => { // remove all previous menu registrations - _menuRegistrations = dispose(_menuRegistrations); + _menuRegistrations.clear(); for (let extension of extensions) { const { value, collector } = extension; @@ -450,7 +450,7 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM order, when: ContextKeyExpr.deserialize(item.when) } as IMenuItem); - _menuRegistrations.push(registration); + _menuRegistrations.add(registration); } }); } diff --git a/src/vs/workbench/api/common/shared/tasks.ts b/src/vs/workbench/api/common/shared/tasks.ts index b8fab0b5a02..465a042d8b5 100644 --- a/src/vs/workbench/api/common/shared/tasks.ts +++ b/src/vs/workbench/api/common/shared/tasks.ts @@ -66,8 +66,8 @@ export interface ShellExecutionDTO { options?: ShellExecutionOptionsDTO; } -export interface CustomExecution2DTO { - customExecution: 'customExecution2'; +export interface CustomExecutionDTO { + customExecution: 'customExecution'; } export interface TaskSourceDTO { @@ -84,11 +84,12 @@ export interface TaskHandleDTO { export interface TaskDTO { _id: string; name?: string; - execution: ProcessExecutionDTO | ShellExecutionDTO | CustomExecution2DTO | undefined; + execution: ProcessExecutionDTO | ShellExecutionDTO | CustomExecutionDTO | undefined; definition: TaskDefinitionDTO; isBackground?: boolean; source: TaskSourceDTO; group?: string; + detail?: string; presentationOptions?: TaskPresentationOptionsDTO; problemMatchers: string[]; hasDefinedMatchers: boolean; diff --git a/src/vs/workbench/api/common/shared/webview.ts b/src/vs/workbench/api/common/shared/webview.ts index b496a453a2f..6d5a52928f8 100644 --- a/src/vs/workbench/api/common/shared/webview.ts +++ b/src/vs/workbench/api/common/shared/webview.ts @@ -7,6 +7,7 @@ import { URI } from 'vs/base/common/uri'; import * as vscode from 'vscode'; export interface WebviewInitData { + readonly isExtensionDevelopmentDebug: boolean; readonly webviewResourceRoot: string; readonly webviewCspSource: string; } @@ -17,7 +18,13 @@ export function asWebviewUri( resource: vscode.Uri, ): vscode.Uri { const uri = initData.webviewResourceRoot - .replace('{{resource}}', resource.toString().replace(/^\S+?:/, '')) + // Make sure we preserve the scheme of the resource but convert it into a normal path segment + // The scheme is important as we need to know if we are requesting a local or a remote resource. + .replace('{{resource}}', resource.scheme + withoutScheme(resource)) .replace('{{uuid}}', uuid); return URI.parse(uri); } + +function withoutScheme(resource: vscode.Uri): string { + return resource.toString().replace(/^\S+?:/, ''); +} diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts index 4cdb2967e9c..e5d3c44e63b 100644 --- a/src/vs/workbench/api/node/extHostCLIServer.ts +++ b/src/vs/workbench/api/node/extHostCLIServer.ts @@ -7,9 +7,10 @@ import { generateRandomPipeName } from 'vs/base/parts/ipc/node/ipc.net'; import * as http from 'http'; import * as fs from 'fs'; import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; -import { IWindowOpenable, IOpenInWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; +import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window'; export interface OpenCommandPipeArgs { type: 'open'; @@ -126,7 +127,7 @@ export class CLIServer { } if (urisToOpen.length) { const waitMarkerFileURI = waitMarkerFilePath ? URI.file(waitMarkerFilePath) : undefined; - const windowOpenArgs: IOpenInWindowOptions = { forceNewWindow, diffMode, addMode, gotoLineMode, forceReuseWindow, waitMarkerFileURI }; + const windowOpenArgs: INativeOpenWindowOptions = { forceNewWindow, diffMode, addMode, gotoLineMode, forceReuseWindow, waitMarkerFileURI }; this._commands.executeCommand('_files.windowOpen', urisToOpen, windowOpenArgs); } res.writeHead(200); diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 4f91793edfc..1b9b233961a 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -82,12 +82,12 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe private _debugAdapters: Map; private _debugAdaptersTrackers: Map; - private _variableResolver: IConfigurationResolverService; + private _variableResolver: IConfigurationResolverService | undefined; private _integratedTerminalInstance?: vscode.Terminal; - private _terminalDisposedListener: IDisposable; + private _terminalDisposedListener: IDisposable | undefined; - private _signService: ISignService; + private _signService: ISignService | undefined; constructor( @@ -340,46 +340,38 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe }); } - return new Promise(resolve => { - if (this._integratedTerminalInstance) { - this._integratedTerminalInstance.processId.then(pid => { - resolve(hasChildProcesses(pid)); - }, err => { - resolve(true); - }); - } else { - resolve(true); - } - }).then(async needNewTerminal => { + let needNewTerminal = true; // be pessimistic + if (this._integratedTerminalInstance) { + const pid = await this._integratedTerminalInstance.processId; + needNewTerminal = await hasChildProcesses(pid); // if no processes running in terminal reuse terminal + } - const configProvider = await this._configurationService.getConfigProvider(); - const shell = this._terminalService.getDefaultShell(true, configProvider); + const configProvider = await this._configurationService.getConfigProvider(); + const shell = this._terminalService.getDefaultShell(true, configProvider); - if (needNewTerminal || !this._integratedTerminalInstance) { - const options: vscode.TerminalOptions = { - shellPath: shell, - // shellArgs: this._terminalService._getDefaultShellArgs(configProvider), - cwd: args.cwd, - name: args.title || nls.localize('debug.terminal.title', "debuggee"), - env: args.env - }; - delete args.cwd; - delete args.env; - this._integratedTerminalInstance = this._terminalService.createTerminalFromOptions(options); - } - const terminal: vscode.Terminal = this._integratedTerminalInstance; + if (needNewTerminal || !this._integratedTerminalInstance) { - terminal.show(); + const options: vscode.TerminalOptions = { + shellPath: shell, + // shellArgs: this._terminalService._getDefaultShellArgs(configProvider), + cwd: args.cwd, + name: args.title || nls.localize('debug.terminal.title', "debuggee"), + env: args.env + }; + delete args.cwd; + delete args.env; + this._integratedTerminalInstance = this._terminalService.createTerminalFromOptions(options); + } - return this._integratedTerminalInstance.processId.then(shellProcessId => { + const terminal = this._integratedTerminalInstance; - const command = prepareCommand(args, shell, configProvider); + terminal.show(); - terminal.sendText(command, true); + const shellProcessId = await this._integratedTerminalInstance.processId; + const command = prepareCommand(args, shell, configProvider); + terminal.sendText(command, true); - return shellProcessId; - }); - }); + return shellProcessId; } else if (args.kind === 'external') { @@ -391,7 +383,7 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe public async $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): Promise { if (!this._variableResolver) { const [workspaceFolders, configProvider] = await Promise.all([this._workspaceService.getWorkspaceFolders2(), this._configurationService.getConfigProvider()]); - this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._editorsService, configProvider); + this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._editorsService, configProvider!); } let ws: IWorkspaceFolder | undefined; const folder = await this.getFolder(folderUri); @@ -791,7 +783,7 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe } return undefined; }), - new Promise((resolve, reject) => { + new Promise((resolve, reject) => { const timeout = setTimeout(() => { clearTimeout(timeout); reject(new Error('timeout')); @@ -1070,10 +1062,8 @@ interface IDapTransport { class DirectDebugAdapter extends AbstractDebugAdapter implements IDapTransport { - readonly onError: Event; - readonly onExit: Event; - private _sendUp: (msg: DebugProtocol.ProtocolMessage) => void; + private _sendUp!: (msg: DebugProtocol.ProtocolMessage) => void; constructor(implementation: any) { super(); diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 8e96e6738ec..a1c3e50ffdc 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -72,6 +72,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { return nativeProcessSend.apply(process, args); } mainThreadConsole.$logExtensionHostMessage(args[0]); + return false; }; } @@ -82,6 +83,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { let r: T | null = null; activationTimesBuilder.codeLoadingStart(); this._logService.info(`ExtensionService#loadCommonJSModule ${module.toString(true)}`); + this._logService.flush(); try { r = require.__$__nodeRequire(module.fsPath); } catch (e) { diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 71d8b818b72..1df1b4731ed 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -19,7 +19,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; -import { ExtHostTaskBase, TaskHandleDTO, TaskDTO, CustomExecution2DTO, HandlerData } from 'vs/workbench/api/common/extHostTask'; +import { ExtHostTaskBase, TaskHandleDTO, TaskDTO, CustomExecutionDTO, HandlerData } from 'vs/workbench/api/common/extHostTask'; import { Schemas } from 'vs/base/common/network'; export class ExtHostTask extends ExtHostTaskBase { @@ -56,8 +56,8 @@ export class ExtHostTask extends ExtHostTaskBase { // If this task is a custom execution, then we need to save it away // in the provided custom execution map that is cleaned up after the // task is executed. - if (CustomExecution2DTO.is(dto.execution)) { - await this.addCustomExecution2(dto, task, false); + if (CustomExecutionDTO.is(dto.execution)) { + await this.addCustomExecution(dto, task, false); } return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, task)); @@ -76,11 +76,11 @@ export class ExtHostTask extends ExtHostTaskBase { if (taskDTO) { taskDTOs.push(taskDTO); - if (CustomExecution2DTO.is(taskDTO.execution)) { + if (CustomExecutionDTO.is(taskDTO.execution)) { // The ID is calculated on the main thread task side, so, let's call into it here. // We need the task id's pre-computed for custom task executions because when OnDidStartTask // is invoked, we have to be able to map it back to our data. - taskIdPromises.push(this.addCustomExecution2(taskDTO, task, true)); + taskIdPromises.push(this.addCustomExecution(taskDTO, task, true)); } } } diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 13831193a59..d89750cfdf1 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -123,7 +123,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService { this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider); } - public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { + public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { const shellLaunchConfig: IShellLaunchConfig = { name: shellLaunchConfigDto.name, executable: shellLaunchConfigDto.executable, @@ -156,16 +156,21 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService { } const activeWorkspaceRootUri = URI.revive(activeWorkspaceRootUriComponents); - // Get the environment - const apiLastActiveWorkspace = await this._extHostWorkspace.getWorkspaceFolder(activeWorkspaceRootUri); - const lastActiveWorkspace = apiLastActiveWorkspace ? { - uri: apiLastActiveWorkspace.uri, - name: apiLastActiveWorkspace.name, - index: apiLastActiveWorkspace.index, - toResource: () => { - throw new Error('Not implemented'); + let lastActiveWorkspace: IWorkspaceFolder | null = null; + if (activeWorkspaceRootUriComponents && activeWorkspaceRootUri) { + // Get the environment + const apiLastActiveWorkspace = await this._extHostWorkspace.getWorkspaceFolder(activeWorkspaceRootUri); + if (apiLastActiveWorkspace) { + lastActiveWorkspace = { + uri: apiLastActiveWorkspace.uri, + name: apiLastActiveWorkspace.name, + index: apiLastActiveWorkspace.index, + toResource: () => { + throw new Error('Not implemented'); + } + }; } - } as IWorkspaceFolder : null; + } // Get the initial cwd const terminalConfig = configProvider.getConfiguration('terminal.integrated'); diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index afd82468c06..4781f226762 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -32,7 +32,7 @@ class WorkerRequireInterceptor extends RequireInterceptor { export class ExtHostExtensionService extends AbstractExtHostExtensionService { - private _fakeModules: WorkerRequireInterceptor; + private _fakeModules?: WorkerRequireInterceptor; protected async _beforeAlmostReadyToRunExtensions(): Promise { // initialize API and register actors @@ -57,7 +57,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { const _exports = {}; const _module = { exports: _exports }; const _require = (request: string) => { - const result = this._fakeModules.getModule(request, module); + const result = this._fakeModules!.getModule(request, module); if (result === undefined) { throw new Error(`Cannot load module '${request}'`); } diff --git a/src/vs/workbench/api/worker/extHostLogService.ts b/src/vs/workbench/api/worker/extHostLogService.ts index a69842324a6..acf2d3be8da 100644 --- a/src/vs/workbench/api/worker/extHostLogService.ts +++ b/src/vs/workbench/api/worker/extHostLogService.ts @@ -72,4 +72,6 @@ export class ExtHostLogService extends AbstractLogService implements ILogService this._proxy.$log(this._logFile, LogLevel.Critical, Array.from(arguments)); } } + + flush(): void { } } diff --git a/src/vs/workbench/browser/actions.ts b/src/vs/workbench/browser/actions.ts index aac3da30445..2cf27b60ae6 100644 --- a/src/vs/workbench/browser/actions.ts +++ b/src/vs/workbench/browser/actions.ts @@ -57,13 +57,7 @@ export class ContributableActionProvider implements IActionProvider { const context = this.toContext(tree, element); const contributors = this.registry.getActionBarContributors(Scope.VIEWER); - for (const contributor of contributors) { - if (contributor.hasActions(context)) { - return true; - } - } - - return false; + return contributors.some(contributor => contributor.hasActions(context)); } getActions(tree: ITree, element: unknown): ReadonlyArray { @@ -156,7 +150,7 @@ export interface IActionBarRegistry { class ActionBarRegistry implements IActionBarRegistry { private readonly actionBarContributorConstructors: { scope: string; ctor: IConstructorSignature0; }[] = []; private readonly actionBarContributorInstances: Map = new Map(); - private instantiationService!: IInstantiationService; + private instantiationService: IInstantiationService | undefined; start(accessor: ServicesAccessor): void { this.instantiationService = accessor.get(IInstantiationService); @@ -168,13 +162,15 @@ class ActionBarRegistry implements IActionBarRegistry { } private createActionBarContributor(scope: string, ctor: IConstructorSignature0): void { - const instance = this.instantiationService.createInstance(ctor); - let target = this.actionBarContributorInstances.get(scope); - if (!target) { - target = []; - this.actionBarContributorInstances.set(scope, target); + if (this.instantiationService) { + const instance = this.instantiationService.createInstance(ctor); + let target = this.actionBarContributorInstances.get(scope); + if (!target) { + target = []; + this.actionBarContributorInstances.set(scope, target); + } + target.push(instance); } - target.push(instance); } private getContributors(scope: string): ActionBarContributor[] { diff --git a/src/vs/workbench/browser/actions/developerActions.ts b/src/vs/workbench/browser/actions/developerActions.ts index 1447d3f1b77..abf8bdb9d12 100644 --- a/src/vs/workbench/browser/actions/developerActions.ts +++ b/src/vs/workbench/browser/actions/developerActions.ts @@ -29,7 +29,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v class InspectContextKeysAction extends Action { static readonly ID = 'workbench.action.inspectContextKeys'; - static LABEL = nls.localize('inspect context keys', "Inspect Context Keys"); + static readonly LABEL = nls.localize('inspect context keys', "Inspect Context Keys"); constructor( id: string, @@ -91,7 +91,7 @@ class InspectContextKeysAction extends Action { class ToggleScreencastModeAction extends Action { static readonly ID = 'workbench.action.toggleScreencastMode'; - static LABEL = nls.localize('toggle screencast mode', "Toggle Screencast Mode"); + static readonly LABEL = nls.localize('toggle screencast mode', "Toggle Screencast Mode"); static disposable: IDisposable | undefined; @@ -152,7 +152,7 @@ class ToggleScreencastModeAction extends Action { } })); - const onKeyDown = domEvent(container, 'keydown', true); + const onKeyDown = domEvent(window, 'keydown', true); let keyboardTimeout: IDisposable = Disposable.None; let length = 0; @@ -195,7 +195,7 @@ class ToggleScreencastModeAction extends Action { class LogStorageAction extends Action { static readonly ID = 'workbench.action.logStorage'; - static LABEL = nls.localize({ key: 'logStorage', comment: ['A developer only action to log the contents of the storage for the current window.'] }, "Log Storage Database Contents"); + static readonly LABEL = nls.localize({ key: 'logStorage', comment: ['A developer only action to log the contents of the storage for the current window.'] }, "Log Storage Database Contents"); constructor( id: string, diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 190f5dcd853..944c253c1b2 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -16,13 +16,14 @@ import { IEditorGroupsService, GroupOrientation } from 'vs/workbench/services/ed import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; +import { getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { isWindows, isLinux, isWeb } from 'vs/base/common/platform'; import { IsMacNativeContext } from 'vs/workbench/browser/contextkeys'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { InEditorZenModeContext, IsCenteredLayoutContext } from 'vs/workbench/common/editor'; +import { InEditorZenModeContext, IsCenteredLayoutContext, EditorAreaVisibleContext } from 'vs/workbench/common/editor'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { SideBarVisibleContext } from 'vs/workbench/common/viewlet'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; const registry = Registry.as(Extensions.WorkbenchActions); const viewCategory = nls.localize('view', "View"); @@ -232,6 +233,16 @@ export class ToggleEditorVisibilityAction extends Action { registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorVisibilityAction, ToggleEditorVisibilityAction.ID, ToggleEditorVisibilityAction.LABEL), 'View: Toggle Editor Area Visibility', viewCategory); +MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { + group: '2_workbench_layout', + command: { + id: ToggleEditorVisibilityAction.ID, + title: nls.localize({ key: 'miShowEditorArea', comment: ['&& denotes a mnemonic'] }, "Show &&Editor Area"), + toggled: EditorAreaVisibleContext + }, + order: 5 +}); + export class ToggleSidebarVisibilityAction extends Action { static readonly ID = 'workbench.action.toggleSidebarVisibility'; @@ -340,7 +351,7 @@ class ToggleTabsVisibilityAction extends Action { } registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTabsVisibilityAction, ToggleTabsVisibilityAction.ID, ToggleTabsVisibilityAction.LABEL, { - primary: undefined!, + primary: undefined, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W, }, linux: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W, } }), 'View: Toggle Tab Visibility', viewCategory); @@ -396,20 +407,21 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ export class ToggleMenuBarAction extends Action { static readonly ID = 'workbench.action.toggleMenuBar'; - static LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar"); + static readonly LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar"); private static readonly menuBarVisibilityKey = 'window.menuBarVisibility'; constructor( id: string, label: string, - @IConfigurationService private readonly configurationService: IConfigurationService + @IConfigurationService private readonly configurationService: IConfigurationService, + @IEnvironmentService private readonly environmentService: IEnvironmentService ) { super(id, label); } run(): Promise { - let currentVisibilityValue = this.configurationService.getValue(ToggleMenuBarAction.menuBarVisibilityKey); + let currentVisibilityValue = getMenuBarVisibility(this.configurationService, this.environmentService); if (typeof currentVisibilityValue !== 'string') { currentVisibilityValue = 'default'; } @@ -417,8 +429,10 @@ export class ToggleMenuBarAction extends Action { let newVisibilityValue: string; if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'default') { newVisibilityValue = 'toggle'; + } else if (currentVisibilityValue === 'compact') { + newVisibilityValue = 'hidden'; } else { - newVisibilityValue = 'default'; + newVisibilityValue = (isWeb && currentVisibilityValue === 'hidden') ? 'compact' : 'default'; } this.configurationService.updateValue(ToggleMenuBarAction.menuBarVisibilityKey, newVisibilityValue, ConfigurationTarget.USER); @@ -446,7 +460,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { export abstract class BaseResizeViewAction extends Action { - protected static RESIZE_INCREMENT = 6.5; // This is a media-size percentage + protected static readonly RESIZE_INCREMENT = 6.5; // This is a media-size percentage constructor( id: string, diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index d33cb450d5d..a1b64e91928 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -17,6 +17,11 @@ import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { DataTree } from 'vs/base/browser/ui/tree/dataTree'; import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; + +function isLegacyTree(widget: ListWidget): widget is ITree { + return widget instanceof Tree; +} function ensureDOMFocus(widget: ListWidget | undefined): void { // it can happen that one of the commands is executed while @@ -552,7 +557,7 @@ function listFocusFirst(accessor: ServicesAccessor, options?: { fromFocused: boo else if (focused) { const tree = focused; - tree.focusFirst({ origin: 'keyboard' }, options && options.fromFocused ? tree.getFocus() : undefined); + tree.focusFirst({ origin: 'keyboard' }, options?.fromFocused ? tree.getFocus() : undefined); tree.reveal(tree.getFocus()); } } @@ -604,7 +609,7 @@ function listFocusLast(accessor: ServicesAccessor, options?: { fromFocused: bool else if (focused) { const tree = focused; - tree.focusLast({ origin: 'keyboard' }, options && options.fromFocused ? tree.getFocus() : undefined); + tree.focusLast({ origin: 'keyboard' }, options?.fromFocused ? tree.getFocus() : undefined); tree.reveal(tree.getFocus()); } } @@ -833,3 +838,67 @@ CommandsRegistry.registerCommand({ } } }); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'list.scrollUp', + weight: KeybindingWeight.WorkbenchContrib, + when: WorkbenchListFocusContextKey, + primary: KeyMod.CtrlCmd | KeyCode.UpArrow, + handler: accessor => { + const focused = accessor.get(IListService).lastFocusedList; + + if (!focused || isLegacyTree(focused)) { + return; + } + + focused.scrollTop -= 10; + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'list.scrollDown', + weight: KeybindingWeight.WorkbenchContrib, + when: WorkbenchListFocusContextKey, + primary: KeyMod.CtrlCmd | KeyCode.DownArrow, + handler: accessor => { + const focused = accessor.get(IListService).lastFocusedList; + + if (!focused || isLegacyTree(focused)) { + return; + } + + focused.scrollTop += 10; + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'list.scrollLeft', + weight: KeybindingWeight.WorkbenchContrib, + when: WorkbenchListFocusContextKey, + primary: KeyMod.CtrlCmd | KeyCode.LeftArrow, + handler: accessor => { + const focused = accessor.get(IListService).lastFocusedList; + + if (!focused || isLegacyTree(focused)) { + return; + } + + focused.scrollLeft -= 10; + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'list.scrollRight', + weight: KeybindingWeight.WorkbenchContrib, + when: WorkbenchListFocusContextKey, + primary: KeyMod.CtrlCmd | KeyCode.RightArrow, + handler: accessor => { + const focused = accessor.get(IListService).lastFocusedList; + + if (!focused || isLegacyTree(focused)) { + return; + } + + focused.scrollLeft += 10; + } +}); diff --git a/src/vs/workbench/browser/actions/navigationActions.ts b/src/vs/workbench/browser/actions/navigationActions.ts index 621f41f00f6..fae9742c7bf 100644 --- a/src/vs/workbench/browser/actions/navigationActions.ts +++ b/src/vs/workbench/browser/actions/navigationActions.ts @@ -68,9 +68,19 @@ abstract class BaseNavigationAction extends Action { return false; } - const activePanelId = this.panelService.getActivePanel()!.getId(); + const activePanel = this.panelService.getActivePanel(); + if (!activePanel) { + return false; + } - return this.panelService.openPanel(activePanelId, true)!; + const activePanelId = activePanel.getId(); + + const res = this.panelService.openPanel(activePanelId, true); + if (!res) { + return false; + } + + return res; } protected async navigateToSidebar(): Promise { @@ -84,8 +94,8 @@ abstract class BaseNavigationAction extends Action { } const activeViewletId = activeViewlet.getId(); - const value = await this.viewletService.openViewlet(activeViewletId, true); - return value === null ? false : value; + const viewlet = await this.viewletService.openViewlet(activeViewletId, true); + return !!viewlet; } protected navigateAcrossEditorGroup(direction: GroupDirection): boolean { diff --git a/src/vs/workbench/browser/actions/textInputActions.ts b/src/vs/workbench/browser/actions/textInputActions.ts new file mode 100644 index 00000000000..b9ae0528184 --- /dev/null +++ b/src/vs/workbench/browser/actions/textInputActions.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 { IAction, Action } from 'vs/base/common/actions'; +import { localize } from 'vs/nls'; +import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { EventHelper } from 'vs/base/browser/dom'; +import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { isNative } from 'vs/base/common/platform'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; + +export class TextInputActionsProvider extends Disposable implements IWorkbenchContribution { + + private textInputActions: IAction[] = []; + + constructor( + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IContextMenuService private readonly contextMenuService: IContextMenuService, + @IClipboardService private readonly clipboardService: IClipboardService + ) { + super(); + + this.createActions(); + + this.registerListeners(); + } + + private createActions(): void { + this.textInputActions.push( + + // Undo/Redo + new Action('undo', localize('undo', "Undo"), undefined, true, async () => document.execCommand('undo')), + new Action('redo', localize('redo', "Redo"), undefined, true, async () => document.execCommand('redo')), + new Separator(), + + // Cut / Copy / Paste + new Action('editor.action.clipboardCutAction', localize('cut', "Cut"), undefined, true, async () => document.execCommand('cut')), + new Action('editor.action.clipboardCopyAction', localize('copy', "Copy"), undefined, true, async () => document.execCommand('copy')), + new Action('editor.action.clipboardPasteAction', localize('paste', "Paste"), undefined, true, async (element: HTMLInputElement | HTMLTextAreaElement) => { + + // Native: paste is supported + if (isNative) { + document.execCommand('paste'); + } + + // Web: paste is not supported due to security reasons + else { + const clipboardText = await this.clipboardService.readText(); + if ( + element instanceof HTMLTextAreaElement || + element instanceof HTMLInputElement + ) { + const selectionStart = element.selectionStart || 0; + const selectionEnd = element.selectionEnd || 0; + + element.value = `${element.value.substring(0, selectionStart)}${clipboardText}${element.value.substring(selectionEnd, element.value.length)}`; + element.selectionStart = selectionStart + clipboardText.length; + element.selectionEnd = element.selectionStart; + } + } + }), + new Separator(), + + // Select All + new Action('editor.action.selectAll', localize('selectAll', "Select All"), undefined, true, async () => document.execCommand('selectAll')) + ); + } + + private registerListeners(): void { + + // Context menu support in input/textarea + this.layoutService.container.addEventListener('contextmenu', e => this.onContextMenu(e)); + + } + + private onContextMenu(e: MouseEvent): void { + if (e.target instanceof HTMLElement) { + const target = e.target; + if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) { + EventHelper.stop(e, true); + + this.contextMenuService.showContextMenu({ + getAnchor: () => e, + getActions: () => this.textInputActions, + getActionsContext: () => target, + onHide: () => target.focus() // fixes https://github.com/Microsoft/vscode/issues/52948 + }); + } + } + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TextInputActionsProvider, LifecyclePhase.Ready); diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index 77f99572d72..c4459105483 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/actions'; import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { IWindowService, IWindowOpenable } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable } from 'vs/platform/windows/common/windows'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -21,7 +21,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { IRecentWorkspace, IRecentFolder, IRecentFile, IRecent, isRecentFolder, isRecentWorkspace } from 'vs/platform/history/common/history'; +import { IRecentWorkspace, IRecentFolder, IRecentFile, IRecent, isRecentFolder, isRecentWorkspace, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; import { FileKind } from 'vs/platform/files/common/files'; @@ -37,14 +37,14 @@ export const inRecentFilesPickerContextKey = 'inRecentFilesPicker'; abstract class BaseOpenRecentAction extends Action { private removeFromRecentlyOpened: IQuickInputButton = { - iconClass: 'action-remove-from-recently-opened', + iconClass: 'codicon-close', tooltip: nls.localize('remove', "Remove from Recently Opened") }; constructor( id: string, label: string, - private windowService: IWindowService, + private workspacesService: IWorkspacesService, private quickInputService: IQuickInputService, private contextService: IWorkspaceContextService, private labelService: ILabelService, @@ -59,7 +59,7 @@ abstract class BaseOpenRecentAction extends Action { protected abstract isQuickNavigate(): boolean; async run(): Promise { - const { workspaces, files } = await this.windowService.getRecentlyOpened(); + const { workspaces, files } = await this.workspacesService.getRecentlyOpened(); this.openRecent(workspaces, files); } @@ -129,13 +129,13 @@ abstract class BaseOpenRecentAction extends Action { onKeyMods: mods => keyMods = mods, quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined, onDidTriggerItemButton: async context => { - await this.windowService.removeFromRecentlyOpened([context.item.resource]); + await this.workspacesService.removeFromRecentlyOpened([context.item.resource]); context.removeItem(); } }); if (pick) { - return this.hostService.openInWindow([pick.openable], { forceNewWindow: keyMods && keyMods.ctrlCmd }); + return this.hostService.openWindow([pick.openable], { forceNewWindow: keyMods?.ctrlCmd }); } } } @@ -148,7 +148,7 @@ export class OpenRecentAction extends BaseOpenRecentAction { constructor( id: string, label: string, - @IWindowService windowService: IWindowService, + @IWorkspacesService workspacesService: IWorkspacesService, @IQuickInputService quickInputService: IQuickInputService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IKeybindingService keybindingService: IKeybindingService, @@ -157,7 +157,7 @@ export class OpenRecentAction extends BaseOpenRecentAction { @ILabelService labelService: ILabelService, @IHostService hostService: IHostService ) { - super(id, label, windowService, quickInputService, contextService, labelService, keybindingService, modelService, modeService, hostService); + super(id, label, workspacesService, quickInputService, contextService, labelService, keybindingService, modelService, modeService, hostService); } protected isQuickNavigate(): boolean { @@ -173,7 +173,7 @@ class QuickOpenRecentAction extends BaseOpenRecentAction { constructor( id: string, label: string, - @IWindowService windowService: IWindowService, + @IWorkspacesService workspacesService: IWorkspacesService, @IQuickInputService quickInputService: IQuickInputService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IKeybindingService keybindingService: IKeybindingService, @@ -182,7 +182,7 @@ class QuickOpenRecentAction extends BaseOpenRecentAction { @ILabelService labelService: ILabelService, @IHostService hostService: IHostService ) { - super(id, label, windowService, quickInputService, contextService, labelService, keybindingService, modelService, modeService, hostService); + super(id, label, workspacesService, quickInputService, contextService, labelService, keybindingService, modelService, modeService, hostService); } protected isQuickNavigate(): boolean { @@ -193,7 +193,7 @@ class QuickOpenRecentAction extends BaseOpenRecentAction { class ToggleFullScreenAction extends Action { static readonly ID = 'workbench.action.toggleFullScreen'; - static LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen"); + static readonly LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen"); constructor( id: string, @@ -211,7 +211,7 @@ class ToggleFullScreenAction extends Action { export class ReloadWindowAction extends Action { static readonly ID = 'workbench.action.reloadWindow'; - static LABEL = nls.localize('reloadWindow', "Reload Window"); + static readonly LABEL = nls.localize('reloadWindow', "Reload Window"); constructor( id: string, @@ -249,7 +249,7 @@ class ShowAboutDialogAction extends Action { export class NewWindowAction extends Action { static readonly ID = 'workbench.action.newWindow'; - static LABEL = nls.localize('newWindow', "New Window"); + static readonly LABEL = nls.localize('newWindow', "New Window"); constructor( id: string, @@ -260,7 +260,7 @@ export class NewWindowAction extends Action { } run(): Promise { - return this.hostService.openEmptyWindow(); + return this.hostService.openWindow(); } } diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 8bfd8f54b5d..0834621124a 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -7,13 +7,13 @@ import { Action } from 'vs/base/common/actions'; import * as nls from 'vs/nls'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { MenuRegistry, MenuId, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { WorkbenchStateContext, SupportsWorkspacesContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; +import { WorkbenchStateContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; @@ -21,11 +21,13 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IHostService } from 'vs/workbench/services/host/browser/host'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; export class OpenFileAction extends Action { static readonly ID = 'workbench.action.files.openFile'; - static LABEL = nls.localize('openFile', "Open File..."); + static readonly LABEL = nls.localize('openFile', "Open File..."); constructor( id: string, @@ -43,7 +45,7 @@ export class OpenFileAction extends Action { export class OpenFolderAction extends Action { static readonly ID = 'workbench.action.files.openFolder'; - static LABEL = nls.localize('openFolder', "Open Folder..."); + static readonly LABEL = nls.localize('openFolder', "Open Folder..."); constructor( id: string, @@ -61,7 +63,7 @@ export class OpenFolderAction extends Action { export class OpenFileFolderAction extends Action { static readonly ID = 'workbench.action.files.openFileFolder'; - static LABEL = nls.localize('openFileFolder', "Open..."); + static readonly LABEL = nls.localize('openFileFolder', "Open..."); constructor( id: string, @@ -79,7 +81,7 @@ export class OpenFileFolderAction extends Action { export class OpenWorkspaceAction extends Action { static readonly ID = 'workbench.action.openWorkspace'; - static LABEL = nls.localize('openWorkspaceAction', "Open Workspace..."); + static readonly LABEL = nls.localize('openWorkspaceAction', "Open Workspace..."); constructor( id: string, @@ -97,14 +99,15 @@ export class OpenWorkspaceAction extends Action { export class CloseWorkspaceAction extends Action { static readonly ID = 'workbench.action.closeFolder'; - static LABEL = nls.localize('closeWorkspace', "Close Workspace"); + static readonly LABEL = nls.localize('closeWorkspace', "Close Workspace"); constructor( id: string, label: string, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @INotificationService private readonly notificationService: INotificationService, - @IHostService private readonly hostService: IHostService + @IHostService private readonly hostService: IHostService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { super(id, label); } @@ -116,7 +119,7 @@ export class CloseWorkspaceAction extends Action { return Promise.resolve(undefined); } - return this.hostService.closeWorkspace(); + return this.hostService.openWindow({ forceReuseWindow: true, remoteAuthority: this.environmentService.configuration.remoteAuthority }); } } @@ -148,7 +151,7 @@ export class OpenWorkspaceConfigFileAction extends Action { export class AddRootFolderAction extends Action { static readonly ID = 'workbench.action.addRootFolder'; - static LABEL = ADD_ROOT_FOLDER_LABEL; + static readonly LABEL = ADD_ROOT_FOLDER_LABEL; constructor( id: string, @@ -166,7 +169,7 @@ export class AddRootFolderAction extends Action { export class GlobalRemoveRootFolderAction extends Action { static readonly ID = 'workbench.action.removeRootFolder'; - static LABEL = nls.localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace..."); + static readonly LABEL = nls.localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace..."); constructor( id: string, @@ -193,14 +196,74 @@ export class GlobalRemoveRootFolderAction extends Action { } } +export class SaveWorkspaceAsAction extends Action { + + static readonly ID = 'workbench.action.saveWorkspaceAs'; + static readonly LABEL = nls.localize('saveWorkspaceAsAction', "Save Workspace As..."); + + constructor( + id: string, + label: string, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService + + ) { + super(id, label); + } + + async run(): Promise { + const configPathUri = await this.workspaceEditingService.pickNewWorkspacePath(); + if (configPathUri) { + switch (this.contextService.getWorkbenchState()) { + case WorkbenchState.EMPTY: + case WorkbenchState.FOLDER: + const folders = this.contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri })); + return this.workspaceEditingService.createAndEnterWorkspace(folders, configPathUri); + case WorkbenchState.WORKSPACE: + return this.workspaceEditingService.saveAndEnterWorkspace(configPathUri); + } + } + } +} + +export class DuplicateWorkspaceInNewWindowAction extends Action { + + static readonly ID = 'workbench.action.duplicateWorkspaceInNewWindow'; + static readonly LABEL = nls.localize('duplicateWorkspaceInNewWindow', "Duplicate Workspace in New Window"); + + constructor( + id: string, + label: string, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, + @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, + @IHostService private readonly hostService: IHostService, + @IWorkspacesService private readonly workspacesService: IWorkspacesService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService + ) { + super(id, label); + } + + async run(): Promise { + const folders = this.workspaceContextService.getWorkspace().folders; + const remoteAuthority = this.environmentService.configuration.remoteAuthority; + + const newWorkspace = await this.workspacesService.createUntitledWorkspace(folders, remoteAuthority); + await this.workspaceEditingService.copyWorkspaceSettings(newWorkspace); + + return this.hostService.openWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true }); + } +} + // --- Actions Registration const registry = Registry.as(Extensions.WorkbenchActions); const workspacesCategory = nls.localize('workspaces', "Workspaces"); -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, SupportsWorkspacesContext); -registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', workspacesCategory, SupportsWorkspacesContext); +registry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'Workspaces: Close Workspace', workspacesCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory); // --- Menu Registration @@ -214,8 +277,16 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { id: ADD_ROOT_FOLDER_COMMAND_ID, title: nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...") }, - order: 1, - when: SupportsWorkspacesContext + order: 1 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '3_workspace', + command: { + id: SaveWorkspaceAsAction.ID, + title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...") + }, + order: 2 }); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { @@ -244,5 +315,5 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { title: nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace") }, order: 3, - when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), SupportsWorkspacesContext) + when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace')) }); diff --git a/src/vs/workbench/browser/actions/workspaceCommands.ts b/src/vs/workbench/browser/actions/workspaceCommands.ts index f8ea5408e58..25217e6470c 100644 --- a/src/vs/workbench/browser/actions/workspaceCommands.ts +++ b/src/vs/workbench/browser/actions/workspaceCommands.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import * as resources from 'vs/base/common/resources'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { CancellationToken } from 'vs/base/common/cancellation'; diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index 1c8f30a8f20..6414496a6d3 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -14,6 +14,8 @@ import { IConstructorSignature0, IInstantiationService } from 'vs/platform/insta import { trackFocus, Dimension } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { Disposable } from 'vs/base/common/lifecycle'; +import { assertIsDefined } from 'vs/base/common/types'; +import { find } from 'vs/base/common/arrays'; /** * Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite @@ -35,10 +37,10 @@ export abstract class Composite extends Component implements IComposite { private readonly _onDidChangeVisibility: Emitter = this._register(new Emitter()); readonly onDidChangeVisibility: Event = this._onDidChangeVisibility.event; - private _onDidFocus!: Emitter; + private _onDidFocus: Emitter | undefined; get onDidFocus(): Event { if (!this._onDidFocus) { - this.registerFocusTrackEvents(); + this._onDidFocus = this.registerFocusTrackEvents().onDidFocus; } return this._onDidFocus.event; @@ -50,28 +52,32 @@ export abstract class Composite extends Component implements IComposite { } } - private _onDidBlur!: Emitter; + private _onDidBlur: Emitter | undefined; get onDidBlur(): Event { if (!this._onDidBlur) { - this.registerFocusTrackEvents(); + this._onDidBlur = this.registerFocusTrackEvents().onDidBlur; } return this._onDidBlur.event; } - private registerFocusTrackEvents(): void { - this._onDidFocus = this._register(new Emitter()); - this._onDidBlur = this._register(new Emitter()); + private registerFocusTrackEvents(): { onDidFocus: Emitter, onDidBlur: Emitter } { + const container = assertIsDefined(this.getContainer()); + const focusTracker = this._register(trackFocus(container)); - const focusTracker = this._register(trackFocus(this.getContainer())); - this._register(focusTracker.onDidFocus(() => this._onDidFocus.fire())); - this._register(focusTracker.onDidBlur(() => this._onDidBlur.fire())); + const onDidFocus = this._onDidFocus = this._register(new Emitter()); + this._register(focusTracker.onDidFocus(() => onDidFocus.fire())); + + const onDidBlur = this._onDidBlur = this._register(new Emitter()); + this._register(focusTracker.onDidBlur(() => onDidBlur.fire())); + + return { onDidFocus, onDidBlur }; } protected actionRunner: IActionRunner | undefined; private visible: boolean; - private parent!: HTMLElement; + private parent: HTMLElement | undefined; constructor( id: string, @@ -112,7 +118,7 @@ export abstract class Composite extends Component implements IComposite { /** * Returns the container this composite is being build in. */ - getContainer(): HTMLElement { + getContainer(): HTMLElement | undefined { return this.parent; } @@ -253,7 +259,7 @@ export abstract class CompositeRegistry extends Disposable private composites: CompositeDescriptor[] = []; protected registerComposite(descriptor: CompositeDescriptor): void { - if (this.compositeById(descriptor.id) !== null) { + if (this.compositeById(descriptor.id)) { return; } @@ -271,7 +277,7 @@ export abstract class CompositeRegistry extends Disposable this._onDidDeregister.fire(descriptor); } - getComposite(id: string): CompositeDescriptor | null { + getComposite(id: string): CompositeDescriptor | undefined { return this.compositeById(id); } @@ -279,13 +285,7 @@ export abstract class CompositeRegistry extends Disposable return this.composites.slice(0); } - private compositeById(id: string): CompositeDescriptor | null { - for (const composite of this.composites) { - if (composite.id === id) { - return composite; - } - } - - return null; + private compositeById(id: string): CompositeDescriptor | undefined { + return find(this.composites, composite => composite.id === id); } } diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 34640af8e1e..d45fe4e74e7 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys'; import { IWindowsConfiguration } from 'vs/platform/windows/common/windows'; -import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorIsSaveableContext, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; +import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorIsSaveableContext, toResource, SideBySideEditor, EditorAreaVisibleContext } from 'vs/workbench/common/editor'; import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom'; import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -38,8 +38,6 @@ export const RemoteConnectionState = new RawContextKey<'' | 'initializing' | 'di export const HasMacNativeTabsContext = new RawContextKey('hasMacNativeTabs', false); -export const SupportsWorkspacesContext = new RawContextKey('supportsWorkspaces', true); - export const IsDevelopmentContext = new RawContextKey('isDevelopment', false); export const WorkbenchStateContext = new RawContextKey('workbenchState', undefined); @@ -73,6 +71,7 @@ export class WorkbenchContextKeysHandler extends Disposable { private isFullscreenContext: IContextKey; private isCenteredLayoutContext: IContextKey; private sideBarVisibleContext: IContextKey; + private editorAreaVisibleContext: IContextKey; private panelPositionContext: IContextKey; constructor( @@ -88,41 +87,6 @@ export class WorkbenchContextKeysHandler extends Disposable { ) { super(); - this.initContextKeys(); - this.registerListeners(); - } - - private registerListeners(): void { - this.editorGroupService.whenRestored.then(() => this.updateEditorContextKeys()); - - this._register(this.editorService.onDidActiveEditorChange(() => this.updateEditorContextKeys())); - this._register(this.editorService.onDidVisibleEditorsChange(() => this.updateEditorContextKeys())); - - this._register(this.editorGroupService.onDidAddGroup(() => this.updateEditorContextKeys())); - this._register(this.editorGroupService.onDidRemoveGroup(() => this.updateEditorContextKeys())); - this._register(this.editorGroupService.onDidGroupIndexChange(() => this.updateEditorContextKeys())); - - this._register(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(), true)); - - this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateWorkbenchStateContextKey())); - this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.updateWorkspaceFolderCountContextKey())); - - this._register(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) { - this.updateSplitEditorsVerticallyContext(); - } - })); - - this._register(this.layoutService.onZenModeChange(enabled => this.inZenModeContext.set(enabled))); - this._register(this.layoutService.onFullscreenChange(fullscreen => this.isFullscreenContext.set(fullscreen))); - this._register(this.layoutService.onCenteredLayoutChange(centered => this.isCenteredLayoutContext.set(centered))); - this._register(this.layoutService.onPanelPositionChange(position => this.panelPositionContext.set(position))); - - this._register(this.viewletService.onDidViewletClose(() => this.updateSideBarContextKeys())); - this._register(this.viewletService.onDidViewletOpen(() => this.updateSideBarContextKeys())); - } - - private initContextKeys(): void { // Platform IsMacContext.bindTo(this.contextKeyService); @@ -136,16 +100,11 @@ export class WorkbenchContextKeysHandler extends Disposable { // macOS Native Tabs const windowConfig = this.configurationService.getValue(); - HasMacNativeTabsContext.bindTo(this.contextKeyService).set(windowConfig && windowConfig.window && windowConfig.window.nativeTabs); + HasMacNativeTabsContext.bindTo(this.contextKeyService).set(windowConfig?.window?.nativeTabs); // Development IsDevelopmentContext.bindTo(this.contextKeyService).set(!this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment); - // Workspaces Support - // - web: only if already in workspace state - // - desktop: always - SupportsWorkspacesContext.bindTo(this.contextKeyService).set(isWeb ? this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE : true); - // Editors this.activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService); this.activeEditorIsSaveable = ActiveEditorIsSaveableContext.bindTo(this.contextKeyService); @@ -181,12 +140,49 @@ export class WorkbenchContextKeysHandler extends Disposable { // Centered Layout this.isCenteredLayoutContext = IsCenteredLayoutContext.bindTo(this.contextKeyService); + // Editor Area + this.editorAreaVisibleContext = EditorAreaVisibleContext.bindTo(this.contextKeyService); + // Sidebar this.sideBarVisibleContext = SideBarVisibleContext.bindTo(this.contextKeyService); // Panel Position this.panelPositionContext = PanelPositionContext.bindTo(this.contextKeyService); this.panelPositionContext.set(this.layoutService.getPanelPosition() === Position.RIGHT ? 'right' : 'bottom'); + + this.registerListeners(); + } + + private registerListeners(): void { + this.editorGroupService.whenRestored.then(() => this.updateEditorContextKeys()); + + this._register(this.editorService.onDidActiveEditorChange(() => this.updateEditorContextKeys())); + this._register(this.editorService.onDidVisibleEditorsChange(() => this.updateEditorContextKeys())); + + this._register(this.editorGroupService.onDidAddGroup(() => this.updateEditorContextKeys())); + this._register(this.editorGroupService.onDidRemoveGroup(() => this.updateEditorContextKeys())); + this._register(this.editorGroupService.onDidGroupIndexChange(() => this.updateEditorContextKeys())); + + this._register(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(), true)); + + this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateWorkbenchStateContextKey())); + this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.updateWorkspaceFolderCountContextKey())); + + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) { + this.updateSplitEditorsVerticallyContext(); + } + })); + + this._register(this.layoutService.onZenModeChange(enabled => this.inZenModeContext.set(enabled))); + this._register(this.layoutService.onFullscreenChange(fullscreen => this.isFullscreenContext.set(fullscreen))); + this._register(this.layoutService.onCenteredLayoutChange(centered => this.isCenteredLayoutContext.set(centered))); + this._register(this.layoutService.onPanelPositionChange(position => this.panelPositionContext.set(position))); + + this._register(this.viewletService.onDidViewletClose(() => this.updateSideBarContextKeys())); + this._register(this.viewletService.onDidViewletOpen(() => this.updateSideBarContextKeys())); + + this._register(this.layoutService.onPartVisibilityChange(() => this.editorAreaVisibleContext.set(this.layoutService.isVisible(Parts.EDITOR_PART)))); } private updateEditorContextKeys(): void { @@ -194,7 +190,7 @@ export class WorkbenchContextKeysHandler extends Disposable { const activeControl = this.editorService.activeControl; const visibleEditors = this.editorService.visibleControls; - this.textCompareEditorActiveContext.set(!!activeControl && activeControl.getId() === TEXT_DIFF_EDITOR_ID); + this.textCompareEditorActiveContext.set(activeControl?.getId() === TEXT_DIFF_EDITOR_ID); this.textCompareEditorVisibleContext.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID)); if (visibleEditors.length > 0) { diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 4f5e092c46e..9b75bfa7da4 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { hasWorkspaceFileExtension, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; +import { hasWorkspaceFileExtension, IWorkspaceFolderCreationData, IRecentFile, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { normalize } from 'vs/base/common/path'; import { basename } from 'vs/base/common/resources'; import { IFileService } from 'vs/platform/files/common/files'; -import { IWindowService, IWindowOpenable } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -20,19 +20,18 @@ import { DataTransfers } from 'vs/base/browser/dnd'; import { DragMouseEvent } from 'vs/base/browser/mouseEvent'; import { normalizeDriveLetter } from 'vs/base/common/labels'; import { MIME_BINARY } from 'vs/base/common/mime'; -import { isWindows, isLinux, isWeb } from 'vs/base/common/platform'; +import { isWindows, isWeb } from 'vs/base/common/platform'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorIdentifier, GroupIdentifier } from 'vs/workbench/common/editor'; import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; import { Disposable } from 'vs/base/common/lifecycle'; -import { addDisposableListener, EventType } from 'vs/base/browser/dom'; +import { addDisposableListener, EventType, asDomUri } from 'vs/base/browser/dom'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IRecentFile } from 'vs/platform/history/common/history'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { withNullAsUndefined } from 'vs/base/common/types'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { isStandalone } from 'vs/base/browser/browser'; export interface IDraggedResource { resource: URI; @@ -114,7 +113,7 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array r.resource.fsPath === file.path) /* prevent duplicates */) { + if (file?.path /* Electron only */ && !resources.some(r => r.resource.fsPath === file.path) /* prevent duplicates */) { try { resources.push({ resource: URI.file(file.path), isExternal: true }); } catch (error) { @@ -161,7 +160,7 @@ export class ResourcesDropHandler { constructor( private options: IResourcesDropHandlerOptions, @IFileService private readonly fileService: IFileService, - @IWindowService private readonly windowService: IWindowService, + @IWorkspacesService private readonly workspacesService: IWorkspacesService, @ITextFileService private readonly textFileService: ITextFileService, @IBackupFileService private readonly backupFileService: IBackupFileService, @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, @@ -189,9 +188,9 @@ export class ResourcesDropHandler { } // Add external ones to recently open list unless dropped resource is a workspace - const recents: IRecentFile[] = untitledOrFileResources.filter(d => d.isExternal && d.resource.scheme === Schemas.file).map(d => ({ fileUri: d.resource })); - if (recents.length) { - this.windowService.addRecentlyOpened(recents); + const recentFiles: IRecentFile[] = untitledOrFileResources.filter(d => d.isExternal && d.resource.scheme === Schemas.file).map(d => ({ fileUri: d.resource })); + if (recentFiles.length) { + this.workspacesService.addRecentlyOpened(recentFiles); } const editors: IResourceEditor[] = untitledOrFileResources.map(untitledOrFileResource => ({ @@ -244,11 +243,13 @@ export class ResourcesDropHandler { } // Resolve the contents of the dropped dirty resource from source - try { - const content = await this.backupFileService.resolveBackupContent((droppedDirtyEditor.backupResource!)); - await this.backupFileService.backupResource(droppedDirtyEditor.resource, content.value.create(this.getDefaultEOL()).createSnapshot(true)); - } catch (e) { - // Ignore error + if (droppedDirtyEditor.backupResource) { + try { + const content = await this.backupFileService.resolveBackupContent((droppedDirtyEditor.backupResource)); + await this.backupFileService.backupResource(droppedDirtyEditor.resource, content.value.create(this.getDefaultEOL()).createSnapshot(true)); + } catch (e) { + // Ignore error + } } return false; @@ -298,7 +299,7 @@ export class ResourcesDropHandler { // Open in separate windows if we drop workspaces or just one folder if (toOpen.length > folderURIs.length || folderURIs.length === 1) { - await this.hostService.openInWindow(toOpen, { forceReuseWindow: true }); + await this.hostService.openWindow(toOpen, { forceReuseWindow: true }); } // folders.length > 1: Multiple folders: Create new workspace with folders and open @@ -323,20 +324,14 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources: return obj; }); - const firstSource = sources[0]; - // Text: allows to paste into text-capable areas const lineDelimiter = isWindows ? '\r\n' : '\n'; event.dataTransfer.setData(DataTransfers.TEXT, sources.map(source => source.resource.scheme === Schemas.file ? normalize(normalizeDriveLetter(source.resource.fsPath)) : source.resource.toString()).join(lineDelimiter)); - const envService = accessor.get(IWorkbenchEnvironmentService); - const hasRemote = !!envService.configuration.remoteAuthority; - if ( - !(isLinux && hasRemote) && // Not supported on linux remote due to chrome limitation https://github.com/microsoft/vscode-remote-release/issues/849 - !isWeb // Does not seem to work anymore when running from web, the file ends up being empty (and PWA crashes) - ) { - // Download URL: enables support to drag a tab as file to desktop (only single file supported) - event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(firstSource.resource), firstSource.resource.toString()].join(':')); + // Download URL: enables support to drag a tab as file to desktop (only single file supported) + // Disabled for PWA web due to: https://github.com/microsoft/vscode/issues/83441 + if (!sources[0].isDirectory && (!isWeb || !isStandalone)) { + event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(sources[0].resource), asDomUri(sources[0].resource).toString()].join(':')); } // Resource URLs: allows to drop multiple resources to a target in VS Code (not directories) @@ -359,7 +354,7 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources: for (const textEditorWidget of textEditorWidgets) { if (isCodeEditor(textEditorWidget)) { const model = textEditorWidget.getModel(); - if (model && model.uri && model.uri.toString() === file.resource.toString()) { + if (model?.uri?.toString() === file.resource.toString()) { viewState = textEditorWidget.saveViewState(); break; } @@ -481,3 +476,23 @@ export class DragAndDropObserver extends Disposable { })); } } + +export function containsDragType(event: DragEvent, ...dragTypesToFind: string[]): boolean { + if (!event.dataTransfer) { + return false; + } + + const dragTypes = event.dataTransfer.types; + const lowercaseDragTypes: string[] = []; + for (let i = 0; i < dragTypes.length; i++) { + lowercaseDragTypes.push(dragTypes[i].toLowerCase()); // somehow the types are lowercase + } + + for (const dragType of dragTypesToFind) { + if (lowercaseDragTypes.indexOf(dragType.toLowerCase()) >= 0) { + return true; + } + } + + return false; +} diff --git a/src/vs/workbench/browser/editor.ts b/src/vs/workbench/browser/editor.ts index a8b4de85142..d441fb2f0d9 100644 --- a/src/vs/workbench/browser/editor.ts +++ b/src/vs/workbench/browser/editor.ts @@ -8,6 +8,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { Registry } from 'vs/platform/registry/common/platform'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IConstructorSignature0, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { find } from 'vs/base/common/arrays'; export interface IEditorDescriptor { instantiate(instantiationService: IInstantiationService): BaseEditor; @@ -140,13 +141,7 @@ class EditorRegistry implements IEditorRegistry { } getEditorById(editorId: string): EditorDescriptor | undefined { - for (const editor of this.editors) { - if (editor.getId() === editorId) { - return editor; - } - } - - return undefined; + return find(this.editors, editor => editor.getId() === editorId); } getEditors(): readonly EditorDescriptor[] { diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 2b5d9be8790..f547fb72eee 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -22,7 +22,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Event, Emitter } from 'vs/base/common/event'; import { ILabelService } from 'vs/platform/label/common/label'; import { getIconClasses, detectModeId } from 'vs/editor/common/services/getIconClasses'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { withNullAsUndefined } from 'vs/base/common/types'; @@ -211,7 +211,7 @@ export class ResourceLabel extends ResourceLabels { constructor( container: HTMLElement, - options: IIconLabelCreationOptions, + options: IIconLabelCreationOptions | undefined, @IInstantiationService instantiationService: IInstantiationService, @IExtensionService extensionService: IExtensionService, @IConfigurationService configurationService: IConfigurationService, @@ -241,6 +241,8 @@ class ResourceLabelWidget extends IconLabel { private _onDidRender = this._register(new Emitter()); readonly onDidRender: Event = this._onDidRender.event; + private readonly renderDisposables = this._register(new DisposableStore()); + private label?: IResourceLabelProps; private options?: IResourceLabelOptions; private computedIconClasses?: string[]; @@ -252,7 +254,7 @@ class ResourceLabelWidget extends IconLabel { constructor( container: HTMLElement, - options: IIconLabelCreationOptions, + options: IIconLabelCreationOptions | undefined, @IModeService private readonly modeService: IModeService, @IModelService private readonly modelService: IModelService, @IDecorationsService private readonly decorationsService: IDecorationsService, @@ -434,7 +436,9 @@ class ResourceLabelWidget extends IconLabel { return; } - const iconLabelOptions: IIconLabelValueOptions = { + this.renderDisposables.clear(); + + const iconLabelOptions: IIconLabelValueOptions & { extraClasses: string[] } = { title: '', italic: this.options && this.options.italic, matches: this.options && this.options.matches, @@ -462,7 +466,7 @@ class ResourceLabelWidget extends IconLabel { } if (this.options && this.options.extraClasses) { - iconLabelOptions.extraClasses!.push(...this.options.extraClasses); + iconLabelOptions.extraClasses.push(...this.options.extraClasses); } if (this.options && this.options.fileDecorations && resource) { @@ -472,16 +476,19 @@ class ResourceLabelWidget extends IconLabel { ); if (deco) { + + this.renderDisposables.add(deco); + if (deco.tooltip) { iconLabelOptions.title = `${iconLabelOptions.title} • ${deco.tooltip}`; } if (this.options.fileDecorations.colors) { - iconLabelOptions.extraClasses!.push(deco.labelClassName); + iconLabelOptions.extraClasses.push(deco.labelClassName); } if (this.options.fileDecorations.badges) { - iconLabelOptions.extraClasses!.push(deco.badgeClassName); + iconLabelOptions.extraClasses.push(deco.badgeClassName); } } } diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 53f8d57c4b4..24ebadeba87 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -5,7 +5,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size, EventHelper, Dimension } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, Dimension, toggleClass } from 'vs/base/browser/dom'; import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -21,9 +21,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { LifecyclePhase, StartupKind, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows'; +import { MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; @@ -31,14 +31,17 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { SerializableGrid, ISerializableView, ISerializedGrid, Orientation, ISerializedNode, ISerializedLeafNode, Direction, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; -import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarService } from 'vs/workbench/services/statusbar/common/statusbar'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { IFileService } from 'vs/platform/files/common/files'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { coalesce } from 'vs/base/common/arrays'; +import { assertIsDefined } from 'vs/base/common/types'; +import { INotificationService, NotificationsFilter } from 'vs/platform/notification/common/notification'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { WINDOW_ACTIVE_BORDER, WINDOW_INACTIVE_BORDER } from 'vs/workbench/common/theme'; enum Settings { - MENUBAR_VISIBLE = 'window.menuBarVisibility', ACTIVITYBAR_VISIBLE = 'workbench.activityBar.visible', STATUSBAR_VISIBLE = 'workbench.statusBar.visible', @@ -46,9 +49,6 @@ enum Settings { PANEL_POSITION = 'workbench.panel.defaultLocation', ZEN_MODE_RESTORE = 'zenMode.restore', - - // TODO @misolori update this when finished - OCTICONS_UPDATE_ENABLED = 'workbench.octiconsUpdate.enabled', } enum Storage { @@ -76,7 +76,8 @@ enum Classes { EDITOR_HIDDEN = 'noeditorarea', PANEL_HIDDEN = 'nopanel', STATUSBAR_HIDDEN = 'nostatusbar', - FULLSCREEN = 'fullscreen' + FULLSCREEN = 'fullscreen', + WINDOW_BORDER = 'border' } export abstract class Layout extends Disposable implements IWorkbenchLayoutService { @@ -85,9 +86,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi //#region Events - private readonly _onTitleBarVisibilityChange: Emitter = this._register(new Emitter()); - readonly onTitleBarVisibilityChange: Event = this._onTitleBarVisibilityChange.event; - private readonly _onZenModeChange: Emitter = this._register(new Emitter()); readonly onZenModeChange: Event = this._onZenModeChange.event; @@ -100,12 +98,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi private readonly _onPanelPositionChange: Emitter = this._register(new Emitter()); readonly onPanelPositionChange: Event = this._onPanelPositionChange.event; + private readonly _onPartVisibilityChange: Emitter = this._register(new Emitter()); + readonly onPartVisibilityChange: Event = this._onPartVisibilityChange.event; + private readonly _onLayout = this._register(new Emitter()); readonly onLayout: Event = this._onLayout.event; //#endregion - private _dimension: IDimension; + private _dimension!: IDimension; get dimension(): IDimension { return this._dimension; } private _container: HTMLElement = document.createElement('div'); @@ -113,32 +114,36 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi private parts: Map = new Map(); - private workbenchGrid: SerializableGrid; + private workbenchGrid!: SerializableGrid; - private disposed: boolean; + private disposed: boolean | undefined; - private titleBarPartView: ISerializableView; - private activityBarPartView: ISerializableView; - private sideBarPartView: ISerializableView; - private panelPartView: ISerializableView; - private editorPartView: ISerializableView; - private statusBarPartView: ISerializableView; + private titleBarPartView!: ISerializableView; + private activityBarPartView!: ISerializableView; + private sideBarPartView!: ISerializableView; + private panelPartView!: ISerializableView; + private editorPartView!: ISerializableView; + private statusBarPartView!: ISerializableView; - private environmentService: IWorkbenchEnvironmentService; - private configurationService: IConfigurationService; - private lifecycleService: ILifecycleService; - private storageService: IStorageService; - private hostService: IHostService; - private editorService: IEditorService; - private editorGroupService: IEditorGroupsService; - private panelService: IPanelService; - private titleService: ITitleService; - private viewletService: IViewletService; - private contextService: IWorkspaceContextService; - private backupFileService: IBackupFileService; + private environmentService!: IWorkbenchEnvironmentService; + private configurationService!: IConfigurationService; + private lifecycleService!: ILifecycleService; + private storageService!: IStorageService; + private hostService!: IHostService; + private editorService!: IEditorService; + private editorGroupService!: IEditorGroupsService; + private panelService!: IPanelService; + private titleService!: ITitleService; + private viewletService!: IViewletService; + private contextService!: IWorkspaceContextService; + private backupFileService!: IBackupFileService; + private notificationService!: INotificationService; + private themeService!: IThemeService; protected readonly state = { fullscreen: false, + hasFocus: false, + windowBorder: false, menuBar: { visibility: 'default' as MenuBarVisibility, @@ -183,13 +188,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi transitionedToCenteredEditorLayout: false, wasSideBarVisible: false, wasPanelVisible: false, - transitionDisposables: new DisposableStore() + transitionDisposables: new DisposableStore(), + setNotificationsFilter: false }, - // TODO @misolori update this when finished - octiconsUpdate: { - enabled: false - } }; constructor( @@ -208,6 +210,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.contextService = accessor.get(IWorkspaceContextService); this.storageService = accessor.get(IStorageService); this.backupFileService = accessor.get(IBackupFileService); + this.themeService = accessor.get(IThemeService); // Parts this.editorService = accessor.get(IEditorService); @@ -215,6 +218,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.panelService = accessor.get(IPanelService); this.viewletService = accessor.get(IViewletService); this.titleService = accessor.get(ITitleService); + this.notificationService = accessor.get(INotificationService); accessor.get(IStatusbarService); // not used, but called to ensure instantiated accessor.get(IActivityBarService); // not used, but called to ensure instantiated @@ -256,15 +260,16 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Prevent workbench from scrolling #55456 this._register(addDisposableListener(this.container, EventType.SCROLL, () => this.container.scrollTop = 0)); - // Prevent native context menus in web #73781 - if (isWeb) { - this._register(addDisposableListener(this.container, EventType.CONTEXT_MENU, (e) => EventHelper.stop(e, true))); - } - // Menubar visibility changes if ((isWindows || isLinux || isWeb) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { this._register(this.titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible))); } + + // Theme changes + this._register(this.themeService.onThemeChange(theme => this.updateStyles())); + + // Window focus changes + this._register(this.hostService.onDidChangeFocus(e => this.onWindowFocusChanged(e))); } private onMenubarToggled(visible: boolean) { @@ -272,8 +277,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.state.menuBar.toggled = visible; if (this.state.fullscreen && (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default')) { - this._onTitleBarVisibilityChange.fire(); - // Propagate to grid this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART)); @@ -298,8 +301,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { - this._onTitleBarVisibilityChange.fire(); - // Propagate to grid this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART)); @@ -309,6 +310,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this._onFullscreenChange.fire(this.state.fullscreen); } + private onWindowFocusChanged(hasFocus: boolean): void { + if (this.state.hasFocus === hasFocus) { + return; + } + + this.state.hasFocus = hasFocus; + this.updateWindowBorder(); + } + private doUpdateLayoutConfiguration(skipLayout?: boolean): void { // Sidebar position @@ -337,13 +347,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } // Menubar visibility - const newMenubarVisibility = this.configurationService.getValue(Settings.MENUBAR_VISIBLE); + const newMenubarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService); this.setMenubarVisibility(newMenubarVisibility, !!skipLayout); - // TODO @misolori update this when finished - const newOcticonsUpdate = this.configurationService.getValue(Settings.OCTICONS_UPDATE_ENABLED); - this.setOcticonsUpdate(newOcticonsUpdate); - } private setSideBarPosition(position: Position): void { @@ -355,10 +361,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.state.sideBar.position = position; // Adjust CSS - removeClass(activityBar.getContainer(), oldPositionValue); - removeClass(sideBar.getContainer(), oldPositionValue); - addClass(activityBar.getContainer(), newPositionValue); - addClass(sideBar.getContainer(), newPositionValue); + const activityBarContainer = assertIsDefined(activityBar.getContainer()); + const sideBarContainer = assertIsDefined(sideBar.getContainer()); + removeClass(activityBarContainer, oldPositionValue); + removeClass(sideBarContainer, oldPositionValue); + addClass(activityBarContainer, newPositionValue); + addClass(sideBarContainer, newPositionValue); // Update Styles activityBar.updateStyles(); @@ -380,13 +388,51 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.layout(); } + private updateWindowBorder(skipLayout: boolean = false) { + if (isWeb || getTitleBarStyle(this.configurationService, this.environmentService) !== 'custom') { + return; + } + + const theme = this.themeService.getTheme(); + + const activeBorder = theme.getColor(WINDOW_ACTIVE_BORDER); + const inactiveBorder = theme.getColor(WINDOW_INACTIVE_BORDER); + + let windowBorder = false; + if (activeBorder || inactiveBorder) { + windowBorder = true; + + // If one color is missing, just fallback to the other one + const borderColor = this.state.hasFocus + ? activeBorder ?? inactiveBorder + : inactiveBorder ?? activeBorder; + this.container.style.setProperty('--window-border-color', borderColor ? borderColor.toString() : 'transparent'); + } + + if (windowBorder === this.state.windowBorder) { + return; + } + + this.state.windowBorder = windowBorder; + + toggleClass(this.container, Classes.WINDOW_BORDER, windowBorder); + + if (!skipLayout) { + this.layout(); + } + } + + private updateStyles() { + this.updateWindowBorder(); + } + private initLayoutState(lifecycleService: ILifecycleService, fileService: IFileService): void { // Fullscreen this.state.fullscreen = isFullscreen(); // Menubar visibility - this.state.menuBar.visibility = this.configurationService.getValue(Settings.MENUBAR_VISIBLE); + this.state.menuBar.visibility = getMenuBarVisibility(this.configurationService, this.environmentService); // Activity bar visibility this.state.activityBar.hidden = !this.configurationService.getValue(Settings.ACTIVITYBAR_VISIBLE); @@ -456,9 +502,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Zen mode enablement this.state.zenMode.restore = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE); - // TODO @misolori update this when finished - this.state.octiconsUpdate.enabled = this.configurationService.getValue(Settings.OCTICONS_UPDATE_ENABLED); - this.setOcticonsUpdate(this.state.octiconsUpdate.enabled); + this.state.hasFocus = this.hostService.hasFocus; + + // Window border + this.updateWindowBorder(true); + } private resolveEditorsToOpen(fileService: IFileService): Promise | IResourceEditor[] { @@ -473,7 +521,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Files to diff is exclusive return pathsToEditors(configuration.filesToDiff, fileService).then(filesToDiff => { - if (filesToDiff && filesToDiff.length === 2) { + if (filesToDiff?.length === 2) { return [{ leftResource: filesToDiff[0].resource, rightResource: filesToDiff[1].resource, @@ -546,10 +594,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const container = this.getContainer(part); - return isAncestor(activeElement, container); + return !!container && isAncestor(activeElement, container); } - getContainer(part: Parts): HTMLElement { + getContainer(part: Parts): HTMLElement | undefined { switch (part) { case Parts.TITLEBAR_PART: return this.getPart(Parts.TITLEBAR_PART).getContainer(); @@ -571,7 +619,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi case Parts.TITLEBAR_PART: if (getTitleBarStyle(this.configurationService, this.environmentService) === 'native') { return false; - } else if (!this.state.fullscreen) { + } else if (!this.state.fullscreen && !isWeb) { return true; } else if (isMacintosh && isNative) { return false; @@ -597,7 +645,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return true; // any other part cannot be hidden } - getDimension(part: Parts): Dimension { + getDimension(part: Parts): Dimension | undefined { return this.getPart(part).dimension; } @@ -665,6 +713,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi hideActivityBar: boolean; hideStatusBar: boolean; hideLineNumbers: boolean; + silentNotifications: boolean; } = this.configurationService.getValue('zenMode'); toggleFullScreen = !this.state.fullscreen && config.fullScreen; @@ -694,6 +743,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.state.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: false })); } + this.state.zenMode.setNotificationsFilter = config.silentNotifications; + if (config.silentNotifications) { + this.notificationService.setFilter(NotificationsFilter.ERROR); + } + if (config.centerLayout) { this.centerEditorLayout(true, true); } @@ -719,6 +773,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.doUpdateLayoutConfiguration(true); this.editorGroupService.activeGroup.focus(); + if (this.state.zenMode.setNotificationsFilter) { + this.notificationService.setFilter(NotificationsFilter.OFF); + } toggleFullScreen = this.state.zenMode.transitionedToFullScreen && this.state.fullscreen; } @@ -765,19 +822,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.workbenchGrid.setViewVisible(this.statusBarPartView, !hidden); } - // TODO @misolori update this when finished - private setOcticonsUpdate(enabled: boolean): void { - this.state.octiconsUpdate.enabled = enabled; - - // Update DOM - if (enabled) { - document.body.dataset.octiconsUpdate = 'enabled'; - } else { - document.body.dataset.octiconsUpdate = ''; - } - } - - protected createWorkbenchLayout(instantiationService: IInstantiationService): void { + protected createWorkbenchLayout(): void { const titleBar = this.getPart(Parts.TITLEBAR_PART); const editorPart = this.getPart(Parts.EDITOR_PART); const activityBar = this.getPart(Parts.ACTIVITYBAR_PART); @@ -812,17 +857,18 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.container.prepend(workbenchGrid.element); this.workbenchGrid = workbenchGrid; - this._register((this.sideBarPartView as SidebarPart).onDidVisibilityChange((visible) => { - this.setSideBarHidden(!visible, true); - })); - - this._register((this.panelPartView as PanelPart).onDidVisibilityChange((visible) => { - this.setPanelHidden(!visible, true); - })); - - this._register((this.editorPartView as PanelPart).onDidVisibilityChange((visible) => { - this.setEditorHidden(!visible, true); - })); + [titleBar, editorPart, activityBar, panelPart, sideBar, statusBar].forEach((part: Part) => { + this._register(part.onDidVisibilityChange((visible) => { + this._onPartVisibilityChange.fire(); + if (part === sideBar) { + this.setSideBarHidden(!visible, true); + } else if (part === panelPart) { + this.setPanelHidden(!visible, true); + } else if (part === editorPart) { + this.setEditorHidden(!visible, true); + } + })); + }); this._register(this.storageService.onWillSaveState(() => { const grid = this.workbenchGrid as SerializableGrid; @@ -845,12 +891,14 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi })); } + getClientArea(): Dimension { + const dim = getClientArea(this.parent); + return this.state.windowBorder ? new Dimension(dim.width - 2, dim.height - 2) : dim; + } + layout(): void { if (!this.disposed) { - this._dimension = getClientArea(this.parent); - - position(this.container, 0, 0, 0, 0, 'relative'); - size(this.container, this._dimension.width, this._dimension.height); + this._dimension = this.getClientArea(); // Layout the grid widget this.workbenchGrid.layout(this._dimension.width, this._dimension.height); @@ -1098,6 +1146,14 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } } + hasWindowBorder(): boolean { + return this.state.windowBorder; + } + + getWindowBorderRadius(): string | undefined { + return this.state.windowBorder && isMacintosh ? '5px' : undefined; + } + isPanelMaximized(): boolean { if (!this.workbenchGrid) { return false; @@ -1151,8 +1207,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.storageService.store(Storage.PANEL_POSITION, positionToString(this.state.panel.position), StorageScope.WORKSPACE); // Adjust CSS - removeClass(panelPart.getContainer(), oldPositionValue); - addClass(panelPart.getContainer(), newPositionValue); + const panelContainer = assertIsDefined(panelPart.getContainer()); + removeClass(panelContainer, oldPositionValue); + addClass(panelContainer, newPositionValue); // Update Styles panelPart.updateStyles(); @@ -1187,11 +1244,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } private createGridDescriptor(): ISerializedGrid { - const workbenchDimensions = getClientArea(this.parent); + const workbenchDimensions = this.getClientArea(); const width = this.storageService.getNumber(Storage.GRID_WIDTH, StorageScope.GLOBAL, workbenchDimensions.width); const height = this.storageService.getNumber(Storage.GRID_HEIGHT, StorageScope.GLOBAL, workbenchDimensions.height); // At some point, we will not fall back to old keys from legacy layout, but for now, let's migrate the keys - const sideBarSize = this.storageService.getNumber(Storage.SIDEBAR_SIZE, StorageScope.GLOBAL, this.storageService.getNumber('workbench.sidebar.width', StorageScope.GLOBAL, Math.min(workbenchDimensions.width / 4, 300))!); + const sideBarSize = this.storageService.getNumber(Storage.SIDEBAR_SIZE, StorageScope.GLOBAL, this.storageService.getNumber('workbench.sidebar.width', StorageScope.GLOBAL, Math.min(workbenchDimensions.width / 4, 300))); const panelSize = this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, this.storageService.getNumber(this.state.panel.position === Position.BOTTOM ? 'workbench.panel.height' : 'workbench.panel.width', StorageScope.GLOBAL, workbenchDimensions.height / 3)); const titleBarHeight = this.titleBarPartView.minimumHeight; diff --git a/src/vs/workbench/browser/media/part.css b/src/vs/workbench/browser/media/part.css index 69b3b64a9dd..89dd7fe4c9b 100644 --- a/src/vs/workbench/browser/media/part.css +++ b/src/vs/workbench/browser/media/part.css @@ -39,8 +39,7 @@ font-size: 11px; cursor: default; font-weight: normal; - -webkit-margin-before: 0; - -webkit-margin-after: 0; + margin: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; @@ -72,6 +71,10 @@ display: none; } +.monaco-workbench .part > .title > .title-actions .action-label.codicon { + color: inherit; +} + .monaco-workbench .part > .content { font-size: 13px; } diff --git a/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css index 2aa9b8cbcec..1491381e007 100644 --- a/src/vs/workbench/browser/media/style.css +++ b/src/vs/workbench/browser/media/style.css @@ -37,6 +37,7 @@ body { overflow: hidden; font-size: 11px; user-select: none; + -webkit-user-select: none; } body.web { @@ -51,6 +52,18 @@ body.web { position: relative; z-index: 1; overflow: hidden; + height: 100vh; + width: 100vw; +} + +.monaco-workbench.border { + height: calc(100vh - 2px); + width: calc(100vw - 2px); + border: 1px solid var(--window-border-color); +} + +.monaco-workbench.border.mac { + border-radius: 5px; } .monaco-workbench img { @@ -97,15 +110,18 @@ body.web { .monaco-workbench.monaco-font-aliasing-antialiased { -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } .monaco-workbench.monaco-font-aliasing-none { -webkit-font-smoothing: none; + -moz-osx-font-smoothing: unset; } @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { .monaco-workbench.monaco-font-aliasing-auto { -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } } @@ -150,14 +166,40 @@ body.web { .monaco-workbench.linux .monaco-menu .monaco-action-bar.vertical .submenu-indicator { height: 100%; - -webkit-mask-size: 10px 10px; mask-size: 10px 10px; + -webkit-mask-size: 10px 10px; } .monaco-workbench .monaco-menu .action-item { cursor: default; } +/* Custom Dropdown (select) Arrows */ + +.monaco-workbench select { + -webkit-appearance: none; + -moz-appearance: none; +} + +.monaco-workbench .select-container { + position: relative; +} + +.monaco-workbench .select-container:after { + content: "\eab4"; + font-family: codicon; + font-size: 14px; + width: 14px; + height: 14px; + line-height: 14px; + position: absolute; + top: 0; + bottom: 0; + right: 6px; + margin: auto; + pointer-events: none; +} + /* START Keyboard Focus Indication Styles */ .monaco-workbench [tabindex="0"]:focus, diff --git a/src/vs/workbench/browser/panel.ts b/src/vs/workbench/browser/panel.ts index 3e1a33fbe2c..cbe865fe623 100644 --- a/src/vs/workbench/browser/panel.ts +++ b/src/vs/workbench/browser/panel.ts @@ -11,6 +11,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; import { isAncestor } from 'vs/base/browser/dom'; +import { assertIsDefined } from 'vs/base/common/types'; export abstract class Panel extends Composite implements IPanel { } @@ -25,7 +26,7 @@ export class PanelDescriptor extends CompositeDescriptor { } export class PanelRegistry extends CompositeRegistry { - private defaultPanelId!: string; + private defaultPanelId: string | undefined; /** * Registers a panel to the platform. @@ -44,7 +45,7 @@ export class PanelRegistry extends CompositeRegistry { /** * Returns a panel by id. */ - getPanel(id: string): PanelDescriptor | null { + getPanel(id: string): PanelDescriptor | undefined { return this.getComposite(id); } @@ -66,7 +67,7 @@ export class PanelRegistry extends CompositeRegistry { * Gets the id of the panel that should open on startup by default. */ getDefaultPanelId(): string { - return this.defaultPanelId; + return assertIsDefined(this.defaultPanelId); } /** @@ -106,13 +107,14 @@ export abstract class TogglePanelAction extends Action { private isPanelActive(): boolean { const activePanel = this.panelService.getActivePanel(); - return !!activePanel && activePanel.getId() === this.panelId; + return activePanel?.getId() === this.panelId; } private isPanelFocused(): boolean { const activeElement = document.activeElement; + const panelPart = this.layoutService.getContainer(Parts.PANEL_PART); - return !!(this.isPanelActive() && activeElement && isAncestor(activeElement, this.layoutService.getContainer(Parts.PANEL_PART))); + return !!(this.isPanelActive() && activeElement && panelPart && isAncestor(activeElement, panelPart)); } } diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index 80e0780610f..d5ee8de2887 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -12,6 +12,7 @@ import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { ISerializableView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { Event, Emitter } from 'vs/base/common/event'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; +import { assertIsDefined } from 'vs/base/common/types'; export interface IPartOptions { hasTitle?: boolean; @@ -29,13 +30,16 @@ export interface ILayoutContentResult { */ export abstract class Part extends Component implements ISerializableView { - private _dimension: Dimension; - get dimension(): Dimension { return this._dimension; } + private _dimension: Dimension | undefined; + get dimension(): Dimension | undefined { return this._dimension; } - private parent: HTMLElement; - private titleArea: HTMLElement | null = null; - private contentArea: HTMLElement | null = null; - private partLayout: PartLayout; + protected _onDidVisibilityChange = this._register(new Emitter()); + readonly onDidVisibilityChange: Event = this._onDidVisibilityChange.event; + + private parent: HTMLElement | undefined; + private titleArea: HTMLElement | undefined; + private contentArea: HTMLElement | undefined; + private partLayout: PartLayout | undefined; constructor( id: string, @@ -80,35 +84,35 @@ export abstract class Part extends Component implements ISerializableView { /** * Returns the overall part container. */ - getContainer(): HTMLElement { + getContainer(): HTMLElement | undefined { return this.parent; } /** * Subclasses override to provide a title area implementation. */ - protected createTitleArea(parent: HTMLElement, options?: object): HTMLElement | null { - return null; + protected createTitleArea(parent: HTMLElement, options?: object): HTMLElement | undefined { + return undefined; } /** * Returns the title area container. */ - protected getTitleArea(): HTMLElement | null { + protected getTitleArea(): HTMLElement | undefined { return this.titleArea; } /** * Subclasses override to provide a content area implementation. */ - protected createContentArea(parent: HTMLElement, options?: object): HTMLElement | null { - return null; + protected createContentArea(parent: HTMLElement, options?: object): HTMLElement | undefined { + return undefined; } /** * Returns the content area container. */ - protected getContentArea(): HTMLElement | null { + protected getContentArea(): HTMLElement | undefined { return this.contentArea; } @@ -116,7 +120,9 @@ export abstract class Part extends Component implements ISerializableView { * Layout title and content area in the given dimension. */ protected layoutContents(width: number, height: number): ILayoutContentResult { - return this.partLayout.layout(width, height); + const partLayout = assertIsDefined(this.partLayout); + + return partLayout.layout(width, height); } //#region ISerializableView @@ -124,7 +130,7 @@ export abstract class Part extends Component implements ISerializableView { private _onDidChange = this._register(new Emitter()); get onDidChange(): Event { return this._onDidChange.event; } - element: HTMLElement; + element!: HTMLElement; abstract minimumWidth: number; abstract maximumWidth: number; @@ -135,6 +141,10 @@ export abstract class Part extends Component implements ISerializableView { this._dimension = new Dimension(width, height); } + setVisible(visible: boolean) { + this._onDidVisibilityChange.fire(visible); + } + abstract toJSON(): object; //#endregion @@ -144,7 +154,7 @@ class PartLayout { private static readonly TITLE_HEIGHT = 35; - constructor(private options: IPartOptions, private contentArea: HTMLElement | null) { } + constructor(private options: IPartOptions, private contentArea: HTMLElement | undefined) { } layout(width: number, height: number): ILayoutContentResult { diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 5c4c70a2e75..bd8425e0555 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -22,7 +22,7 @@ import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarCol import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { IActivity } from 'vs/workbench/common/activity'; -import { ACTIVITY_BAR_FOREGROUND } from 'vs/workbench/common/theme'; +import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -60,7 +60,7 @@ export class ViewletActivityAction extends ActivityAction { const activeViewlet = this.viewletService.getActiveViewlet(); // Hide sidebar if selected viewlet already visible - if (sideBarVisible && activeViewlet && activeViewlet.getId() === this.activity.id) { + if (sideBarVisible && activeViewlet?.getId() === this.activity.id) { this.logAction('hide'); this.layoutService.setSideBarHidden(true); return true; @@ -95,7 +95,7 @@ export class ToggleViewletAction extends Action { const activeViewlet = this.viewletService.getActiveViewlet(); // Hide sidebar if selected viewlet already visible - if (sideBarVisible && activeViewlet && activeViewlet.getId() === this._viewlet.id) { + if (sideBarVisible && activeViewlet?.getId() === this._viewlet.id) { this.layoutService.setSideBarHidden(true); return Promise.resolve(); } @@ -163,15 +163,24 @@ export class GlobalActivityActionViewItem extends ActivityActionViewItem { export class PlaceHolderViewletActivityAction extends ViewletActivityAction { constructor( - id: string, name: string, iconUrl: URI, + id: string, + name: string, + iconUrl: URI | undefined, @IViewletService viewletService: IViewletService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @ITelemetryService telemetryService: ITelemetryService ) { super({ id, name: id, cssClass: `extensionViewlet-placeholder-${id.replace(/\./g, '-')}` }, viewletService, layoutService, telemetryService); - const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${this.class}`; // Generate Placeholder CSS to show the icon in the activity bar - DOM.createCSSRule(iconClass, `-webkit-mask: ${DOM.asCSSUrl(iconUrl)} no-repeat 50% 50%; -webkit-mask-size: 24px;`); + if (iconUrl) { + const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${this.class}`; // Generate Placeholder CSS to show the icon in the activity bar + DOM.createCSSRule(iconClass, ` + mask: ${DOM.asCSSUrl(iconUrl)} no-repeat 50% 50%; + mask-size: 24px; + -webkit-mask: ${DOM.asCSSUrl(iconUrl)} no-repeat 50% 50%; + -webkit-mask-size: 24px; + `); + } } setActivity(activity: IActivity): void { @@ -222,7 +231,7 @@ class SwitchSideBarViewAction extends Action { export class PreviousSideBarViewAction extends SwitchSideBarViewAction { static readonly ID = 'workbench.action.previousSideBarView'; - static LABEL = nls.localize('previousSideBarView', 'Previous Side Bar View'); + static readonly LABEL = nls.localize('previousSideBarView', 'Previous Side Bar View'); constructor( id: string, @@ -241,7 +250,7 @@ export class PreviousSideBarViewAction extends SwitchSideBarViewAction { export class NextSideBarViewAction extends SwitchSideBarViewAction { static readonly ID = 'workbench.action.nextSideBarView'; - static LABEL = nls.localize('nextSideBarView', 'Next Side Bar View'); + static readonly LABEL = nls.localize('nextSideBarView', 'Next Side Bar View'); constructor( id: string, @@ -266,11 +275,35 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const activeForegroundColor = theme.getColor(ACTIVITY_BAR_FOREGROUND); if (activeForegroundColor) { collector.addRule(` - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active .action-label, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item:focus .action-label, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item:hover .action-label { + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label:not(.codicon), + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label:not(.codicon), + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label:not(.codicon) { background-color: ${activeForegroundColor} !important; } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label.codicon, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label.codicon, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label.codicon { + color: ${activeForegroundColor} !important; + } + `); + } + + const activeBorderColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER); + if (activeBorderColor) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before { + border-left-color: ${activeBorderColor}; + } + `); + } + + const activeBackgroundColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND); + if (activeBackgroundColor) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator { + z-index: 0; + background-color: ${activeBackgroundColor}; + } `); } @@ -278,7 +311,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const outline = theme.getColor(activeContrastBorder); if (outline) { collector.addRule(` - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item:before { + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:before { content: ""; position: absolute; top: 9px; @@ -287,26 +320,26 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { width: 32px; } - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active:before, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active:hover:before, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.checked:before, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.checked:hover:before { + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:hover:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:hover:before { outline: 1px solid; } - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item:hover:before { + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover:before { outline: 1px dashed; } - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item:focus:before { + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { border-left-color: ${outline}; } - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active:before, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active:hover:before, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.checked:before, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item.checked:hover:before, - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item:hover:before { + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:hover:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:hover:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover:before { outline-color: ${outline}; } `); @@ -317,7 +350,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const focusBorderColor = theme.getColor(focusBorder); if (focusBorderColor) { collector.addRule(` - .monaco-workbench .activitybar > .content .monaco-action-bar .action-item:focus:before { + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { border-left-color: ${focusBorderColor}; } `); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 1afbdd3e69a..7775095b4e1 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -5,7 +5,6 @@ import 'vs/css!./media/activitybarpart'; import * as nls from 'vs/nls'; -import { illegalArgument } from 'vs/base/common/errors'; import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -15,13 +14,13 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkbenchLayoutService, Parts, Position as SideBarPosition } from 'vs/workbench/services/layout/browser/layoutService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions'; +import { IDisposable, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { ToggleActivityBarVisibilityAction, ToggleMenuBarAction } from 'vs/workbench/browser/actions/layoutActions'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; -import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND } from 'vs/workbench/common/theme'; +import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { CompositeBar, ICompositeBarItem } from 'vs/workbench/browser/parts/compositeBar'; -import { Dimension, addClass } from 'vs/base/browser/dom'; +import { Dimension, addClass, removeNode } from 'vs/base/browser/dom'; import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { URI, UriComponents } from 'vs/base/common/uri'; @@ -30,11 +29,16 @@ import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { IViewsService, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewDescriptorCollection } from 'vs/workbench/common/views'; import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IViewlet } from 'vs/workbench/common/viewlet'; -import { isUndefinedOrNull } from 'vs/base/common/types'; +import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { getMenuBarVisibility } from 'vs/platform/windows/common/windows'; +import { isWeb } from 'vs/base/common/platform'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; interface ICachedViewlet { id: string; @@ -62,13 +66,17 @@ export class ActivitybarPart extends Part implements IActivityBarService { //#endregion - private globalActivityAction: ActivityAction; - private globalActivityActionBar: ActionBar; + private globalActivityAction: ActivityAction | undefined; + private globalActivityActionBar: ActionBar | undefined; + + private customMenubar: CustomMenubarControl | undefined; + private menubar: HTMLElement | undefined; + private content: HTMLElement | undefined; private cachedViewlets: ICachedViewlet[] = []; private compositeBar: CompositeBar; - private compositeActions: Map = new Map(); + private readonly compositeActions: Map = new Map(); private readonly viewletDisposables: Map = new Map(); @@ -81,7 +89,9 @@ export class ActivitybarPart extends Part implements IActivityBarService { @IExtensionService private readonly extensionService: IExtensionService, @IViewsService private readonly viewsService: IViewsService, @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IConfigurationService private readonly configurationService: IConfigurationService, @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, + @IEnvironmentService private readonly environmentService: IEnvironmentService ) { super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); @@ -102,8 +112,18 @@ export class ActivitybarPart extends Part implements IActivityBarService { openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true), getActivityAction: (compositeId: string) => this.getCompositeActions(compositeId).activityAction, getCompositePinnedAction: (compositeId: string) => this.getCompositeActions(compositeId).pinnedAction, - getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletAction, this.viewletService.getViewlet(compositeId)), - getContextMenuActions: () => [this.instantiationService.createInstance(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, nls.localize('hideActivitBar', "Hide Activity Bar"))], + getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(ToggleViewletAction, assertIsDefined(this.viewletService.getViewlet(compositeId))), + getContextMenuActions: () => { + const menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService); + const actions = []; + + if (menuBarVisibility === 'compact' || (menuBarVisibility === 'hidden' && isWeb)) { + actions.push(this.instantiationService.createInstance(ToggleMenuBarAction, ToggleMenuBarAction.ID, menuBarVisibility === 'compact' ? nls.localize('hideMenu', "Hide Menu") : nls.localize('showMenu', "Show Menu"))); + } + + actions.push(this.instantiationService.createInstance(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, nls.localize('hideActivitBar', "Hide Activity Bar"))); + return actions; + }, getDefaultCompositeId: () => this.viewletService.getDefaultViewletId(), hidePart: () => this.layoutService.setSideBarHidden(true), compositeSize: 50, @@ -135,6 +155,17 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.compositeBar.onDidChange(() => this.saveCachedViewlets(), this, disposables); this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables); })); + + // Register for configuration changes + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('window.menuBarVisibility')) { + if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') { + this.installMenubar(); + } else { + this.uninstallMenubar(); + } + } + })); } private onDidRegisterExtensions(): void { @@ -150,13 +181,15 @@ export class ActivitybarPart extends Part implements IActivityBarService { if (foundViewlet) { this.compositeBar.addComposite(foundViewlet); } + this.compositeBar.activateComposite(viewlet.getId()); + const viewletDescriptor = this.viewletService.getViewlet(viewlet.getId()); if (viewletDescriptor) { const viewContainer = this.getViewContainer(viewletDescriptor.id); - if (viewContainer && viewContainer.hideIfEmpty) { + if (viewContainer?.hideIfEmpty) { const viewDescriptors = this.viewsService.getViewDescriptors(viewContainer); - if (viewDescriptors && viewDescriptors.activeViewDescriptors.length === 0) { + if (viewDescriptors?.activeViewDescriptors.length === 0) { this.hideComposite(viewletDescriptor.id); // Update the composite bar by hiding } } @@ -172,60 +205,89 @@ export class ActivitybarPart extends Part implements IActivityBarService { return this.showGlobalActivity(badge, clazz); } - throw illegalArgument('globalActivityId'); + return Disposable.None; } private showGlobalActivity(badge: IBadge, clazz?: string): IDisposable { - this.globalActivityAction.setBadge(badge, clazz); + const globalActivityAction = assertIsDefined(this.globalActivityAction); - return toDisposable(() => this.globalActivityAction.setBadge(undefined)); + globalActivityAction.setBadge(badge, clazz); + + return toDisposable(() => globalActivityAction.setBadge(undefined)); + } + + private uninstallMenubar() { + if (this.customMenubar) { + this.customMenubar.dispose(); + } + + if (this.menubar) { + removeNode(this.menubar); + } + } + + private installMenubar() { + this.menubar = document.createElement('div'); + addClass(this.menubar, 'menubar'); + + const content = assertIsDefined(this.content); + content.prepend(this.menubar); + + // Menubar: install a custom menu bar depending on configuration + this.customMenubar = this._register(this.instantiationService.createInstance(CustomMenubarControl)); + this.customMenubar.create(this.menubar); } createContentArea(parent: HTMLElement): HTMLElement { this.element = parent; - const content = document.createElement('div'); - addClass(content, 'content'); - parent.appendChild(content); + this.content = document.createElement('div'); + addClass(this.content, 'content'); + parent.appendChild(this.content); + + // Install menubar if compact + if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') { + this.installMenubar(); + } // Viewlets action bar - this.compositeBar.create(content); + this.compositeBar.create(this.content); // Global action bar const globalActivities = document.createElement('div'); addClass(globalActivities, 'global-activity'); - content.appendChild(globalActivities); + this.content.appendChild(globalActivities); this.createGlobalActivityActionBar(globalActivities); - this.element.style.display = this.layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? null : 'none'; - - return content; + return this.content; } updateStyles(): void { super.updateStyles(); // Part container - const container = this.getContainer(); - const background = this.getColor(ACTIVITY_BAR_BACKGROUND); + const container = assertIsDefined(this.getContainer()); + const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || ''; container.style.backgroundColor = background; - const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder); + const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || ''; const isPositionLeft = this.layoutService.getSideBarPosition() === SideBarPosition.LEFT; container.style.boxSizing = borderColor && isPositionLeft ? 'border-box' : ''; - container.style.borderRightWidth = borderColor && isPositionLeft ? '1px' : null; - container.style.borderRightStyle = borderColor && isPositionLeft ? 'solid' : null; - container.style.borderRightColor = isPositionLeft ? borderColor : null; - container.style.borderLeftWidth = borderColor && !isPositionLeft ? '1px' : null; - container.style.borderLeftStyle = borderColor && !isPositionLeft ? 'solid' : null; - container.style.borderLeftColor = !isPositionLeft ? borderColor : null; + container.style.borderRightWidth = borderColor && isPositionLeft ? '1px' : ''; + container.style.borderRightStyle = borderColor && isPositionLeft ? 'solid' : ''; + container.style.borderRightColor = isPositionLeft ? borderColor : ''; + container.style.borderLeftWidth = borderColor && !isPositionLeft ? '1px' : ''; + container.style.borderLeftStyle = borderColor && !isPositionLeft ? 'solid' : ''; + container.style.borderLeftColor = !isPositionLeft ? borderColor : ''; } private getActivitybarItemColors(theme: ITheme): ICompositeBarColors { return { activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND), inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND), + activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER), + activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND), badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), dragAndDropBackground: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND), @@ -235,7 +297,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private createGlobalActivityActionBar(container: HTMLElement): void { this.globalActivityActionBar = this._register(new ActionBar(container, { - actionViewItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionViewItem, a, (theme: ITheme) => this.getActivitybarItemColors(theme)), + actionViewItemProvider: action => this.instantiationService.createInstance(GlobalActivityActionViewItem, action as ActivityAction, (theme: ITheme) => this.getActivitybarItemColors(theme)), orientation: ActionsOrientation.VERTICAL, ariaLabel: nls.localize('manage', "Manage"), animated: false @@ -244,8 +306,9 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.globalActivityAction = new ActivityAction({ id: 'workbench.actions.manage', name: nls.localize('manage', "Manage"), - cssClass: 'update-activity' + cssClass: 'codicon-settings-gear' }); + this.globalActivityActionBar.push(this.globalActivityAction); } @@ -261,7 +324,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } else { const cachedComposite = this.cachedViewlets.filter(c => c.id === compositeId)[0]; compositeActions = { - activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite && cachedComposite.name ? cachedComposite.name : compositeId, cachedComposite && cachedComposite.iconUrl ? URI.revive(cachedComposite.iconUrl) : undefined), + activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite?.name || compositeId, cachedComposite?.iconUrl ? URI.revive(cachedComposite.iconUrl) : undefined), pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar) }; } @@ -276,7 +339,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { for (const viewlet of viewlets) { const cachedViewlet = this.cachedViewlets.filter(({ id }) => id === viewlet.id)[0]; const activeViewlet = this.viewletService.getActiveViewlet(); - const isActive = activeViewlet && activeViewlet.getId() === viewlet.id; + const isActive = activeViewlet?.getId() === viewlet.id; if (isActive || !this.shouldBeHidden(viewlet.id, cachedViewlet)) { this.compositeBar.addComposite(viewlet); @@ -291,10 +354,11 @@ export class ActivitybarPart extends Part implements IActivityBarService { } } } + for (const viewlet of viewlets) { this.enableCompositeActions(viewlet); const viewContainer = this.getViewContainer(viewlet.id); - if (viewContainer && viewContainer.hideIfEmpty) { + if (viewContainer?.hideIfEmpty) { const viewDescriptors = this.viewsService.getViewDescriptors(viewContainer); if (viewDescriptors) { this.onDidChangeActiveViews(viewlet, viewDescriptors); @@ -309,6 +373,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { if (disposable) { disposable.dispose(); } + this.viewletDisposables.delete(viewletId); this.hideComposite(viewletId); } @@ -326,7 +391,8 @@ export class ActivitybarPart extends Part implements IActivityBarService { if (!viewContainer || !viewContainer.hideIfEmpty) { return false; } - return cachedViewlet && cachedViewlet.views && cachedViewlet.views.length + + return cachedViewlet?.views && cachedViewlet.views.length ? cachedViewlet.views.every(({ when }) => !!when && !this.contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(when))) : viewletId === TEST_VIEW_CONTAINER_ID /* Hide Test viewlet for the first time or it had no views registered before */; } @@ -342,6 +408,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private hideComposite(compositeId: string): void { this.compositeBar.hideComposite(compositeId); + const compositeActions = this.compositeActions.get(compositeId); if (compositeActions) { compositeActions.activityAction.dispose(); @@ -370,12 +437,6 @@ export class ActivitybarPart extends Part implements IActivityBarService { .map(v => v.id); } - setVisible(visible: boolean): void { - if (this.element) { - this.element.style.display = visible ? null : 'none'; - } - } - layout(width: number, height: number): void { if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) { return; @@ -395,7 +456,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void { if (e.key === ActivitybarPart.PINNED_VIEWLETS && e.scope === StorageScope.GLOBAL && this.cachedViewletsValue !== this.getStoredCachedViewletsValue() /* This checks if current window changed the value or not */) { - this._cachedViewletsValue = null; + this._cachedViewletsValue = undefined; const newCompositeItems: ICompositeBarItem[] = []; const compositeItems = this.compositeBar.getCompositeBarItems(); const cachedViewlets = this.getCachedViewlets(); @@ -480,7 +541,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { return result; } - private _cachedViewletsValue: string | null; + private _cachedViewletsValue: string | undefined; private get cachedViewletsValue(): string { if (!this._cachedViewletsValue) { this._cachedViewletsValue = this.getStoredCachedViewletsValue(); diff --git a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css index 1aedfd5cb21..1fb755062de 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activityaction.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css @@ -3,46 +3,91 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .activitybar > .content .monaco-action-bar .action-item { +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item { display: block; position: relative; padding: 5px 0; } - -.monaco-workbench .activitybar > .content .monaco-action-bar .action-label { +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label { + position: relative; + z-index: 1; display: flex; overflow: hidden; height: 40px; - line-height: 40px; margin-right: 0; - padding: 0 0 0 48px; box-sizing: border-box; - font-size: 15px; + } -.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:focus:before { +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon) { + font-size: 15px; + line-height: 40px; + padding: 0 0 0 48px; +} + +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label.codicon { + font-size: 24px; + align-items: center; + justify-content: center; +} + +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before, +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { content: ""; position: absolute; top: 9px; height: 32px; + z-index: 1; + top: 5px; + height: 40px; width: 0; border-left: 2px solid; } -.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.clicked:focus:before { +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before { + top: 0; + height: 100%; +} + +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus .active-item-indicator:before { + border-left: none; /* don't show active border + focus at the same time, focus takes priority */ +} + +/* Hides active elements in high contrast mode */ +.hc-black .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator { + display: none; +} + +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.clicked:focus:before { border-left: none !important; /* no focus feedback when using mouse */ } -.monaco-workbench .activitybar.left > .content .monaco-action-bar .action-item:focus:before { +.monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before{ + left: 0; +} + +.monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { left: 1px; } -.monaco-workbench .activitybar.right > .content .monaco-action-bar .action-item:focus:before { +.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { right: 1px; } -.monaco-workbench .activitybar > .content .monaco-action-bar .badge { +.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before { + right: 2px; +} + +/* Hides outline on HC as focus is handled by border */ +.hc-black .monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before, +.hc-black .monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before { + outline: none; +} + +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .active-item-indicator, +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge { position: absolute; + z-index: 1; top: 5px; left: 0; overflow: hidden; @@ -50,7 +95,7 @@ height: 40px; } -.monaco-workbench .activitybar > .content .monaco-action-bar .badge .badge-content { +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .badge-content { position: absolute; top: 20px; right: 8px; @@ -66,13 +111,13 @@ /* Right aligned */ -.monaco-workbench .activitybar.right > .content .monaco-action-bar .action-label { +.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon) { margin-left: 0; padding: 0 50px 0 0; background-position: calc(100% - 9px) center; } -.monaco-workbench .activitybar.right > .content .monaco-action-bar .badge { +.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .badge { left: auto; right: 0; -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css index ec58e4ab04f..9afde58f0ad 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css @@ -24,9 +24,20 @@ } .monaco-workbench .activitybar > .content > .composite-bar > .monaco-action-bar .action-label.toggle-more { + mask: url('ellipsis-activity-bar.svg') no-repeat 50% 50%; -webkit-mask: url('ellipsis-activity-bar.svg') no-repeat 50% 50%; } .monaco-workbench .activitybar .global-activity .monaco-action-bar .action-label.update-activity { + mask: url('settings-activity-bar.svg') no-repeat 50% 50%; -webkit-mask: url('settings-activity-bar.svg') no-repeat 50% 50%; -} \ No newline at end of file +} + +.monaco-workbench .activitybar > .content > .composite-bar { + margin-bottom: auto; +} + +.monaco-workbench .activitybar .menubar { + width: 100%; + height: 35px; +} diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 7a39fce8178..70c951cac17 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -30,11 +30,12 @@ export interface ICompositeBarItem { } export interface ICompositeBarOptions { - icon: boolean; - orientation: ActionsOrientation; - colors: (theme: ITheme) => ICompositeBarColors; - compositeSize: number; - overflowActionSize: number; + readonly icon: boolean; + readonly orientation: ActionsOrientation; + readonly colors: (theme: ITheme) => ICompositeBarColors; + readonly compositeSize: number; + readonly overflowActionSize: number; + getActivityAction: (compositeId: string) => ActivityAction; getCompositePinnedAction: (compositeId: string) => Action; getOnCompositeClickAction: (compositeId: string) => Action; @@ -48,7 +49,7 @@ export class CompositeBar extends Widget implements ICompositeBar { private dimension: Dimension | undefined; - private compositeSwitcherBar!: ActionBar; + private compositeSwitcherBar: ActionBar | undefined; private compositeOverflowAction: CompositeOverflowActivityAction | undefined; private compositeOverflowActionViewItem: CompositeOverflowActivityActionViewItem | undefined; @@ -92,13 +93,14 @@ export class CompositeBar extends Widget implements ICompositeBar { create(parent: HTMLElement): HTMLElement { const actionBarDiv = parent.appendChild($('.composite-bar')); + this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, { actionViewItemProvider: (action: Action) => { if (action instanceof CompositeOverflowActivityAction) { return this.compositeOverflowActionViewItem; } const item = this.model.findItem(action.id); - return item && this.instantiationService.createInstance(CompositeActionViewItem, action, item.pinnedAction, () => this.getContextMenuActions(), this.options.colors, this.options.icon, this); + return item && this.instantiationService.createInstance(CompositeActionViewItem, action as ActivityAction, item.pinnedAction, () => this.getContextMenuActions() as Action[], this.options.colors, this.options.icon, this); }, orientation: this.options.orientation, ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), @@ -113,12 +115,15 @@ export class CompositeBar extends Widget implements ICompositeBar { if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { EventHelper.stop(e, true); - const draggedCompositeId = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype)![0].id; - this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype); + const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); + if (Array.isArray(data)) { + const draggedCompositeId = data[0].id; + this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype); - const targetItem = this.model.visibleItems[this.model.visibleItems.length - 1]; - if (targetItem && targetItem.id !== draggedCompositeId) { - this.move(draggedCompositeId, targetItem.id); + const targetItem = this.model.visibleItems[this.model.visibleItems.length - 1]; + if (targetItem && targetItem.id !== draggedCompositeId) { + this.move(draggedCompositeId, targetItem.id); + } } } })); @@ -258,7 +263,7 @@ export class CompositeBar extends Widget implements ICompositeBar { isPinned(compositeId: string): boolean { const item = this.model.findItem(compositeId); - return item && item.pinned; + return item?.pinned; } move(compositeId: string, toCompositeId: string): void { @@ -270,7 +275,7 @@ export class CompositeBar extends Widget implements ICompositeBar { getAction(compositeId: string): ActivityAction { const item = this.model.findItem(compositeId); - return item && item.activityAction; + return item?.activityAction; } private computeSizes(items: ICompositeBarModelItem[]): void { @@ -278,21 +283,23 @@ export class CompositeBar extends Widget implements ICompositeBar { if (size) { items.forEach(composite => this.compositeSizeInBar.set(composite.id, size)); } else { - if (this.dimension && this.dimension.height !== 0 && this.dimension.width !== 0) { + const compositeSwitcherBar = this.compositeSwitcherBar; + if (compositeSwitcherBar && this.dimension && this.dimension.height !== 0 && this.dimension.width !== 0) { // Compute sizes only if visible. Otherwise the size measurment would be computed wrongly. - const currentItemsLength = this.compositeSwitcherBar.viewItems.length; - this.compositeSwitcherBar.push(items.map(composite => composite.activityAction)); + const currentItemsLength = compositeSwitcherBar.viewItems.length; + compositeSwitcherBar.push(items.map(composite => composite.activityAction)); items.map((composite, index) => this.compositeSizeInBar.set(composite.id, this.options.orientation === ActionsOrientation.VERTICAL - ? this.compositeSwitcherBar.getHeight(currentItemsLength + index) - : this.compositeSwitcherBar.getWidth(currentItemsLength + index) + ? compositeSwitcherBar.getHeight(currentItemsLength + index) + : compositeSwitcherBar.getWidth(currentItemsLength + index) )); - items.forEach(() => this.compositeSwitcherBar.pull(this.compositeSwitcherBar.viewItems.length - 1)); + items.forEach(() => compositeSwitcherBar.pull(compositeSwitcherBar.viewItems.length - 1)); } } } private updateCompositeSwitcher(): void { - if (!this.compositeSwitcherBar || !this.dimension) { + const compositeSwitcherBar = this.compositeSwitcherBar; + if (!compositeSwitcherBar || !this.dimension) { return; // We have not been rendered yet so there is nothing to update. } @@ -340,7 +347,7 @@ export class CompositeBar extends Widget implements ICompositeBar { // Pull out overflow action if there is a composite change so that we can add it to the end later if (this.compositeOverflowAction && visibleCompositesChange) { - this.compositeSwitcherBar.pull(this.compositeSwitcherBar.length() - 1); + compositeSwitcherBar.pull(compositeSwitcherBar.length() - 1); this.compositeOverflowAction.dispose(); this.compositeOverflowAction = undefined; @@ -359,8 +366,8 @@ export class CompositeBar extends Widget implements ICompositeBar { } }); compositesToRemove.reverse().forEach(index => { - const actionViewItem = this.compositeSwitcherBar.viewItems[index]; - this.compositeSwitcherBar.pull(index); + const actionViewItem = compositeSwitcherBar.viewItems[index]; + compositeSwitcherBar.pull(index); actionViewItem.dispose(); this.visibleComposites.splice(index, 1); }); @@ -370,19 +377,19 @@ export class CompositeBar extends Widget implements ICompositeBar { const currentIndex = this.visibleComposites.indexOf(compositeId); if (newIndex !== currentIndex) { if (currentIndex !== -1) { - const actionViewItem = this.compositeSwitcherBar.viewItems[currentIndex]; - this.compositeSwitcherBar.pull(currentIndex); + const actionViewItem = compositeSwitcherBar.viewItems[currentIndex]; + compositeSwitcherBar.pull(currentIndex); actionViewItem.dispose(); this.visibleComposites.splice(currentIndex, 1); } - this.compositeSwitcherBar.push(this.model.findItem(compositeId).activityAction, { label: true, icon: this.options.icon, index: newIndex }); + compositeSwitcherBar.push(this.model.findItem(compositeId).activityAction, { label: true, icon: this.options.icon, index: newIndex }); this.visibleComposites.splice(newIndex, 0, compositeId); } }); // Add overflow action as needed - if ((visibleCompositesChange && overflows) || this.compositeSwitcherBar.length() === 0) { + if ((visibleCompositesChange && overflows) || compositeSwitcherBar.length() === 0) { this.compositeOverflowAction = this.instantiationService.createInstance(CompositeOverflowActivityAction, () => { if (this.compositeOverflowActionViewItem) { this.compositeOverflowActionViewItem.showMenu(); @@ -395,13 +402,13 @@ export class CompositeBar extends Widget implements ICompositeBar { () => this.model.activeItem ? this.model.activeItem.id : undefined, (compositeId: string) => { const item = this.model.findItem(compositeId); - return item && item.activity[0] && item.activity[0].badge; + return item?.activity[0]?.badge; }, this.options.getOnCompositeClickAction, this.options.colors ); - this.compositeSwitcherBar.push(this.compositeOverflowAction, { label: false, icon: true }); + compositeSwitcherBar.push(this.compositeOverflowAction, { label: false, icon: true }); } this._onDidChange.fire(); diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index 33c609eba58..cfcbbf171b1 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -57,7 +57,7 @@ export class ActivityAction extends Action { private readonly _onDidChangeBadge = new Emitter(); readonly onDidChangeBadge: Event = this._onDidChangeBadge.event; - private badge?: IBadge; + private badge: IBadge | undefined; private clazz: string | undefined; constructor(private _activity: IActivity) { @@ -110,6 +110,8 @@ export class ActivityAction extends Action { export interface ICompositeBarColors { activeBackgroundColor?: Color; inactiveBackgroundColor?: Color; + activeBorderColor?: Color; + activeBackground?: Color; activeBorderBottomColor?: Color; activeForegroundColor?: Color; inactiveForegroundColor?: Color; @@ -156,12 +158,21 @@ export class ActivityActionViewItem extends BaseActionViewItem { if (this.label) { if (this.options.icon) { const foreground = this._action.checked ? colors.activeBackgroundColor || colors.activeForegroundColor : colors.inactiveBackgroundColor || colors.inactiveForegroundColor; - this.label.style.backgroundColor = foreground ? foreground.toString() : null; + // TODO @misolori find a cleaner way to do this + const isExtension = this.activity.cssClass?.indexOf('extensionViewlet') === 0; + if (!isExtension) { + // Apply foreground color to activity bar items (codicons) + this.label.style.color = foreground ? foreground.toString() : ''; + } else { + // Apply background color to extensions + remote explorer (svgs) + + this.label.style.backgroundColor = foreground ? foreground.toString() : ''; + } } else { const foreground = this._action.checked ? colors.activeForegroundColor : colors.inactiveForegroundColor; const borderBottomColor = this._action.checked ? colors.activeBorderBottomColor : null; this.label.style.color = foreground ? foreground.toString() : null; - this.label.style.borderBottomColor = borderBottomColor ? borderBottomColor.toString() : null; + this.label.style.borderBottomColor = borderBottomColor ? borderBottomColor.toString() : ''; } } @@ -172,11 +183,11 @@ export class ActivityActionViewItem extends BaseActionViewItem { const contrastBorderColor = theme.getColor(contrastBorder); this.badgeContent.style.color = badgeForeground ? badgeForeground.toString() : null; - this.badgeContent.style.backgroundColor = badgeBackground ? badgeBackground.toString() : null; + this.badgeContent.style.backgroundColor = badgeBackground ? badgeBackground.toString() : ''; - this.badgeContent.style.borderStyle = contrastBorderColor ? 'solid' : null; - this.badgeContent.style.borderWidth = contrastBorderColor ? '1px' : null; - this.badgeContent.style.borderColor = contrastBorderColor ? contrastBorderColor.toString() : null; + this.badgeContent.style.borderStyle = contrastBorderColor ? 'solid' : ''; + this.badgeContent.style.borderWidth = contrastBorderColor ? '1px' : ''; + this.badgeContent.style.borderColor = contrastBorderColor ? contrastBorderColor.toString() : ''; } } @@ -205,12 +216,18 @@ export class ActivityActionViewItem extends BaseActionViewItem { })); // Label - this.label = dom.append(this.element!, dom.$('a')); + this.label = dom.append(container, dom.$('a')); // Badge - this.badge = dom.append(this.element!, dom.$('.badge')); + this.badge = dom.append(container, dom.$('.badge')); this.badgeContent = dom.append(this.badge, dom.$('.badge-content')); + // Activity bar active border + background + const isActivityBarItem = this.options.icon; + if (isActivityBarItem) { + dom.append(container, dom.$('.active-item-indicator')); + } + dom.hide(this.badge); this.updateActivity(); @@ -285,7 +302,7 @@ export class ActivityActionViewItem extends BaseActionViewItem { // Title let title: string; - if (badge && badge.getDescription()) { + if (badge?.getDescription()) { if (this.activity.name) { title = nls.localize('badgeTitle', "{0} - {1}", this.activity.name, badge.getDescription()); } else { @@ -294,14 +311,23 @@ export class ActivityActionViewItem extends BaseActionViewItem { } else { title = this.activity.name; } + this.updateTitle(title); } protected updateLabel(): void { this.label.className = 'action-label'; + if (this.activity.cssClass) { + // TODO @misolori find a cleaner way to do this + const isExtension = this.activity.cssClass?.indexOf('extensionViewlet') === 0; + if (this.options.icon && !isExtension) { + // Only apply icon class to activity bar items (exclude extensions + remote explorer) + dom.addClass(this.label, 'codicon'); + } dom.addClass(this.label, this.activity.cssClass); } + if (!this.options.icon) { this.label.textContent = this.getAction().label; } @@ -335,7 +361,7 @@ export class CompositeOverflowActivityAction extends ActivityAction { super({ id: 'additionalComposites.action', name: nls.localize('additionalViews', "Additional Views"), - cssClass: 'toggle-more' + cssClass: 'codicon-more' }); } @@ -347,12 +373,12 @@ export class CompositeOverflowActivityAction extends ActivityAction { } export class CompositeOverflowActivityActionViewItem extends ActivityActionViewItem { - private actions: Action[] | undefined; + private actions: Action[] = []; constructor( action: ActivityAction, - private getOverflowingComposites: () => { id: string, name: string }[], - private getActiveCompositeId: () => string, + private getOverflowingComposites: () => { id: string, name?: string }[], + private getActiveCompositeId: () => string | undefined, private getBadge: (compositeId: string) => IBadge, private getCompositeOpenAction: (compositeId: string) => Action, colors: (theme: ITheme) => ICompositeBarColors, @@ -370,16 +396,17 @@ export class CompositeOverflowActivityActionViewItem extends ActivityActionViewI this.actions = this.getActions(); this.contextMenuService.showContextMenu({ - getAnchor: () => this.element!, - getActions: () => this.actions!, - onHide: () => dispose(this.actions!) + getAnchor: () => this.container, + getActions: () => this.actions, + getCheckedActionsRepresentation: () => 'radio', + onHide: () => dispose(this.actions) }); } private getActions(): Action[] { return this.getOverflowingComposites().map(composite => { const action = this.getCompositeOpenAction(composite.id); - action.radio = this.getActiveCompositeId() === action.id; + action.checked = this.getActiveCompositeId() === action.id; const badge = this.getBadge(composite.id); let suffix: string | number | undefined; @@ -392,7 +419,7 @@ export class CompositeOverflowActivityActionViewItem extends ActivityActionViewI if (suffix) { action.label = nls.localize('numberBadge', "{0} ({1})", composite.name, suffix); } else { - action.label = composite.name; + action.label = composite.name || ''; } return action; @@ -439,7 +466,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem { constructor( private compositeActivityAction: ActivityAction, private toggleCompositePinnedAction: Action, - private contextMenuActionsProvider: () => Action[], + private contextMenuActionsProvider: () => ReadonlyArray, colors: (theme: ITheme) => ICompositeBarColors, icon: boolean, private compositeBar: ICompositeBar, @@ -502,7 +529,9 @@ export class CompositeActionViewItem extends ActivityActionViewItem { // Allow to drag this._register(dom.addDisposableListener(this.container, dom.EventType.DRAG_START, (e: DragEvent) => { - e.dataTransfer!.effectAllowed = 'move'; + if (e.dataTransfer) { + e.dataTransfer.effectAllowed = 'move'; + } // Registe as dragged to local transfer this.compositeTransfer.setData([new DraggedCompositeIdentifier(this.activity.id)], DraggedCompositeIdentifier.prototype); @@ -515,8 +544,11 @@ export class CompositeActionViewItem extends ActivityActionViewItem { this._register(new DragAndDropObserver(this.container, { onDragEnter: e => { - if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype) && this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype)![0].id !== this.activity.id) { - this.updateFromDragging(container, true); + if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { + const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); + if (Array.isArray(data) && data[0].id !== this.activity.id) { + this.updateFromDragging(container, true); + } } }, @@ -538,12 +570,15 @@ export class CompositeActionViewItem extends ActivityActionViewItem { dom.EventHelper.stop(e, true); if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { - const draggedCompositeId = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype)![0].id; - if (draggedCompositeId !== this.activity.id) { - this.updateFromDragging(container, false); - this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype); + const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); + if (Array.isArray(data)) { + const draggedCompositeId = data[0].id; + if (draggedCompositeId !== this.activity.id) { + this.updateFromDragging(container, false); + this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype); - this.compositeBar.move(draggedCompositeId, this.activity.id); + this.compositeBar.move(draggedCompositeId, this.activity.id); + } } } } @@ -563,7 +598,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem { const theme = this.themeService.getTheme(); const dragBackground = this.options.colors(theme).dragAndDropBackground; - element.style.backgroundColor = isDragging && dragBackground ? dragBackground.toString() : null; + element.style.backgroundColor = isDragging && dragBackground ? dragBackground.toString() : ''; } private showContextMenu(container: HTMLElement): void { @@ -595,8 +630,8 @@ export class CompositeActionViewItem extends ActivityActionViewItem { this.contextMenuService.showContextMenu({ getAnchor: () => anchor, - getActionsContext: () => this.activity.id, - getActions: () => actions + getActions: () => actions, + getActionsContext: () => this.activity.id }); } diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index adac882f1d3..9001551e9c4 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -32,6 +32,7 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { Dimension, append, $, addClass, hide, show, addClasses } from 'vs/base/browser/dom'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; +import { assertIsDefined, withNullAsUndefined } from 'vs/base/common/types'; export interface ICompositeTitleLabel { @@ -57,15 +58,15 @@ export abstract class CompositePart extends Part { protected readonly onDidCompositeOpen = this._register(new Emitter<{ composite: IComposite, focus: boolean }>()); protected readonly onDidCompositeClose = this._register(new Emitter()); - protected toolBar!: ToolBar; + protected toolBar: ToolBar | undefined; private mapCompositeToCompositeContainer = new Map(); private mapActionsBindingToComposite = new Map void>(); - private activeComposite: Composite | null; + private activeComposite: Composite | undefined; private lastActiveCompositeId: string; private instantiatedCompositeItems: Map; - private titleLabel!: ICompositeTitleLabel; - private progressBar!: ProgressBar; + private titleLabel: ICompositeTitleLabel | undefined; + private progressBar: ProgressBar | undefined; private contentAreaSize: Dimension | undefined; private readonly telemetryActionsListener = this._register(new MutableDisposable()); private currentCompositeOpenToken: string | undefined; @@ -90,7 +91,6 @@ export abstract class CompositePart extends Part { ) { super(id, options, themeService, storageService, layoutService); - this.activeComposite = null; this.instantiatedCompositeItems = new Map(); this.lastActiveCompositeId = storageService.get(activeCompositeSettingsKey, StorageScope.WORKSPACE, this.defaultCompositeId); } @@ -168,7 +168,7 @@ export abstract class CompositePart extends Part { // Instantiate composite from registry otherwise const compositeDescriptor = this.registry.getComposite(id); if (compositeDescriptor) { - const compositeProgressIndicator = this.instantiationService.createInstance(CompositeProgressIndicator, this.progressBar, compositeDescriptor.id, isActive); + const compositeProgressIndicator = this.instantiationService.createInstance(CompositeProgressIndicator, assertIsDefined(this.progressBar), compositeDescriptor.id, !!isActive); const compositeInstantiationService = this.instantiationService.createChild(new ServiceCollection( [IEditorProgressService, compositeProgressIndicator] // provide the editor progress service for any editors instantiated within the composite )); @@ -234,7 +234,8 @@ export abstract class CompositePart extends Part { show(compositeContainer); // Setup action runner - this.toolBar.actionRunner = composite.getActionRunner(); + const toolBar = assertIsDefined(this.toolBar); + toolBar.actionRunner = composite.getActionRunner(); // Update title with composite title if it differs from descriptor const descriptor = this.registry.getComposite(composite.getId()); @@ -251,7 +252,7 @@ export abstract class CompositePart extends Part { actionsBinding(); // Action Run Handling - this.telemetryActionsListener.value = this.toolBar.actionRunner.onDidRun(e => { + this.telemetryActionsListener.value = toolBar.actionRunner.onDidRun(e => { // Check for Error if (e.error && !errors.isPromiseCanceledError(e.error)) { @@ -284,7 +285,7 @@ export abstract class CompositePart extends Part { if (this.activeComposite && this.activeComposite.getId() === compositeId) { // Title - this.updateTitle(this.activeComposite.getId(), this.activeComposite.getTitle() || undefined); + this.updateTitle(this.activeComposite.getId(), this.activeComposite.getTitle()); // Actions const actionsBinding = this.collectCompositeActions(this.activeComposite); @@ -310,9 +311,10 @@ export abstract class CompositePart extends Part { const keybinding = this.keybindingService.lookupKeybinding(compositeId); - this.titleLabel.updateTitle(compositeId, compositeTitle, (keybinding && keybinding.getLabel()) || undefined); + this.titleLabel.updateTitle(compositeId, compositeTitle, withNullAsUndefined(keybinding?.getLabel())); - this.toolBar.setAriaLabel(nls.localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle)); + const toolBar = assertIsDefined(this.toolBar); + toolBar.setAriaLabel(nls.localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle)); } private collectCompositeActions(composite: Composite): () => void { @@ -326,13 +328,14 @@ export abstract class CompositePart extends Part { secondaryActions.push(...this.getSecondaryActions()); // Update context - this.toolBar.context = this.actionsContextProvider(); + const toolBar = assertIsDefined(this.toolBar); + toolBar.context = this.actionsContextProvider(); // Return fn to set into toolbar - return this.toolBar.setActions(prepareActions(primaryActions), prepareActions(secondaryActions)); + return toolBar.setActions(prepareActions(primaryActions), prepareActions(secondaryActions)); } - protected getActiveComposite(): IComposite | null { + protected getActiveComposite(): IComposite | undefined { return this.activeComposite; } @@ -346,7 +349,7 @@ export abstract class CompositePart extends Part { } const composite = this.activeComposite; - this.activeComposite = null; + this.activeComposite = undefined; const compositeContainer = this.mapCompositeToCompositeContainer.get(composite.getId()); @@ -360,10 +363,14 @@ export abstract class CompositePart extends Part { } // Clear any running Progress - this.progressBar.stop().hide(); + if (this.progressBar) { + this.progressBar.stop().hide(); + } // Empty Actions - this.toolBar.setActions([])(); + if (this.toolBar) { + this.toolBar.setActions([])(); + } this.onDidCompositeClose.fire(composite); return composite; @@ -413,7 +420,8 @@ export abstract class CompositePart extends Part { super.updateStyles(); // Forward to title label - this.titleLabel.updateStyles(); + const titleLabel = assertIsDefined(this.titleLabel); + titleLabel.updateStyles(); } protected actionViewItemProvider(action: IAction): IActionViewItem | undefined { @@ -446,10 +454,10 @@ export abstract class CompositePart extends Part { return contentContainer; } - getProgressIndicator(id: string): IProgressIndicator | null { + getProgressIndicator(id: string): IProgressIndicator | undefined { const compositeItem = this.instantiatedCompositeItems.get(id); - return compositeItem ? compositeItem.progress : null; + return compositeItem ? compositeItem.progress : undefined; } protected getActions(): ReadonlyArray { diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index 9445929501c..53b00a24b33 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -19,8 +19,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { dispose } from 'vs/base/common/lifecycle'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; export interface IOpenCallbacks { openInternal: (input: EditorInput, options: EditorOptions | undefined) => Promise; @@ -40,8 +39,8 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { private callbacks: IOpenCallbacks; private metadata: string | undefined; - private binaryContainer: HTMLElement; - private scrollbar: DomScrollableElement; + private binaryContainer: HTMLElement | undefined; + private scrollbar: DomScrollableElement | undefined; private resourceViewerContext: ResourceViewerContext | undefined; constructor( @@ -49,10 +48,8 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { callbacks: IOpenCallbacks, telemetryService: ITelemetryService, themeService: IThemeService, - @IFileService private readonly fileService: IFileService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IStorageService storageService: IStorageService, - @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(id, telemetryService, themeService, storageService); @@ -95,11 +92,12 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { this.resourceViewerContext.dispose(); } - this.resourceViewerContext = ResourceViewer.show({ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag(), mime: model.getMime() }, this.fileService, this.binaryContainer, this.scrollbar, { + const [binaryContainer, scrollbar] = assertAllDefined(this.binaryContainer, this.scrollbar); + this.resourceViewerContext = ResourceViewer.show({ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag(), mime: model.getMime() }, binaryContainer, scrollbar, { openInternalClb: () => this.handleOpenInternalCallback(input, options), openExternalClb: this.environmentService.configuration.remoteAuthority ? undefined : resource => this.callbacks.openExternal(resource), metadataClb: meta => this.handleMetadataChanged(meta) - }, this.instantiationService); + }); } private async handleOpenInternalCallback(input: EditorInput, options: EditorOptions | undefined): Promise { @@ -124,8 +122,10 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { // Clear Meta this.handleMetadataChanged(undefined); - // Clear Resource Viewer - clearNode(this.binaryContainer); + // Clear the rest + if (this.binaryContainer) { + clearNode(this.binaryContainer); + } dispose(this.resourceViewerContext); this.resourceViewerContext = undefined; @@ -135,19 +135,24 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { layout(dimension: Dimension): void { // Pass on to Binary Container - size(this.binaryContainer, dimension.width, dimension.height); - this.scrollbar.scanDomNode(); + const [binaryContainer, scrollbar] = assertAllDefined(this.binaryContainer, this.scrollbar); + size(binaryContainer, dimension.width, dimension.height); + scrollbar.scanDomNode(); if (this.resourceViewerContext && this.resourceViewerContext.layout) { this.resourceViewerContext.layout(dimension); } } focus(): void { - this.binaryContainer.focus(); + const binaryContainer = assertIsDefined(this.binaryContainer); + + binaryContainer.focus(); } dispose(): void { - this.binaryContainer.remove(); + if (this.binaryContainer) { + this.binaryContainer.remove(); + } dispose(this.resourceViewerContext); this.resourceViewerContext = undefined; diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts index 96a35f5a192..ac600063f15 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts @@ -66,14 +66,14 @@ export abstract class BreadcrumbsConfig { // internal } - static IsEnabled = BreadcrumbsConfig._stub('breadcrumbs.enabled'); - static UseQuickPick = BreadcrumbsConfig._stub('breadcrumbs.useQuickPick'); - static FilePath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.filePath'); - static SymbolPath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.symbolPath'); - static SymbolSortOrder = BreadcrumbsConfig._stub<'position' | 'name' | 'type'>('breadcrumbs.symbolSortOrder'); - static Icons = BreadcrumbsConfig._stub('breadcrumbs.icons'); + static readonly IsEnabled = BreadcrumbsConfig._stub('breadcrumbs.enabled'); + static readonly UseQuickPick = BreadcrumbsConfig._stub('breadcrumbs.useQuickPick'); + static readonly FilePath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.filePath'); + static readonly SymbolPath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.symbolPath'); + static readonly SymbolSortOrder = BreadcrumbsConfig._stub<'position' | 'name' | 'type'>('breadcrumbs.symbolSortOrder'); + static readonly Icons = BreadcrumbsConfig._stub('breadcrumbs.icons'); - static FileExcludes = BreadcrumbsConfig._stub('files.exclude'); + static readonly FileExcludes = BreadcrumbsConfig._stub('files.exclude'); private static _stub(name: string): { bindTo(service: IConfigurationService): BreadcrumbsConfig } { return { @@ -166,6 +166,136 @@ Registry.as(Extensions.Configuration).registerConfigurat description: localize('icons', "Render breadcrumb items with icons."), type: 'boolean', default: true + }, + 'breadcrumbs.showFiles': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.file', "When enabled breadcrumbs show `file`-symbols.") + }, + 'breadcrumbs.showModules': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.module', "When enabled breadcrumbs show `module`-symbols.") + }, + 'breadcrumbs.showNamespaces': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.namespace', "When enabled breadcrumbs show `namespace`-symbols.") + }, + 'breadcrumbs.showPackages': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.package', "When enabled breadcrumbs show `package`-symbols.") + }, + 'breadcrumbs.showClasses': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.class', "When enabled breadcrumbs show `class`-symbols.") + }, + 'breadcrumbs.showMethods': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.method', "When enabled breadcrumbs show `method`-symbols.") + }, + 'breadcrumbs.showProperties': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.property', "When enabled breadcrumbs show `property`-symbols.") + }, + 'breadcrumbs.showFields': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.field', "When enabled breadcrumbs show `field`-symbols.") + }, + 'breadcrumbs.showConstructors': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.constructor', "When enabled breadcrumbs show `constructor`-symbols.") + }, + 'breadcrumbs.showEnums': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.enum', "When enabled breadcrumbs show `enum`-symbols.") + }, + 'breadcrumbs.showInterfaces': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.interface', "When enabled breadcrumbs show `interface`-symbols.") + }, + 'breadcrumbs.showFunctions': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.function', "When enabled breadcrumbs show `function`-symbols.") + }, + 'breadcrumbs.showVariables': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.variable', "When enabled breadcrumbs show `variable`-symbols.") + }, + 'breadcrumbs.showConstants': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.constant', "When enabled breadcrumbs show `constant`-symbols.") + }, + 'breadcrumbs.showStrings': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.string', "When enabled breadcrumbs show `string`-symbols.") + }, + 'breadcrumbs.showNumbers': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.number', "When enabled breadcrumbs show `number`-symbols.") + }, + 'breadcrumbs.showBooleans': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.boolean', "When enabled breadcrumbs show `boolean`-symbols.") + }, + 'breadcrumbs.showArrays': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.array', "When enabled breadcrumbs show `array`-symbols.") + }, + 'breadcrumbs.showObjects': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.object', "When enabled breadcrumbs show `object`-symbols.") + }, + 'breadcrumbs.showKeys': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.key', "When enabled breadcrumbs show `key`-symbols.") + }, + 'breadcrumbs.showNull': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.null', "When enabled breadcrumbs show `null`-symbols.") + }, + 'breadcrumbs.showEnumMembers': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.enumMember', "When enabled breadcrumbs show `enumMember`-symbols.") + }, + 'breadcrumbs.showStructs': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.struct', "When enabled breadcrumbs show `struct`-symbols.") + }, + 'breadcrumbs.showEvents': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.event', "When enabled breadcrumbs show `event`-symbols.") + }, + 'breadcrumbs.showOperators': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.operator', "When enabled breadcrumbs show `operator`-symbols.") + }, + 'breadcrumbs.showTypeParameters': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.typeParameter', "When enabled breadcrumbs show `typeParameter`-symbols.") } } }); diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 4594e365427..375f8a2274e 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -17,7 +17,7 @@ import 'vs/css!./media/breadcrumbscontrol'; import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; import { ICodeEditorViewState, ScrollType } from 'vs/editor/common/editorCommon'; -import { symbolKindToCssClass } from 'vs/editor/common/modes'; +import { SymbolKinds } from 'vs/editor/common/modes'; import { OutlineElement, OutlineGroup, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; @@ -45,7 +45,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { onDidChangeZoomLevel } from 'vs/base/browser/browser'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; class Item extends BreadcrumbsItem { @@ -109,7 +109,7 @@ class Item extends BreadcrumbsItem { // symbol if (this.options.showSymbolIcons) { let icon = document.createElement('div'); - icon.className = symbolKindToCssClass(this.element.symbol.kind); + icon.className = SymbolKinds.toCssClassName(this.element.symbol.kind); container.appendChild(icon); dom.addClass(container, 'shows-symbol-icon'); } @@ -130,15 +130,15 @@ export interface IBreadcrumbsControlOptions { export class BreadcrumbsControl { - static HEIGHT = 22; + static readonly HEIGHT = 22; static readonly Payload_Reveal = {}; static readonly Payload_RevealAside = {}; static readonly Payload_Pick = {}; - static CK_BreadcrumbsPossible = new RawContextKey('breadcrumbsPossible', false); - static CK_BreadcrumbsVisible = new RawContextKey('breadcrumbsVisible', false); - static CK_BreadcrumbsActive = new RawContextKey('breadcrumbsActive', false); + static readonly CK_BreadcrumbsPossible = new RawContextKey('breadcrumbsPossible', false); + static readonly CK_BreadcrumbsVisible = new RawContextKey('breadcrumbsVisible', false); + static readonly CK_BreadcrumbsActive = new RawContextKey('breadcrumbsActive', false); private readonly _ckBreadcrumbsPossible: IContextKey; private readonly _ckBreadcrumbsVisible: IContextKey; @@ -246,7 +246,7 @@ export class BreadcrumbsControl { const uri = input.getResource()!; const editor = this._getActiveCodeEditor(); - const model = new EditorBreadcrumbsModel(uri, editor, this._workspaceService, this._configurationService); + const model = new EditorBreadcrumbsModel(uri, editor, this._configurationService, this._workspaceService); dom.toggleClass(this.domNode, 'relative-path', model.isRelative()); dom.toggleClass(this.domNode, 'backslash-path', this._labelService.getSeparator(uri.scheme, uri.authority) === '\\'); @@ -485,7 +485,7 @@ export class BreadcrumbsControl { selection: Range.collapseToStart(element.symbol.selectionRange), revealInCenterIfOutsideViewport: true } - }, this._getActiveCodeEditor(), group === SIDE_GROUP); + }, withUndefinedAsNull(this._getActiveCodeEditor()), group === SIDE_GROUP); } } } diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts index c6f7164cc8e..f05157c5257 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts @@ -6,7 +6,7 @@ import { equals } from 'vs/base/common/arrays'; import { TimeoutTimer } from 'vs/base/common/async'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { size } from 'vs/base/common/collections'; +import { size, values } from 'vs/base/common/collections'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -22,6 +22,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs'; import { FileKind } from 'vs/platform/files/common/files'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { OutlineFilter } from 'vs/editor/contrib/documentSymbols/outlineTree'; export class FileElement { constructor( @@ -51,16 +52,15 @@ export class EditorBreadcrumbsModel { constructor( private readonly _uri: URI, private readonly _editor: ICodeEditor | undefined, + @IConfigurationService private readonly _configurationService: IConfigurationService, @IWorkspaceContextService workspaceService: IWorkspaceContextService, - @IConfigurationService configurationService: IConfigurationService, ) { - this._cfgFilePath = BreadcrumbsConfig.FilePath.bindTo(configurationService); - this._cfgSymbolPath = BreadcrumbsConfig.SymbolPath.bindTo(configurationService); + this._cfgFilePath = BreadcrumbsConfig.FilePath.bindTo(_configurationService); + this._cfgSymbolPath = BreadcrumbsConfig.SymbolPath.bindTo(_configurationService); this._disposables.add(this._cfgFilePath.onDidChange(_ => this._onDidUpdate.fire(this))); this._disposables.add(this._cfgSymbolPath.onDidChange(_ => this._onDidUpdate.fire(this))); - this._fileInfo = EditorBreadcrumbsModel._initFilePathInfo(this._uri, workspaceService); this._bindToEditor(); this._onDidUpdate.fire(this); @@ -138,6 +138,14 @@ export class EditorBreadcrumbsModel { this._disposables.add(this._editor.onDidChangeModel(_ => this._updateOutline())); this._disposables.add(this._editor.onDidChangeModelLanguage(_ => this._updateOutline())); + // update when config changes (re-render) + this._disposables.add(this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('breadcrumbs')) { + this._updateOutline(true); + } + })); + + // update soon'ish as model content change const updateSoon = new TimeoutTimer(); this._disposables.add(updateSoon); @@ -207,7 +215,7 @@ export class EditorBreadcrumbsModel { } let item: OutlineGroup | OutlineElement | undefined = model.getItemEnclosingPosition(position); if (!item) { - return [model]; + return this._getOutlineElementsRoot(model); } let chain: Array = []; while (item) { @@ -221,7 +229,30 @@ export class EditorBreadcrumbsModel { } item = parent; } - return chain.reverse(); + let result: Array = []; + for (let i = chain.length - 1; i >= 0; i--) { + let element = chain[i]; + if (this._isFiltered(element)) { + break; + } + result.push(element); + } + if (result.length === 0) { + return this._getOutlineElementsRoot(model); + } + return result; + } + + private _getOutlineElementsRoot(model: OutlineModel): (OutlineModel | OutlineGroup | OutlineElement)[] { + return values(model.children).every(e => this._isFiltered(e)) ? [] : [model]; + } + + private _isFiltered(element: TreeElement): boolean { + if (element instanceof OutlineElement) { + const key = `breadcrumbs.${OutlineFilter.kindToConfigName[element.symbol.kind]}`; + return !this._configurationService.getValue(key); + } + return false; } private _updateOutlineElements(elements: Array): void { diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index b34cd439d03..0541cf5d157 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -26,7 +26,7 @@ import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs import { BreadcrumbElement, FileElement } from 'vs/workbench/browser/parts/editor/breadcrumbsModel'; import { IFileIconTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeFilter, TreeVisibility, ITreeSorter } from 'vs/base/browser/ui/tree/tree'; -import { OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItemComparator, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineDataSource, OutlineSortOrder } from 'vs/editor/contrib/documentSymbols/outlineTree'; +import { OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItemComparator, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineDataSource, OutlineSortOrder, OutlineFilter } from 'vs/editor/contrib/documentSymbols/outlineTree'; import { IIdentityProvider, IListVirtualDelegate, IKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/list/list'; export function createBreadcrumbsPicker(instantiationService: IInstantiationService, parent: HTMLElement, element: BreadcrumbElement): BreadcrumbsPicker { @@ -240,7 +240,7 @@ class FileRenderer implements ITreeRenderer, index: number, templateData: IResourceLabel): void { - const fileDecorations = this._configService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations'); + const fileDecorations = this._configService.getValue<{ colors: boolean, badges: boolean; }>('explorer.decorations'); const { element } = node; let resource: URI; let fileKind: FileKind; @@ -374,7 +374,7 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { const labels = this._instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER /* TODO@Jo visibility propagation */); this._disposables.add(labels); - return this._instantiationService.createInstance(WorkbenchAsyncDataTree, 'BreadcrumbsFilePicker', container, new FileVirtualDelegate(), [this._instantiationService.createInstance(FileRenderer, labels)], this._instantiationService.createInstance(FileDataSource), { + return this._instantiationService.createInstance>(WorkbenchAsyncDataTree, 'BreadcrumbsFilePicker', container, new FileVirtualDelegate(), [this._instantiationService.createInstance(FileRenderer, labels)], this._instantiationService.createInstance(FileDataSource), { multipleSelectionSupport: false, sorter: new FileSorter(), filter: this._instantiationService.createInstance(FileFilter), @@ -438,7 +438,7 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { } protected _createTree(container: HTMLElement) { - return this._instantiationService.createInstance( + return this._instantiationService.createInstance>( WorkbenchDataTree, 'BreadcrumbsOutlinePicker', container, @@ -446,11 +446,13 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { [new OutlineGroupRenderer(), this._instantiationService.createInstance(OutlineElementRenderer)], new OutlineDataSource(), { + collapseByDefault: true, expandOnlyOnTwistieClick: true, multipleSelectionSupport: false, sorter: new OutlineItemComparator(this._getOutlineItemCompareType()), identityProvider: new OutlineIdentityProvider(), - keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider() + keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider(), + filter: this._instantiationService.createInstance(OutlineFilter, 'breadcrumbs') } ); } @@ -466,14 +468,10 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { const tree = this._tree as WorkbenchDataTree; tree.setInput(model); - let focusElement: TreeElement; - if (element === model) { - focusElement = tree.navigate().first(); - } else { - focusElement = element; + if (element !== model) { + tree.reveal(element, 0.5); + tree.setFocus([element], this._fakeEvent); } - tree.reveal(focusElement, 0.5); - tree.setFocus([focusElement], this._fakeEvent); tree.domFocus(); return Promise.resolve(); diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 5f4afb20bc2..48c613127ca 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -17,7 +17,7 @@ import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorIn import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor'; import { ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; @@ -106,7 +106,7 @@ interface ISerializedUntitledEditorInput { resource: string; resourceJSON: object; modeId: string | undefined; - encoding: string; + encoding: string | undefined; } // Register Editor Input Factory @@ -218,7 +218,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory { Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(SideBySideEditorInput.ID, SideBySideEditorInputFactory); // Register Editor Contributions -registerEditorContribution(OpenWorkspaceButtonContribution); +registerEditorContribution(OpenWorkspaceButtonContribution.ID, OpenWorkspaceButtonContribution); // Register Editor Status Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorStatus, LifecyclePhase.Ready); @@ -227,7 +227,10 @@ Registry.as(WorkbenchExtensions.Workbench).regi const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeModeAction, ChangeModeAction.ID, ChangeModeAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode'); registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEOLAction, ChangeEOLAction.ID, ChangeEOLAction.LABEL), 'Change End of Line Sequence'); -registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL), 'Change File Encoding'); + +if (Object.keys(SUPPORTED_ENCODINGS).length > 1) { + registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL), 'Change File Encoding'); +} export class QuickOpenActionContributor extends ActionBarContributor { private openToSideActionInstance: OpenToSideFromQuickOpenAction | undefined; @@ -585,7 +588,7 @@ appendEditorToolItem( appendEditorToolItem( { id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, - title: nls.localize('ignoreTrimWhitespace.label', "Ignore Trim Whitespace"), + title: nls.localize('ignoreTrimWhitespace.label', "Ignore Leading/Trailing Whitespace Differences"), iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-dark.svg')), iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-light.svg')) }, @@ -597,7 +600,7 @@ appendEditorToolItem( appendEditorToolItem( { id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, - title: nls.localize('showTrimWhitespace.label', "Show Trim Whitespace"), + title: nls.localize('showTrimWhitespace.label', "Show Leading/Trailing Whitespace Differences"), iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-disabled-dark.svg')), iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-disabled-light.svg')) }, diff --git a/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts index b2e46d001d6..39bf1a94e44 100644 --- a/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -5,7 +5,7 @@ import { GroupIdentifier, IWorkbenchEditorConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditor, IEditorPartOptions } from 'vs/workbench/common/editor'; import { EditorGroup } from 'vs/workbench/common/editor/editorGroup'; -import { IEditorGroup, GroupDirection, IAddGroupOptions, IMergeGroupOptions, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorGroup, GroupDirection, IAddGroupOptions, IMergeGroupOptions, GroupsOrder, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Dimension } from 'vs/base/browser/dom'; import { Event } from 'vs/base/common/event'; @@ -37,7 +37,8 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = { openSideBySideDirection: 'right', closeEmptyGroups: true, labelFormat: 'default', - iconTheme: 'vs-seti' + iconTheme: 'vs-seti', + splitSizing: 'distribute' }; export function impactsEditorPartOptions(event: IConfigurationChangeEvent): boolean { @@ -103,6 +104,8 @@ export interface IEditorGroupsAccessor { copyGroup(group: IEditorGroupView | GroupIdentifier, location: IEditorGroupView | GroupIdentifier, direction: GroupDirection): IEditorGroupView; removeGroup(group: IEditorGroupView | GroupIdentifier): void; + + arrangeGroups(arrangement: GroupsArrangement, target?: IEditorGroupView | GroupIdentifier): void; } export interface IEditorGroupView extends IDisposable, ISerializableView, IEditorGroup { diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index a57849a4b8c..5968708814a 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -16,12 +16,12 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; import { CLOSE_EDITOR_COMMAND_ID, NAVIGATE_ALL_EDITORS_GROUP_PREFIX, MOVE_ACTIVE_EDITOR_COMMAND_ID, NAVIGATE_IN_ACTIVE_GROUP_PREFIX, ActiveEditorMoveArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, mergeAllGroups } from 'vs/workbench/browser/parts/editor/editorCommands'; import { IEditorGroupsService, IEditorGroup, GroupsArrangement, EditorsOrder, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; export class ExecuteCommandAction extends Action { @@ -425,7 +425,7 @@ export class OpenToSideFromQuickOpenAction extends Action { const input = entry.getInput(); if (input) { if (input instanceof EditorInput) { - return this.editorService.openEditor(input, entry.getOptions() || undefined, SIDE_GROUP); + return this.editorService.openEditor(input, entry.getOptions(), SIDE_GROUP); } const resourceInput = input as IResourceInput; @@ -495,7 +495,7 @@ export class CloseOneEditorAction extends Action { group = this.editorGroupService.getGroup(context.groupId); if (group) { - editorIndex = context.editorIndex!; // only allow editor at index if group is valid + editorIndex = context.editorIndex; // only allow editor at index if group is valid } } @@ -1218,7 +1218,7 @@ export class ClearRecentFilesAction extends Action { constructor( id: string, label: string, - @IWindowsService private readonly windowsService: IWindowsService, + @IWorkspacesService private readonly workspacesService: IWorkspacesService, @IHistoryService private readonly historyService: IHistoryService ) { super(id, label); @@ -1227,7 +1227,7 @@ export class ClearRecentFilesAction extends Action { run(): Promise { // Clear global recently opened - this.windowsService.clearRecentlyOpened(); + this.workspacesService.clearRecentlyOpened(); // Clear workspace specific recently opened this.historyService.clearRecentlyOpened(); diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 654a9c96650..38bdcd700ce 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -606,6 +606,10 @@ function registerCloseEditorCommands() { .map(context => typeof context.editorIndex === 'number' ? group.getEditor(context.editorIndex) : group.activeEditor); const editorsToClose = group.editors.filter(e => editors.indexOf(e) === -1); + if (group.activeEditor) { + group.pinEditor(group.activeEditor); + } + return group.closeEditors(editorsToClose); } @@ -624,6 +628,10 @@ function registerCloseEditorCommands() { const { group, editor } = resolveCommandsContext(editorGroupService, getCommandsContext(resourceOrContext, context)); if (group && editor) { + if (group.activeEditor) { + group.pinEditor(group.activeEditor); + } + return group.closeEditors({ direction: CloseDirection.RIGHT, except: editor }); } @@ -744,7 +752,7 @@ export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsCon const selection: Array = list.getSelectedElements().filter(onlyEditorGroupAndEditor); // Only respect selection if it contains focused element - if (selection && selection.some(s => { + if (selection?.some(s => { if (isEditorGroup(s)) { return s.id === focus.groupId; } diff --git a/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts index 898d7339fef..3fe6abaef73 100644 --- a/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -15,6 +15,7 @@ import { IEditorProgressService, LongRunningOperation } from 'vs/platform/progre import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; import { Event, Emitter } from 'vs/base/common/event'; import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService'; +import { assertIsDefined } from 'vs/base/common/types'; export interface IOpenEditorResult { readonly control: BaseEditor; @@ -88,8 +89,9 @@ export class EditorControl extends Disposable { this.doSetActiveControl(control); // Show editor - this.parent.appendChild(control.getContainer()); - show(control.getContainer()); + const container = assertIsDefined(control.getContainer()); + this.parent.appendChild(container); + show(container); // Indicate to editor that it is now visible control.setVisible(true, this.groupView); @@ -154,7 +156,7 @@ export class EditorControl extends Disposable { // If the input did not change, return early and only apply the options // unless the options instruct us to force open it even if it is the same - const forceReload = options && options.forceReload; + const forceReload = options?.forceReload; const inputMatches = control.input && control.input.matches(editor); if (inputMatches && !forceReload) { @@ -203,8 +205,10 @@ export class EditorControl extends Disposable { // Remove control from parent and hide const controlInstanceContainer = this._activeControl.getContainer(); - this.parent.removeChild(controlInstanceContainer); - hide(controlInstanceContainer); + if (controlInstanceContainer) { + this.parent.removeChild(controlInstanceContainer); + hide(controlInstanceContainer); + } // Indicate to editor control this._activeControl.clearInput(); diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 2113a4e7c50..09574ed1708 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -4,18 +4,20 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/editordroptarget'; -import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, DragAndDropObserver } from 'vs/workbench/browser/dnd'; +import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, DragAndDropObserver, containsDragType } from 'vs/workbench/browser/dnd'; import { addDisposableListener, EventType, EventHelper, isAncestor, toggleClass, addClass, removeClass } from 'vs/base/browser/dom'; import { IEditorGroupsAccessor, EDITOR_TITLE_HEIGHT, IEditorGroupView, getActiveTextEditorOptions } from 'vs/workbench/browser/parts/editor/editor'; import { EDITOR_DRAG_AND_DROP_BACKGROUND, Themable } from 'vs/workbench/common/theme'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { IEditorIdentifier, EditorInput, EditorOptions } from 'vs/workbench/common/editor'; -import { isMacintosh } from 'vs/base/common/platform'; +import { isMacintosh, isWeb } from 'vs/base/common/platform'; import { GroupDirection, MergeGroupMode } from 'vs/workbench/services/editor/common/editorGroupsService'; import { toDisposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { find } from 'vs/base/common/arrays'; +import { DataTransfers } from 'vs/base/browser/dnd'; interface IDropOperation { splitDirection?: GroupDirection; @@ -23,7 +25,7 @@ interface IDropOperation { class DropOverlay extends Themable { - private static OVERLAY_ID = 'monaco-workbench-editor-drop-overlay'; + private static readonly OVERLAY_ID = 'monaco-workbench-editor-drop-overlay'; private container!: HTMLElement; private overlay!: HTMLElement; @@ -84,7 +86,7 @@ class DropOverlay extends Themable { protected updateStyles(): void { // Overlay drop background - this.overlay.style.backgroundColor = this.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND); + this.overlay.style.backgroundColor = this.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND) || ''; // Overlay contrast border (if any) const activeContrastBorderColor = this.getColor(activeContrastBorder); @@ -98,6 +100,10 @@ class DropOverlay extends Themable { this._register(new DragAndDropObserver(this.container, { onDragEnter: e => undefined, onDragOver: e => { + if (isWeb && containsDragType(e, DataTransfers.FILES)) { + return; // dropping files into editor is unsupported on web + } + const isDraggingGroup = this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype); const isDraggingEditor = this.editorTransfer.hasData(DraggedEditorIdentifier.prototype); @@ -108,7 +114,16 @@ class DropOverlay extends Themable { } // Find out if operation is valid - const isCopy = isDraggingGroup ? this.isCopyOperation(e) : isDraggingEditor ? this.isCopyOperation(e, this.editorTransfer.getData(DraggedEditorIdentifier.prototype)![0].identifier) : true; + let isCopy = true; + if (isDraggingGroup) { + isCopy = this.isCopyOperation(e); + } else if (isDraggingEditor) { + const data = this.editorTransfer.getData(DraggedEditorIdentifier.prototype); + if (Array.isArray(data)) { + isCopy = this.isCopyOperation(e, data[0].identifier); + } + } + if (!isCopy) { const sourceGroupView = this.findSourceGroupView(); if (sourceGroupView === this.groupView) { @@ -162,12 +177,18 @@ class DropOverlay extends Themable { // Check for group transfer if (this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype)) { - return this.accessor.getGroup(this.groupTransfer.getData(DraggedEditorGroupIdentifier.prototype)![0].identifier); + const data = this.groupTransfer.getData(DraggedEditorGroupIdentifier.prototype); + if (Array.isArray(data)) { + return this.accessor.getGroup(data[0].identifier); + } } // Check for editor transfer else if (this.editorTransfer.hasData(DraggedEditorIdentifier.prototype)) { - return this.accessor.getGroup(this.editorTransfer.getData(DraggedEditorIdentifier.prototype)![0].identifier.groupId); + const data = this.editorTransfer.getData(DraggedEditorIdentifier.prototype); + if (Array.isArray(data)) { + return this.accessor.getGroup(data[0].identifier.groupId); + } } return undefined; @@ -189,69 +210,75 @@ class DropOverlay extends Themable { // Check for group transfer if (this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype)) { - const draggedEditorGroup = this.groupTransfer.getData(DraggedEditorGroupIdentifier.prototype)![0].identifier; + const data = this.groupTransfer.getData(DraggedEditorGroupIdentifier.prototype); + if (Array.isArray(data)) { + const draggedEditorGroup = data[0].identifier; - // Return if the drop is a no-op - const sourceGroup = this.accessor.getGroup(draggedEditorGroup); - if (sourceGroup) { - if (typeof splitDirection !== 'number' && sourceGroup === this.groupView) { - return; - } + // Return if the drop is a no-op + const sourceGroup = this.accessor.getGroup(draggedEditorGroup); + if (sourceGroup) { + if (typeof splitDirection !== 'number' && sourceGroup === this.groupView) { + return; + } - // Split to new group - let targetGroup: IEditorGroupView | undefined; - if (typeof splitDirection === 'number') { - if (this.isCopyOperation(event)) { - targetGroup = this.accessor.copyGroup(sourceGroup, this.groupView, splitDirection); - } else { - targetGroup = this.accessor.moveGroup(sourceGroup, this.groupView, splitDirection); + // Split to new group + let targetGroup: IEditorGroupView | undefined; + if (typeof splitDirection === 'number') { + if (this.isCopyOperation(event)) { + targetGroup = this.accessor.copyGroup(sourceGroup, this.groupView, splitDirection); + } else { + targetGroup = this.accessor.moveGroup(sourceGroup, this.groupView, splitDirection); + } + } + + // Merge into existing group + else { + if (this.isCopyOperation(event)) { + targetGroup = this.accessor.mergeGroup(sourceGroup, this.groupView, { mode: MergeGroupMode.COPY_EDITORS }); + } else { + targetGroup = this.accessor.mergeGroup(sourceGroup, this.groupView); + } + } + + if (targetGroup) { + this.accessor.activateGroup(targetGroup); } } - // Merge into existing group - else { - if (this.isCopyOperation(event)) { - targetGroup = this.accessor.mergeGroup(sourceGroup, this.groupView, { mode: MergeGroupMode.COPY_EDITORS }); - } else { - targetGroup = this.accessor.mergeGroup(sourceGroup, this.groupView); - } - } - - if (targetGroup) { - this.accessor.activateGroup(targetGroup); - } + this.groupTransfer.clearData(DraggedEditorGroupIdentifier.prototype); } - - this.groupTransfer.clearData(DraggedEditorGroupIdentifier.prototype); } // Check for editor transfer else if (this.editorTransfer.hasData(DraggedEditorIdentifier.prototype)) { - const draggedEditor = this.editorTransfer.getData(DraggedEditorIdentifier.prototype)![0].identifier; - const targetGroup = ensureTargetGroup(); + const data = this.editorTransfer.getData(DraggedEditorIdentifier.prototype); + if (Array.isArray(data)) { + const draggedEditor = data[0].identifier; + const targetGroup = ensureTargetGroup(); - // Return if the drop is a no-op - const sourceGroup = this.accessor.getGroup(draggedEditor.groupId); - if (sourceGroup) { - if (sourceGroup === targetGroup) { - return; + // Return if the drop is a no-op + const sourceGroup = this.accessor.getGroup(draggedEditor.groupId); + if (sourceGroup) { + if (sourceGroup === targetGroup) { + return; + } + + // Open in target group + const options = getActiveTextEditorOptions(sourceGroup, draggedEditor.editor, EditorOptions.create({ pinned: true })); + targetGroup.openEditor(draggedEditor.editor, options); + + // Ensure target has focus + targetGroup.focus(); + + // Close in source group unless we copy + const copyEditor = this.isCopyOperation(event, draggedEditor); + if (!copyEditor) { + sourceGroup.closeEditor(draggedEditor.editor); + } } - // Open in target group - const options = getActiveTextEditorOptions(sourceGroup, draggedEditor.editor, EditorOptions.create({ pinned: true })); - targetGroup.openEditor(draggedEditor.editor, options); - - // Ensure target has focus - targetGroup.focus(); - - // Close in source group unless we copy - const copyEditor = this.isCopyOperation(event, draggedEditor); - if (!copyEditor) { - sourceGroup.closeEditor(draggedEditor.editor); - } + this.editorTransfer.clearData(DraggedEditorIdentifier.prototype); } - - this.editorTransfer.clearData(DraggedEditorIdentifier.prototype); } // Check for URI transfer @@ -266,7 +293,7 @@ class DropOverlay extends Themable { } private isCopyOperation(e: DragEvent, draggedEditor?: IEditorIdentifier): boolean { - if (draggedEditor && draggedEditor.editor instanceof EditorInput && !draggedEditor.editor.supportsSplitEditor()) { + if (draggedEditor?.editor instanceof EditorInput && !draggedEditor.editor.supportsSplitEditor()) { return false; } @@ -438,6 +465,10 @@ class DropOverlay extends Themable { } } +export interface EditorDropTargetDelegate { + groupContainsPredicate?(groupView: IEditorGroupView): boolean; +} + export class EditorDropTarget extends Themable { private _overlay?: DropOverlay; @@ -450,6 +481,7 @@ export class EditorDropTarget extends Themable { constructor( private accessor: IEditorGroupsAccessor, private container: HTMLElement, + private readonly delegate: EditorDropTargetDelegate, @IThemeService themeService: IThemeService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { @@ -523,13 +555,7 @@ export class EditorDropTarget extends Themable { private findTargetGroupView(child: HTMLElement): IEditorGroupView | undefined { const groups = this.accessor.groups; - for (const groupView of groups) { - if (isAncestor(child, groupView.element)) { - return groupView; - } - } - - return undefined; + return find(groups, groupView => isAncestor(child, groupView.element) || this.delegate.groupContainsPredicate?.(groupView)); } private updateContainer(isDraggedOver: boolean): void { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index c1de6319db0..e88315780d5 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -21,7 +21,7 @@ import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChan import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleControl'; import { EditorControl } from 'vs/workbench/browser/parts/editor/editorControl'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; -import { EditorProgressService } from 'vs/workbench/services/progress/browser/editorProgressService'; +import { EditorProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; import { localize } from 'vs/nls'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { dispose, MutableDisposable } from 'vs/base/common/lifecycle'; @@ -49,7 +49,8 @@ import { hash } from 'vs/base/common/hash'; import { guessMimeTypes } from 'vs/base/common/mime'; import { extname } from 'vs/base/common/resources'; import { Schemas } from 'vs/base/common/network'; -import { EditorActivation } from 'vs/platform/editor/common/editor'; +import { EditorActivation, EditorOpenContext } from 'vs/platform/editor/common/editor'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; export class EditorGroupView extends Themable implements IEditorGroupView { @@ -95,13 +96,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#endregion private _group: EditorGroup; - private _disposed: boolean; + private _disposed = false; - private active: boolean; - private dimension: Dimension; + private active: boolean | undefined; + private dimension: Dimension | undefined; private _whenRestored: Promise; - private isRestored: boolean; + private isRestored = false; private scopedInstantiationService: IInstantiationService; @@ -119,12 +120,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView { constructor( private accessor: IEditorGroupsAccessor, - from: IEditorGroupView | ISerializedEditorGroup, + from: IEditorGroupView | ISerializedEditorGroup | null, private _index: number, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, @INotificationService private readonly notificationService: INotificationService, + @IDialogService private readonly dialogService: IDialogService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, @IKeybindingService private readonly keybindingService: IKeybindingService, @@ -143,7 +145,68 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.disposedEditorsWorker = this._register(new RunOnceWorker(editors => this.handleDisposedEditors(editors), 0)); - this.create(); + //#region create() + { + // Container + addClasses(this.element, 'editor-group-container'); + + // Container listeners + this.registerContainerListeners(); + + // Container toolbar + this.createContainerToolbar(); + + // Container context menu + this.createContainerContextMenu(); + + // Letterpress container + const letterpressContainer = document.createElement('div'); + addClass(letterpressContainer, 'editor-group-letterpress'); + this.element.appendChild(letterpressContainer); + + // Progress bar + this.progressBar = this._register(new ProgressBar(this.element)); + this._register(attachProgressBarStyler(this.progressBar, this.themeService)); + this.progressBar.hide(); + + // Scoped services + const scopedContextKeyService = this._register(this.contextKeyService.createScoped(this.element)); + this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection( + [IContextKeyService, scopedContextKeyService], + [IEditorProgressService, this._register(new EditorProgressIndicator(this.progressBar, this))] + )); + + // Context keys + this.handleGroupContextKeys(scopedContextKeyService); + + // Title container + this.titleContainer = document.createElement('div'); + addClass(this.titleContainer, 'title'); + this.element.appendChild(this.titleContainer); + + // Title control + this.titleAreaControl = this.createTitleAreaControl(); + + // Editor container + this.editorContainer = document.createElement('div'); + addClass(this.editorContainer, 'editor-container'); + this.element.appendChild(this.editorContainer); + + // Editor control + this.editorControl = this._register(this.scopedInstantiationService.createInstance(EditorControl, this.editorContainer, this)); + this._onDidChange.input = this.editorControl.onDidSizeConstraintsChange; + + // Track Focus + this.doTrackFocus(); + + // Update containers + this.updateTitleContainer(); + this.updateContainer(); + + // Update styles + this.updateStyles(); + } + //#endregion this._whenRestored = this.restoreEditors(from); this._whenRestored.then(() => this.isRestored = true); @@ -151,68 +214,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.registerListeners(); } - private create(): void { - - // Container - addClasses(this.element, 'editor-group-container'); - - // Container listeners - this.registerContainerListeners(); - - // Container toolbar - this.createContainerToolbar(); - - // Container context menu - this.createContainerContextMenu(); - - // Letterpress container - const letterpressContainer = document.createElement('div'); - addClass(letterpressContainer, 'editor-group-letterpress'); - this.element.appendChild(letterpressContainer); - - // Progress bar - this.progressBar = this._register(new ProgressBar(this.element)); - this._register(attachProgressBarStyler(this.progressBar, this.themeService)); - this.progressBar.hide(); - - // Scoped services - const scopedContextKeyService = this._register(this.contextKeyService.createScoped(this.element)); - this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection( - [IContextKeyService, scopedContextKeyService], - [IEditorProgressService, new EditorProgressService(this.progressBar)] - )); - - // Context keys - this.handleGroupContextKeys(scopedContextKeyService); - - // Title container - this.titleContainer = document.createElement('div'); - addClass(this.titleContainer, 'title'); - this.element.appendChild(this.titleContainer); - - // Title control - this.createTitleAreaControl(); - - // Editor container - this.editorContainer = document.createElement('div'); - addClass(this.editorContainer, 'editor-container'); - this.element.appendChild(this.editorContainer); - - // Editor control - this.editorControl = this._register(this.scopedInstantiationService.createInstance(EditorControl, this.editorContainer, this)); - this._onDidChange.input = this.editorControl.onDidSizeConstraintsChange; - - // Track Focus - this.doTrackFocus(); - - // Update containers - this.updateTitleContainer(); - this.updateContainer(); - - // Update styles - this.updateStyles(); - } - private handleGroupContextKeys(contextKeyService: IContextKeyService): void { const groupActiveEditorDirtyContextKey = EditorGroupActiveEditorDirtyContext.bindTo(contextKeyService); const groupEditorsCountContext = EditorGroupEditorsCountContext.bindTo(contextKeyService); @@ -289,7 +290,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { const removeGroupAction = this._register(new Action( CLOSE_EDITOR_GROUP_COMMAND_ID, localize('closeGroupAction', "Close"), - 'close-editor-group', + 'codicon-close', true, () => { this.accessor.removeGroup(this); @@ -404,7 +405,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { toggleClass(this.titleContainer, 'show-file-icons', this.accessor.partOptions.showIcons); } - private createTitleAreaControl(): void { + private createTitleAreaControl(): TitleControl { // Clear old if existing if (this.titleAreaControl) { @@ -418,9 +419,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } else { this.titleAreaControl = this.scopedInstantiationService.createInstance(NoTabsTitleControl, this.titleContainer, this.accessor, this); } + + return this.titleAreaControl; } - private async restoreEditors(from: IEditorGroupView | ISerializedEditorGroup): Promise { + private async restoreEditors(from: IEditorGroupView | ISerializedEditorGroup | null): Promise { if (this._group.count === 0) { return; // nothing to show } @@ -596,7 +599,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Recreate and layout control this.createTitleAreaControl(); - this.layoutTitleAreaControl(); + if (this.dimension) { + this.layoutTitleAreaControl(this.dimension.width); + } // Ensure to show active editor if any if (this._group.activeEditor) { @@ -821,7 +826,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Determine options const openEditorOptions: IEditorOpenOptions = { index: options ? options.index : undefined, - pinned: !this.accessor.partOptions.enablePreview || editor.isDirty() || (options && options.pinned) || (options && typeof options.index === 'number'), + pinned: !this.accessor.partOptions.enablePreview || editor.isDirty() || options?.pinned || typeof options?.index === 'number', active: this._group.count === 0 || !options || !options.inactive }; @@ -835,13 +840,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView { let activateGroup = false; let restoreGroup = false; - if (options && options.activation === EditorActivation.ACTIVATE) { + if (options?.activation === EditorActivation.ACTIVATE) { // Respect option to force activate an editor group. activateGroup = true; - } else if (options && options.activation === EditorActivation.RESTORE) { + } else if (options?.activation === EditorActivation.RESTORE) { // Respect option to force restore an editor group. restoreGroup = true; - } else if (options && options.activation === EditorActivation.PRESERVE) { + } else if (options?.activation === EditorActivation.PRESERVE) { // Respect option to preserve active editor group. activateGroup = false; restoreGroup = false; @@ -913,23 +918,67 @@ export class EditorGroupView extends Themable implements IEditorGroupView { return openEditorPromise; } - private doHandleOpenEditorError(error: Error, editor: EditorInput, options?: EditorOptions): void { + private async doHandleOpenEditorError(error: Error, editor: EditorInput, options?: EditorOptions): Promise { // Report error only if this was not us restoring previous error state or // we are told to ignore errors that occur from opening an editor if (this.isRestored && !isPromiseCanceledError(error) && (!options || !options.ignoreError)) { - const actions: INotificationActions = { primary: [] }; + + // Extract possible error actions from the error + let errorActions: ReadonlyArray | undefined = undefined; if (isErrorWithActions(error)) { - actions.primary = (error as IErrorWithActions).actions; + errorActions = (error as IErrorWithActions).actions; } - const handle = this.notificationService.notify({ - severity: Severity.Error, - message: localize('editorOpenError', "Unable to open '{0}': {1}.", editor.getName(), toErrorMessage(error)), - actions - }); + // If the context is USER, we try to show a modal dialog instead of a background notification + if (options?.context === EditorOpenContext.USER) { + const buttons: string[] = []; + if (Array.isArray(errorActions) && errorActions.length > 0) { + errorActions.forEach(action => buttons.push(action.label)); + } else { + buttons.push(localize('ok', 'OK')); + } - Event.once(handle.onDidClose)(() => actions.primary && dispose(actions.primary)); + let cancelId: number | undefined = undefined; + if (buttons.length === 1) { + buttons.push(localize('cancel', "Cancel")); + cancelId = 1; + } + + const result = await this.dialogService.show( + Severity.Error, + localize('editorOpenErrorDialog', "Unable to open '{0}'", editor.getName()), + buttons, + { + detail: toErrorMessage(error), + cancelId + } + ); + + // Make sure to run any error action if present + if (result.choice !== cancelId && Array.isArray(errorActions)) { + const errorAction = errorActions[result.choice]; + if (errorAction) { + errorAction.run(); + } + } + } + + // Otherwise, show a background notification. + else { + const actions: INotificationActions = { primary: [] }; + if (Array.isArray(errorActions)) { + actions.primary = errorActions; + } + + const handle = this.notificationService.notify({ + severity: Severity.Error, + message: localize('editorOpenError', "Unable to open '{0}': {1}.", editor.getName(), toErrorMessage(error)), + actions + }); + + Event.once(handle.onDidClose)(() => actions.primary && dispose(actions.primary)); + } } // Event @@ -1065,7 +1114,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } // Do close - this.doCloseEditor(editor, options && options.preserveFocus ? false : undefined); + this.doCloseEditor(editor, options?.preserveFocus ? false : undefined); } private doCloseEditor(editor: EditorInput, focusNext = (this.accessor.activeGroup === this), fromError?: boolean): void { @@ -1314,7 +1363,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Close active editor last if contained in editors list to close if (closeActiveEditor) { - this.doCloseActiveEditor(options && options.preserveFocus ? false : undefined); + this.doCloseActiveEditor(options?.preserveFocus ? false : undefined); } // Forward to title control @@ -1442,9 +1491,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Container if (isEmpty) { - this.element.style.backgroundColor = this.getColor(EDITOR_GROUP_EMPTY_BACKGROUND); + this.element.style.backgroundColor = this.getColor(EDITOR_GROUP_EMPTY_BACKGROUND) || ''; } else { - this.element.style.backgroundColor = null; + this.element.style.backgroundColor = ''; } // Title control @@ -1459,10 +1508,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.titleContainer.style.removeProperty('--title-border-bottom-color'); } - this.titleContainer.style.backgroundColor = this.getColor(showTabs ? EDITOR_GROUP_HEADER_TABS_BACKGROUND : EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND); + this.titleContainer.style.backgroundColor = this.getColor(showTabs ? EDITOR_GROUP_HEADER_TABS_BACKGROUND : EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND) || ''; // Editor container - this.editorContainer.style.backgroundColor = this.getColor(editorBackground); + this.editorContainer.style.backgroundColor = this.getColor(editorBackground) || ''; } //#endregion @@ -1487,12 +1536,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.editorContainer.style.height = `calc(100% - ${this.titleAreaControl.getPreferredHeight()}px)`; // Forward to controls - this.layoutTitleAreaControl(); + this.layoutTitleAreaControl(width); this.editorControl.layout(new Dimension(this.dimension.width, this.dimension.height - this.titleAreaControl.getPreferredHeight())); } - private layoutTitleAreaControl(): void { - this.titleAreaControl.layout(new Dimension(this.dimension.width, this.titleAreaControl.getPreferredHeight())); + private layoutTitleAreaControl(width: number): void { + this.titleAreaControl.layout(new Dimension(width, this.titleAreaControl.getPreferredHeight())); } relayout(): void { @@ -1520,7 +1569,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } class EditorOpeningEvent implements IEditorOpeningEvent { - private override: () => Promise; + private override: (() => Promise) | undefined = undefined; constructor( private _group: GroupIdentifier, @@ -1545,7 +1594,7 @@ class EditorOpeningEvent implements IEditorOpeningEvent { this.override = callback; } - isPrevented(): () => Promise { + isPrevented(): (() => Promise) | undefined { return this.override; } } diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index a3dec299bc6..83b1c0cabe3 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -23,13 +23,14 @@ import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/com import { assign } from 'vs/base/common/objects'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup'; -import { EditorDropTarget } from 'vs/workbench/browser/parts/editor/editorDropTarget'; +import { EditorDropTarget, EditorDropTargetDelegate } from 'vs/workbench/browser/parts/editor/editorDropTarget'; import { Color } from 'vs/base/common/color'; import { CenteredViewLayout } from 'vs/base/browser/ui/centered/centeredViewLayout'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { MementoObject } from 'vs/workbench/common/memento'; +import { assertIsDefined } from 'vs/base/common/types'; interface IEditorPartUIState { serializedGrid: ISerializedGrid; @@ -49,13 +50,13 @@ class GridWidgetView implements IView { private _onDidChange = new Relay<{ width: number; height: number; } | undefined>(); readonly onDidChange: Event<{ width: number; height: number; } | undefined> = this._onDidChange.event; - private _gridWidget: Grid; + private _gridWidget: Grid | undefined; - get gridWidget(): Grid { + get gridWidget(): Grid | undefined { return this._gridWidget; } - set gridWidget(grid: Grid) { + set gridWidget(grid: Grid | undefined) { this.element.innerHTML = ''; if (grid) { @@ -113,9 +114,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>()); get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return Event.any(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event); } - private _onDidVisibilityChange = this._register(new Emitter()); - readonly onDidVisibilityChange: Event = this._onDidVisibilityChange.event; - //#endregion private readonly workspaceMemento: MementoObject; @@ -123,17 +121,18 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro private _partOptions: IEditorPartOptions; - private _activeGroup: IEditorGroupView; private groupViews: Map = new Map(); private mostRecentActiveGroups: GroupIdentifier[] = []; - private container: HTMLElement; - private centeredLayoutWidget: CenteredViewLayout; - private gridWidget: SerializableGrid; + private container: HTMLElement | undefined; + + private centeredLayoutWidget!: CenteredViewLayout; + + private gridWidget!: SerializableGrid; private gridWidgetView: GridWidgetView; private _whenRestored: Promise; - private whenRestoredResolve: () => void; + private whenRestoredResolve: (() => void) | undefined; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -204,9 +203,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#region IEditorGroupsService - private _contentDimension: Dimension; + private _contentDimension!: Dimension; get contentDimension(): Dimension { return this._contentDimension; } + private _activeGroup!: IEditorGroupView; get activeGroup(): IEditorGroupView { return this._activeGroup; } @@ -463,7 +463,11 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } } - private shouldRestoreFocus(target: Element): boolean { + private shouldRestoreFocus(target: Element | undefined): boolean { + if (!target) { + return false; + } + const activeElement = document.activeElement; if (activeElement === document.body) { @@ -490,7 +494,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro const group = this.doAddGroup(locationView, direction); - if (options && options.activate) { + if (options?.activate) { this.doSetGroupActive(group); } @@ -503,7 +507,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Add to grid widget this.gridWidget.addView( newGroupView, - Sizing.Distribute, + this.getSplitSizingStyle(), locationView, this.toGridViewDirection(direction), ); @@ -520,6 +524,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro return newGroupView; } + private getSplitSizingStyle(): Sizing { + return this._partOptions.splitSizing === 'split' ? Sizing.Split : Sizing.Distribute; + } + private doCreateGroupView(from?: IEditorGroupView | ISerializedEditorGroup | null): IEditorGroupView { // Create group view @@ -670,7 +678,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } // Remove from grid widget & dispose - this.gridWidget.removeView(groupView, Sizing.Distribute); + this.gridWidget.removeView(groupView, this.getSplitSizingStyle()); groupView.dispose(); // Restore focus if we had it previously (we run this after gridWidget.removeView() is called @@ -700,7 +708,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro const restoreFocus = this.shouldRestoreFocus(sourceView.element); // Move through grid widget API - this.gridWidget.moveView(sourceView, Sizing.Distribute, targetView, this.toGridViewDirection(direction)); + this.gridWidget.moveView(sourceView, this.getSplitSizingStyle(), targetView, this.toGridViewDirection(direction)); // Restore focus if we had it previously (we run this after gridWidget.removeView() is called // because removing a view can mean to reparent it and thus focus would be removed otherwise) @@ -744,7 +752,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro const inactive = !sourceView.isActive(editor) || this._activeGroup !== sourceView; const copyOptions: ICopyEditorOptions = { index, inactive, preserveFocus: inactive }; - if (options && options.mode === MergeGroupMode.COPY_EDITORS) { + if (options?.mode === MergeGroupMode.COPY_EDITORS) { sourceView.copyEditor(editor, targetView, copyOptions); } else { sourceView.moveEditor(editor, targetView, copyOptions); @@ -796,7 +804,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } updateStyles(): void { - this.container.style.backgroundColor = this.getColor(editorBackground); + const container = assertIsDefined(this.container); + container.style.backgroundColor = this.getColor(editorBackground) || ''; const separatorBorderStyle = { separatorBorder: this.gridSeparatorBorder, background: this.theme.getColor(EDITOR_PANE_BACKGROUND) || Color.transparent }; this.gridWidget.style(separatorBorderStyle); @@ -817,7 +826,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro this.centeredLayoutWidget = this._register(new CenteredViewLayout(this.container, this.gridWidgetView, this.globalMemento[EditorPart.EDITOR_PART_CENTERED_VIEW_STORAGE_KEY])); // Drop support - this._register(this.instantiationService.createInstance(EditorDropTarget, this, this.container)); + this._register(this.createEditorDropTarget(this.container, {})); return this.container; } @@ -850,7 +859,11 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } // Signal restored - Promise.all(this.groups.map(group => group.whenRestored)).finally(() => this.whenRestoredResolve()); + Promise.all(this.groups.map(group => group.whenRestored)).finally(() => { + if (this.whenRestoredResolve) { + this.whenRestoredResolve(); + } + }); // Update container this.updateContainer(); @@ -861,7 +874,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro private doCreateGridControlWithPreviousState(): boolean { const uiState: IEditorPartUIState = this.workspaceMemento[EditorPart.EDITOR_PART_UI_STATE_STORAGE_KEY]; - if (uiState && uiState.serializedGrid) { + if (uiState?.serializedGrid) { try { // MRU @@ -950,7 +963,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } private updateContainer(): void { - toggleClass(this.container, 'empty', this.isEmpty); + const container = assertIsDefined(this.container); + toggleClass(container, 'empty', this.isEmpty); } private notifyGroupIndexChange(): void { @@ -1024,15 +1038,19 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#endregion - setVisible(visible: boolean): void { - this._onDidVisibilityChange.fire(visible); - } - toJSON(): object { return { type: Parts.EDITOR_PART }; } + + //#region TODO@matt this should move into some kind of service + + createEditorDropTarget(container: HTMLElement, delegate: EditorDropTargetDelegate): IDisposable { + return this.instantiationService.createInstance(EditorDropTarget, this, container, delegate); + } + + //#endregion } registerSingleton(IEditorGroupsService, EditorPart); diff --git a/src/vs/workbench/browser/parts/editor/editorPicker.ts b/src/vs/workbench/browser/parts/editor/editorPicker.ts index a3d495473f5..1c8e7996d06 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -15,7 +15,7 @@ import { QuickOpenHandler } from 'vs/workbench/browser/quickopen'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService, IEditorGroup, EditorsOrder, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { EditorInput, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; +import { toResource, SideBySideEditor, IEditorInput } from 'vs/workbench/common/editor'; import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; import { CancellationToken } from 'vs/base/common/cancellation'; import { withNullAsUndefined } from 'vs/base/common/types'; @@ -23,7 +23,7 @@ import { withNullAsUndefined } from 'vs/base/common/types'; export class EditorPickerEntry extends QuickOpenEntryGroup { constructor( - private editor: EditorInput, + private editor: IEditorInput, private _group: IEditorGroup, @IModeService private readonly modeService: IModeService, @IModelService private readonly modelService: IModelService diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 76fc6248804..5bcf1ff5f5d 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/editorstatus'; import * as nls from 'vs/nls'; import { runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { format } from 'vs/base/common/strings'; -import { extname, basename } from 'vs/base/common/resources'; +import { extname, basename, isEqual } from 'vs/base/common/resources'; import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; @@ -39,7 +39,7 @@ import { ConfigurationChangedEvent, IEditorOptions, EditorOption } from 'vs/edit import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { deepClone } from 'vs/base/common/objects'; -import { ICodeEditor, isCodeEditor, isDiffEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser'; import { Schemas } from 'vs/base/common/network'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; @@ -49,12 +49,12 @@ import { INotificationHandle, INotificationService, Severity } from 'vs/platform import { Event } from 'vs/base/common/event'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; class SideBySideEditorEncodingSupport implements IEncodingSupport { constructor(private master: IEncodingSupport, private details: IEncodingSupport) { } - getEncoding(): string { + getEncoding(): string | undefined { return this.master.getEncoding(); // always report from modified (right hand) side } @@ -278,7 +278,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { private readonly screenRedearModeElement = this._register(new MutableDisposable()); private readonly indentationElement = this._register(new MutableDisposable()); private readonly selectionElement = this._register(new MutableDisposable()); - private readonly encodingElement = this._register(new MutableDisposable()); + private readonly encodingElement = Object.keys(SUPPORTED_ENCODINGS).length > 1 ? this._register(new MutableDisposable()) : undefined; private readonly eolElement = this._register(new MutableDisposable()); private readonly modeElement = this._register(new MutableDisposable()); private readonly metadataElement = this._register(new MutableDisposable()); @@ -352,7 +352,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return this.quickInputService.pick([{ label: nls.localize('noWritableCodeEditor', "The active code editor is read-only.") }]); } - const picks: QuickPickInput[] = [ + const picks: QuickPickInput[] = [ activeTextEditorWidget.getAction(IndentUsingSpaces.ID), activeTextEditorWidget.getAction(IndentUsingTabs.ID), activeTextEditorWidget.getAction(DetectIndentation.ID), @@ -363,7 +363,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return { id: a.id, label: a.label, - detail: Language.isDefaultVariant() ? undefined : a.alias, + detail: (Language.isDefaultVariant() || a.label === a.alias) ? undefined : a.alias, run: () => { activeTextEditorWidget.focus(); a.run(); @@ -375,7 +375,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { picks.unshift({ type: 'separator', label: nls.localize('indentView', "change view") }); const action = await this.quickInputService.pick(picks, { placeHolder: nls.localize('pickAction', "Select Action"), matchOnDetail: true }); - return action && action.run(); + return action?.run(); } private updateTabFocusModeElement(visible: boolean): void { @@ -412,7 +412,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return; } - const props = { + const props: IStatusbarEntry = { text, tooltip: nls.localize('gotoLine', "Go to Line"), command: 'workbench.action.gotoLine' @@ -427,7 +427,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return; } - const props = { + const props: IStatusbarEntry = { text, tooltip: nls.localize('selectIndentation', "Select Indentation"), command: 'changeEditorIndentation' @@ -437,12 +437,16 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } private updateEncodingElement(text: string | undefined): void { + if (!this.encodingElement) { + return; // return early if encoding should not show (e.g. in Web we only support utf8) + } + if (!text) { this.encodingElement.clear(); return; } - const props = { + const props: IStatusbarEntry = { text, tooltip: nls.localize('selectEncoding', "Select Encoding"), command: 'workbench.action.editor.changeEncoding' @@ -457,7 +461,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return; } - const props = { + const props: IStatusbarEntry = { text, tooltip: nls.localize('selectEOL', "Select End of Line Sequence"), command: 'workbench.action.editor.changeEOL' @@ -472,7 +476,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return; } - const props = { + const props: IStatusbarEntry = { text, tooltip: nls.localize('selectLanguageMode', "Select Language Mode"), command: 'workbench.action.editor.changeLanguageMode' @@ -487,7 +491,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return; } - const props = { + const props: IStatusbarEntry = { text, tooltip: nls.localize('fileInfo', "File Information") }; @@ -570,7 +574,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.onSelectionChange(activeCodeEditor); this.onModeChange(activeCodeEditor); this.onEOLChange(activeCodeEditor); - this.onEncodingChange(activeControl); + this.onEncodingChange(activeControl, activeCodeEditor); this.onIndentationChange(activeCodeEditor); this.onMetadataChange(activeControl); @@ -655,7 +659,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { const textModel = editorWidget.getModel(); if (textModel) { const modeId = textModel.getLanguageIdentifier().language; - info = { mode: this.modeService.getLanguageName(modeId) || undefined }; + info = { mode: withNullAsUndefined(this.modeService.getLanguageName(modeId)) }; } } @@ -730,20 +734,23 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { const textModel = editorWidget.getModel(); if (textModel) { info.selections.forEach(selection => { - info.charactersSelected! += textModel.getValueLengthInRange(selection); + if (typeof info.charactersSelected !== 'number') { + info.charactersSelected = 0; + } + + info.charactersSelected += textModel.getCharacterCountInRange(selection); }); } // Compute the visible column for one selection. This will properly handle tabs and their configured widths if (info.selections.length === 1) { - const visibleColumn = editorWidget.getVisibleColumnFromPosition(editorWidget.getPosition()!); + const editorPosition = editorWidget.getPosition(); - let selectionClone = info.selections[0].clone(); // do not modify the original position we got from the editor - selectionClone = new Selection( - selectionClone.selectionStartLineNumber, - selectionClone.selectionStartColumn, - selectionClone.positionLineNumber, - visibleColumn + let selectionClone = new Selection( + info.selections[0].selectionStartLineNumber, + info.selections[0].selectionStartColumn, + info.selections[0].positionLineNumber, + editorPosition ? editorWidget.getStatusbarColumn(editorPosition) : info.selections[0].positionColumn ); info.selections[0] = selectionClone; @@ -766,19 +773,21 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.updateState(info); } - private onEncodingChange(e?: IBaseEditor): void { - if (e && !this.isActiveEditor(e)) { + private onEncodingChange(editor: IBaseEditor | undefined, editorWidget: ICodeEditor | undefined): void { + if (editor && !this.isActiveEditor(editor)) { return; } const info: StateDelta = { encoding: undefined }; - // We only support text based editors - if (e && (isCodeEditor(e.getControl()) || isDiffEditor(e.getControl()))) { - const encodingSupport: IEncodingSupport | null = e.input ? toEditorWithEncodingSupport(e.input) : null; + // We only support text based editors that have a model associated + // This ensures we do not show the encoding picker while an editor + // is still loading. + if (editor && editorWidget?.hasModel()) { + const encodingSupport: IEncodingSupport | null = editor.input ? toEditorWithEncodingSupport(editor.input) : null; if (encodingSupport) { const rawEncoding = encodingSupport.getEncoding(); - const encodingInfo = SUPPORTED_ENCODINGS[rawEncoding]; + const encodingInfo = typeof rawEncoding === 'string' ? SUPPORTED_ENCODINGS[rawEncoding] : undefined; if (encodingInfo) { info.encoding = encodingInfo.labelShort; // if we have a label, take it from there } else { @@ -794,8 +803,10 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { const activeControl = this.editorService.activeControl; if (activeControl) { const activeResource = toResource(activeControl.input, { supportSideBySide: SideBySideEditor.MASTER }); - if (activeResource && activeResource.toString() === resource.toString()) { - return this.onEncodingChange(activeControl); // only update if the encoding changed for the active resource + if (activeResource && isEqual(activeResource, resource)) { + const activeCodeEditor = withNullAsUndefined(getCodeEditor(activeControl.getControl())); + + return this.onEncodingChange(activeControl, activeCodeEditor); // only update if the encoding changed for the active resource } } } @@ -821,7 +832,7 @@ function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean { } function isWritableBaseEditor(e: IBaseEditor): boolean { - return e && isWritableCodeEditor(getCodeEditor(e.getControl()) || undefined); + return e && isWritableCodeEditor(withNullAsUndefined(getCodeEditor(e.getControl()))); } export class ShowLanguageExtensionsAction extends Action { @@ -873,7 +884,7 @@ export class ChangeModeAction extends Action { const resource = this.editorService.activeEditor ? toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null; let hasLanguageSupport = !!resource; - if (resource && resource.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource)) { + if (resource?.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource)) { hasLanguageSupport = false; // no configuration for untitled resources (e.g. "Untitled-1") } @@ -882,7 +893,7 @@ export class ChangeModeAction extends Action { let modeId: string | undefined; if (textModel) { modeId = textModel.getLanguageIdentifier().language; - currentModeId = this.modeService.getLanguageName(modeId) || undefined; + currentModeId = withNullAsUndefined(this.modeService.getLanguageName(modeId)); } // All languages are valid picks @@ -1032,11 +1043,11 @@ export class ChangeModeAction extends Action { let fakeResource: URI | undefined; const extensions = this.modeService.getExtensions(lang); - if (extensions && extensions.length) { + if (extensions?.length) { fakeResource = URI.file(extensions[0]); } else { const filenames = this.modeService.getFilenames(lang); - if (filenames && filenames.length) { + if (filenames?.length) { fakeResource = URI.file(filenames[0]); } } @@ -1080,12 +1091,12 @@ export class ChangeEOLAction extends Action { { label: nlsEOLCRLF, eol: EndOfLineSequence.CRLF }, ]; - const selectedIndex = (textModel && textModel.getEOL() === '\n') ? 0 : 1; + const selectedIndex = (textModel?.getEOL() === '\n') ? 0 : 1; const eol = await this.quickInputService.pick(EOLOptions, { placeHolder: nls.localize('pickEndOfLine', "Select End of Line Sequence"), activeItem: EOLOptions[selectedIndex] }); if (eol) { const activeCodeEditor = getCodeEditor(this.editorService.activeTextEditorWidget); - if (activeCodeEditor && activeCodeEditor.hasModel() && isWritableCodeEditor(activeCodeEditor)) { + if (activeCodeEditor?.hasModel() && isWritableCodeEditor(activeCodeEditor)) { textModel = activeCodeEditor.getModel(); textModel.pushEOL(eol.eol); } @@ -1125,14 +1136,19 @@ export class ChangeEncodingAction extends Action { return this.quickInputService.pick([{ label: nls.localize('noFileEditor', "No file active at this time") }]); } - let saveWithEncodingPick: IQuickPickItem; - let reopenWithEncodingPick: IQuickPickItem; - if (Language.isDefaultVariant()) { - saveWithEncodingPick = { label: nls.localize('saveWithEncoding', "Save with Encoding") }; - reopenWithEncodingPick = { label: nls.localize('reopenWithEncoding', "Reopen with Encoding") }; - } else { - saveWithEncodingPick = { label: nls.localize('saveWithEncoding', "Save with Encoding"), detail: 'Save with Encoding', }; - reopenWithEncodingPick = { label: nls.localize('reopenWithEncoding', "Reopen with Encoding"), detail: 'Reopen with Encoding' }; + const saveWithEncodingPick: IQuickPickItem = { label: nls.localize('saveWithEncoding', "Save with Encoding") }; + const reopenWithEncodingPick: IQuickPickItem = { label: nls.localize('reopenWithEncoding', "Reopen with Encoding") }; + + if (!Language.isDefaultVariant()) { + const saveWithEncodingAlias = 'Save with Encoding'; + if (saveWithEncodingAlias !== saveWithEncodingPick.label) { + saveWithEncodingPick.detail = saveWithEncodingAlias; + } + + const reopenWithEncodingAlias = 'Reopen with Encoding'; + if (reopenWithEncodingAlias !== reopenWithEncodingPick.label) { + reopenWithEncodingPick.detail = reopenWithEncodingAlias; + } } let action: IQuickPickItem; diff --git a/src/vs/workbench/browser/parts/editor/editorWidgets.ts b/src/vs/workbench/browser/parts/editor/editorWidgets.ts index e086ecdc76f..53652291b68 100644 --- a/src/vs/workbench/browser/parts/editor/editorWidgets.ts +++ b/src/vs/workbench/browser/parts/editor/editorWidgets.ts @@ -8,7 +8,7 @@ import { IOverlayWidget, ICodeEditor, IOverlayWidgetPosition, OverlayWidgetPosit import { Event, Emitter } from 'vs/base/common/event'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { $, append } from 'vs/base/browser/dom'; +import { $, append, clearNode } from 'vs/base/browser/dom'; import { attachStylerCallback } from 'vs/platform/theme/common/styler'; import { buttonBackground, buttonForeground, editorBackground, editorForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -31,12 +31,14 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget { constructor( private editor: ICodeEditor, private label: string, - keyBindingAction: string, + keyBindingAction: string | null, @IKeybindingService keybindingService: IKeybindingService, @IThemeService private readonly themeService: IThemeService ) { super(); + this._domNode = $('.floating-click-widget'); + if (keyBindingAction) { const keybinding = keybindingService.lookupKeybinding(keyBindingAction); if (keybinding) { @@ -60,7 +62,7 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget { } render() { - this._domNode = $('.floating-click-widget'); + clearNode(this._domNode); this._register(attachStylerCallback(this.themeService, { buttonBackground, buttonForeground, editorBackground, editorForeground, contrastBorder }, colors => { const backgroundColor = colors.buttonBackground ? colors.buttonBackground : colors.editorBackground; @@ -73,9 +75,9 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget { this._domNode.style.color = foregroundColor.toString(); } - const borderColor = colors.contrastBorder ? colors.contrastBorder.toString() : null; - this._domNode.style.borderWidth = borderColor ? '1px' : null; - this._domNode.style.borderStyle = borderColor ? 'solid' : null; + const borderColor = colors.contrastBorder ? colors.contrastBorder.toString() : ''; + this._domNode.style.borderWidth = borderColor ? '1px' : ''; + this._domNode.style.borderStyle = borderColor ? 'solid' : ''; this._domNode.style.borderColor = borderColor; })); @@ -99,7 +101,7 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit return editor.getContribution(OpenWorkspaceButtonContribution.ID); } - private static readonly ID = 'editor.contrib.openWorkspaceButton'; + public static readonly ID = 'editor.contrib.openWorkspaceButton'; private openWorkspaceButton: FloatingClickWidget | undefined; @@ -120,10 +122,6 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit this._register(this.editor.onDidChangeModel(e => this.update())); } - getId(): string { - return OpenWorkspaceButtonContribution.ID; - } - private update(): void { if (!this.shouldShowButton(this.editor)) { this.disposeOpenWorkspaceWidgetRenderer(); @@ -163,7 +161,7 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit this._register(this.openWorkspaceButton.onClick(() => { const model = this.editor.getModel(); if (model) { - this.hostService.openInWindow([{ workspaceUri: model.uri }]); + this.hostService.openWindow([{ workspaceUri: model.uri }]); } })); diff --git a/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css b/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css index 1e6e29ee935..98ddd9e96ba 100644 --- a/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css @@ -17,7 +17,7 @@ text-decoration-line: underline; } -.monaco-workbench .monaco-breadcrumb-item.shows-symbol-icon .symbol-icon.block { +.monaco-workbench .monaco-breadcrumb-item.shows-symbol-icon .codicon[class*='codicon-symbol-'] { padding-right: 6px; } diff --git a/src/vs/workbench/browser/parts/editor/media/editorstatus.css b/src/vs/workbench/browser/parts/editor/media/editorstatus.css index ba3fa7d7480..367d9044dd5 100644 --- a/src/vs/workbench/browser/parts/editor/media/editorstatus.css +++ b/src/vs/workbench/browser/parts/editor/media/editorstatus.css @@ -48,4 +48,5 @@ padding-right: 12px; margin-right: 5px; max-width: fit-content; + max-width: -moz-fit-content; } diff --git a/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css index 8bc05e970dd..77a7fa03e7a 100644 --- a/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css @@ -76,6 +76,15 @@ padding-right: 4px; /* does not have trailing separator*/ } +.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item .codicon[class*='codicon-symbol-'] { + padding: 0 1px; +} + +.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item .codicon:last-child, +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child .codicon:last-child { + display: none; /* hides chevrons when no tabs visible and when last items */ +} + /* Title Actions */ .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions { display: flex; diff --git a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css index 0c056ced27d..e2faab1cc32 100644 --- a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css @@ -53,6 +53,8 @@ .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit { width: 120px; min-width: fit-content; + min-width: -moz-fit-content; + flex-shrink: 0; } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink { @@ -60,6 +62,11 @@ flex-basis: 0; /* all tabs are even */ flex-grow: 1; /* all tabs grow even */ max-width: fit-content; + max-width: -moz-fit-content; +} + +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-left .action-label { + margin-right: 4px !important; } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-left::after, @@ -186,7 +193,7 @@ overflow: visible; /* ...but still show the close button on hover, focus and when dirty */ } -.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off > .tab-close { +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off:not(.dirty) > .tab-close { display: none; /* hide the close action bar when we are configured to hide it */ } @@ -198,6 +205,10 @@ opacity: 1; } +.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab > .tab-close .action-label.codicon { + color: inherit; +} + /* change close icon to dirty state icon */ .monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-close .action-label:not(:hover)::before, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-close .action-label:not(:hover)::before { @@ -232,11 +243,17 @@ padding-right: 5px; /* we need less room when sizing is shrink */ } +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty-border-top > .tab-close, +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty-border-top > .tab-close { + display: none; /* hide dirty state when highlightModifiedTabs is enabled and when running without close button */ +} + .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty:not(.dirty-border-top) { - background-repeat: no-repeat; - background-position-y: center; - background-position-x: calc(100% - 6px); /* to the right of the tab label */ - padding-right: 28px; /* make room for dirty indication when we are running without close button */ + padding-right: 0; /* remove extra padding when we are running without close button */ +} + +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off > .tab-close { + pointer-events: none; /* don't allow dirty state/close button to be clicked when running without close button */ } /* Editor Actions */ @@ -270,8 +287,11 @@ } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before { - min-width: 16px; + width: 16px; height: 22px; + display: flex; + align-items: center; + justify-content: center; } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child { diff --git a/src/vs/workbench/browser/parts/editor/media/titlecontrol.css b/src/vs/workbench/browser/parts/editor/media/titlecontrol.css index 86292c1ee09..2c77ffb461d 100644 --- a/src/vs/workbench/browser/parts/editor/media/titlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/titlecontrol.css @@ -40,7 +40,7 @@ } .hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label, -.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label { +.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label:not(.codicon) { line-height: initial; } @@ -49,6 +49,10 @@ display: none; } +.monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label.codicon { + color: inherit; +} + /* Drag Cursor */ .monaco-workbench .part.editor > .content .editor-group-container > .title { cursor: grab; diff --git a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts index 50995662333..1f2612e42ff 100644 --- a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts @@ -14,7 +14,7 @@ import { EDITOR_TITLE_HEIGHT } from 'vs/workbench/browser/parts/editor/editor'; import { IAction } from 'vs/base/common/actions'; import { CLOSE_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; import { Color } from 'vs/base/common/color'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { withNullAsUndefined, assertIsDefined, assertAllDefined } from 'vs/base/common/types'; interface IRenderedEditorLabel { editor?: IEditorInput; @@ -22,23 +22,23 @@ interface IRenderedEditorLabel { } export class NoTabsTitleControl extends TitleControl { - private titleContainer: HTMLElement; - private editorLabel: IResourceLabel; + private titleContainer: HTMLElement | undefined; + private editorLabel: IResourceLabel | undefined; private activeLabel: IRenderedEditorLabel = Object.create(null); protected create(parent: HTMLElement): void { - this.titleContainer = parent; - this.titleContainer.draggable = true; + const titleContainer = this.titleContainer = parent; + titleContainer.draggable = true; //Container listeners - this.registerContainerListeners(); + this.registerContainerListeners(titleContainer); // Gesture Support - Gesture.addTarget(this.titleContainer); + this._register(Gesture.addTarget(titleContainer)); const labelContainer = document.createElement('div'); addClass(labelContainer, 'label-container'); - this.titleContainer.appendChild(labelContainer); + titleContainer.appendChild(labelContainer); // Editor Label this.editorLabel = this._register(this.instantiationService.createInstance(ResourceLabel, labelContainer, undefined)).element; @@ -46,41 +46,41 @@ export class NoTabsTitleControl extends TitleControl { // Breadcrumbs this.createBreadcrumbsControl(labelContainer, { showFileIcons: false, showSymbolIcons: true, showDecorationColors: false, breadcrumbsBackground: () => Color.transparent }); - toggleClass(this.titleContainer, 'breadcrumbs', Boolean(this.breadcrumbsControl)); - this._register({ dispose: () => removeClass(this.titleContainer, 'breadcrumbs') }); // import to remove because the container is a shared dom node + toggleClass(titleContainer, 'breadcrumbs', Boolean(this.breadcrumbsControl)); + this._register({ dispose: () => removeClass(titleContainer, 'breadcrumbs') }); // import to remove because the container is a shared dom node // Right Actions Container const actionsContainer = document.createElement('div'); addClass(actionsContainer, 'title-actions'); - this.titleContainer.appendChild(actionsContainer); + titleContainer.appendChild(actionsContainer); // Editor actions toolbar this.createEditorActionsToolBar(actionsContainer); } - private registerContainerListeners(): void { + private registerContainerListeners(titleContainer: HTMLElement): void { // Group dragging - this.enableGroupDragging(this.titleContainer); + this.enableGroupDragging(titleContainer); // Pin on double click - this._register(addDisposableListener(this.titleContainer, EventType.DBLCLICK, (e: MouseEvent) => this.onTitleDoubleClick(e))); + this._register(addDisposableListener(titleContainer, EventType.DBLCLICK, (e: MouseEvent) => this.onTitleDoubleClick(e))); // Detect mouse click - this._register(addDisposableListener(this.titleContainer, EventType.MOUSE_UP, (e: MouseEvent) => this.onTitleClick(e))); + this._register(addDisposableListener(titleContainer, EventType.MOUSE_UP, (e: MouseEvent) => this.onTitleClick(e))); // Detect touch - this._register(addDisposableListener(this.titleContainer, TouchEventType.Tap, (e: GestureEvent) => this.onTitleClick(e))); + this._register(addDisposableListener(titleContainer, TouchEventType.Tap, (e: GestureEvent) => this.onTitleClick(e))); // Context Menu - this._register(addDisposableListener(this.titleContainer, EventType.CONTEXT_MENU, (e: Event) => { + this._register(addDisposableListener(titleContainer, EventType.CONTEXT_MENU, (e: Event) => { if (this.group.activeEditor) { - this.onContextMenu(this.group.activeEditor, e, this.titleContainer); + this.onContextMenu(this.group.activeEditor, e, titleContainer); } })); - this._register(addDisposableListener(this.titleContainer, TouchEventType.Contextmenu, (e: Event) => { + this._register(addDisposableListener(titleContainer, TouchEventType.Contextmenu, (e: Event) => { if (this.group.activeEditor) { - this.onContextMenu(this.group.activeEditor, e, this.titleContainer); + this.onContextMenu(this.group.activeEditor, e, titleContainer); } })); } @@ -157,10 +157,11 @@ export class NoTabsTitleControl extends TitleControl { updateEditorDirty(editor: IEditorInput): void { this.ifEditorIsActive(editor, () => { + const titleContainer = assertIsDefined(this.titleContainer); if (editor.isDirty()) { - addClass(this.titleContainer, 'dirty'); + addClass(titleContainer, 'dirty'); } else { - removeClass(this.titleContainer, 'dirty'); + removeClass(titleContainer, 'dirty'); } }); } @@ -176,7 +177,9 @@ export class NoTabsTitleControl extends TitleControl { } protected handleBreadcrumbsEnablementChange(): void { - toggleClass(this.titleContainer, 'breadcrumbs', Boolean(this.breadcrumbsControl)); + const titleContainer = assertIsDefined(this.titleContainer); + + toggleClass(titleContainer, 'breadcrumbs', Boolean(this.breadcrumbsControl)); this.redraw(); } @@ -230,9 +233,10 @@ export class NoTabsTitleControl extends TitleControl { } // Clear if there is no editor + const [titleContainer, editorLabel] = assertAllDefined(this.titleContainer, this.editorLabel); if (!editor) { - removeClass(this.titleContainer, 'dirty'); - this.editorLabel.clear(); + removeClass(titleContainer, 'dirty'); + editorLabel.clear(); this.clearEditorActionsToolbar(); } @@ -261,11 +265,11 @@ export class NoTabsTitleControl extends TitleControl { title = ''; // dont repeat what is already shown } - this.editorLabel.setResource({ name, description, resource: resource || undefined }, { title: typeof title === 'string' ? title : undefined, italic: !isEditorPinned, extraClasses: ['no-tabs', 'title-label'] }); + editorLabel.setResource({ name, description, resource }, { title: typeof title === 'string' ? title : undefined, italic: !isEditorPinned, extraClasses: ['no-tabs', 'title-label'] }); if (isGroupActive) { - this.editorLabel.element.style.color = this.getColor(TAB_ACTIVE_FOREGROUND); + editorLabel.element.style.color = this.getColor(TAB_ACTIVE_FOREGROUND); } else { - this.editorLabel.element.style.color = this.getColor(TAB_UNFOCUSED_ACTIVE_FOREGROUND); + editorLabel.element.style.color = this.getColor(TAB_UNFOCUSED_ACTIVE_FOREGROUND); } // Update Editor Actions Toolbar diff --git a/src/vs/workbench/browser/parts/editor/resourceViewer.ts b/src/vs/workbench/browser/parts/editor/resourceViewer.ts index f5145606ebb..c87b88479de 100644 --- a/src/vs/workbench/browser/parts/editor/resourceViewer.ts +++ b/src/vs/workbench/browser/parts/editor/resourceViewer.ts @@ -10,15 +10,13 @@ import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/resourceviewer'; import * as nls from 'vs/nls'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICssStyleCollector, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IMAGE_PREVIEW_BORDER } from 'vs/workbench/common/theme'; export interface IResourceDescriptor { readonly resource: URI; readonly name: string; - readonly size: number; + readonly size?: number; readonly etag?: string; readonly mime: string; } @@ -75,19 +73,17 @@ export class ResourceViewer { static show( descriptor: IResourceDescriptor, - fileService: IFileService, container: HTMLElement, scrollbar: DomScrollableElement, delegate: ResourceViewerDelegate, - instantiationService: IInstantiationService, ): ResourceViewerContext { // Ensure CSS class container.className = 'monaco-resource-viewer'; // Large Files - if (descriptor.size > ResourceViewer.MAX_OPEN_INTERNAL_SIZE) { - return FileTooLargeFileView.create(container, descriptor, scrollbar, delegate); + if (typeof descriptor.size === 'number' && descriptor.size > ResourceViewer.MAX_OPEN_INTERNAL_SIZE) { + return FileTooLargeFileView.create(container, descriptor.size, scrollbar, delegate); } // Seemingly Binary Files @@ -95,18 +91,16 @@ export class ResourceViewer { return FileSeemsBinaryFileView.create(container, descriptor, scrollbar, delegate); } } - } - class FileTooLargeFileView { static create( container: HTMLElement, - descriptor: IResourceDescriptor, + descriptorSize: number, scrollbar: DomScrollableElement, delegate: ResourceViewerDelegate ) { - const size = BinarySize.formatSize(descriptor.size); + const size = BinarySize.formatSize(descriptorSize); delegate.metadataClb(size); DOM.clearNode(container); diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index b05cb17d70f..9d8ae67d35b 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -17,6 +17,7 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe import { SplitView, Sizing, Orientation } from 'vs/base/browser/ui/splitview/splitview'; import { Event, Relay, Emitter } from 'vs/base/common/event'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { assertIsDefined } from 'vs/base/common/types'; export class SideBySideEditor extends BaseEditor { @@ -47,10 +48,10 @@ export class SideBySideEditor extends BaseEditor { protected masterEditor?: BaseEditor; protected detailsEditor?: BaseEditor; - private masterEditorContainer: HTMLElement; - private detailsEditorContainer: HTMLElement; + private masterEditorContainer: HTMLElement | undefined; + private detailsEditorContainer: HTMLElement | undefined; - private splitview: SplitView; + private splitview: SplitView | undefined; private dimension: DOM.Dimension = new DOM.Dimension(0, 0); private onDidCreateEditors = this._register(new Emitter<{ width: number; height: number; } | undefined>()); @@ -69,8 +70,8 @@ export class SideBySideEditor extends BaseEditor { protected createEditor(parent: HTMLElement): void { DOM.addClass(parent, 'side-by-side-editor'); - this.splitview = this._register(new SplitView(parent, { orientation: Orientation.HORIZONTAL })); - this._register(this.splitview.onDidSashReset(() => this.splitview.distributeViewSizes())); + const splitview = this.splitview = this._register(new SplitView(parent, { orientation: Orientation.HORIZONTAL })); + this._register(this.splitview.onDidSashReset(() => splitview.distributeViewSizes())); this.detailsEditorContainer = DOM.$('.details-editor-container'); this.splitview.addView({ @@ -140,7 +141,9 @@ export class SideBySideEditor extends BaseEditor { layout(dimension: DOM.Dimension): void { this.dimension = dimension; - this.splitview.layout(dimension.width); + + const splitview = assertIsDefined(this.splitview); + splitview.layout(dimension.width); } getControl(): IEditorControl | undefined { @@ -179,8 +182,8 @@ export class SideBySideEditor extends BaseEditor { } private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { - const detailsEditor = this.doCreateEditor(newInput.details, this.detailsEditorContainer); - const masterEditor = this.doCreateEditor(newInput.master, this.masterEditorContainer); + const detailsEditor = this.doCreateEditor(newInput.details, assertIsDefined(this.detailsEditorContainer)); + const masterEditor = this.doCreateEditor(newInput.master, assertIsDefined(this.masterEditorContainer)); return this.onEditorsCreated(detailsEditor, masterEditor, newInput.details, newInput.master, options, token); } @@ -234,8 +237,13 @@ export class SideBySideEditor extends BaseEditor { this.masterEditor = undefined; } - this.detailsEditorContainer.innerHTML = ''; - this.masterEditorContainer.innerHTML = ''; + if (this.detailsEditorContainer) { + DOM.clearNode(this.detailsEditorContainer); + } + + if (this.masterEditorContainer) { + DOM.clearNode(this.masterEditorContainer); + } } dispose(): void { diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 6a8daa4b094..f360d3c9fbb 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -31,7 +31,7 @@ import { ResourcesDropHandler, fillResourceDataTransfers, DraggedEditorIdentifie import { Color } from 'vs/base/common/color'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { MergeGroupMode, IMergeGroupOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { MergeGroupMode, IMergeGroupOptions, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { addClass, addDisposableListener, hasClass, EventType, EventHelper, removeClass, Dimension, scheduleAtNextAnimationFrame, findParentWithClass, clearNode } from 'vs/base/browser/dom'; import { localize } from 'vs/nls'; @@ -40,11 +40,11 @@ import { CloseOneEditorAction } from 'vs/workbench/browser/parts/editor/editorAc import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl'; import { IFileService } from 'vs/platform/files/common/files'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { withNullAsUndefined, assertAllDefined, assertIsDefined } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; interface IEditorInputLabel { - name: string; + name?: string; description?: string; title?: string; } @@ -53,19 +53,20 @@ type AugmentedLabel = IEditorInputLabel & { editor: IEditorInput }; export class TabsTitleControl extends TitleControl { - private titleContainer: HTMLElement; - private tabsContainer: HTMLElement; - private editorToolbarContainer: HTMLElement; - private tabsScrollbar: ScrollableElement; + private titleContainer: HTMLElement | undefined; + private tabsContainer: HTMLElement | undefined; + private editorToolbarContainer: HTMLElement | undefined; + private tabsScrollbar: ScrollableElement | undefined; + private closeOneEditorAction: CloseOneEditorAction; private tabResourceLabels: ResourceLabels; private tabLabels: IEditorInputLabel[] = []; private tabDisposables: IDisposable[] = []; - private dimension: Dimension; + private dimension: Dimension | undefined; private readonly layoutScheduled = this._register(new MutableDisposable()); - private blockRevealActiveTab: boolean; + private blockRevealActiveTab: boolean | undefined; constructor( parent: HTMLElement, @@ -87,6 +88,9 @@ export class TabsTitleControl extends TitleControl { @ILabelService labelService: ILabelService ) { super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService, labelService); + + this.tabResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER)); + this.closeOneEditorAction = this._register(this.instantiationService.createInstance(CloseOneEditorAction, CloseOneEditorAction.ID, CloseOneEditorAction.LABEL)); } protected create(parent: HTMLElement): void { @@ -103,13 +107,13 @@ export class TabsTitleControl extends TitleControl { this.tabsContainer.draggable = true; addClass(this.tabsContainer, 'tabs-container'); - // Tabs Container listeners - this.registerTabsContainerListeners(); - // Tabs Scrollbar this.tabsScrollbar = this._register(this.createTabsScrollbar(this.tabsContainer)); tabsAndActionsContainer.appendChild(this.tabsScrollbar.getDomNode()); + // Tabs Container listeners + this.registerTabsContainerListeners(this.tabsContainer, this.tabsScrollbar); + // Editor Toolbar Container this.editorToolbarContainer = document.createElement('div'); addClass(this.editorToolbarContainer, 'editor-actions'); @@ -118,17 +122,11 @@ export class TabsTitleControl extends TitleControl { // Editor Actions Toolbar this.createEditorActionsToolBar(this.editorToolbarContainer); - // Close Action - this.closeOneEditorAction = this._register(this.instantiationService.createInstance(CloseOneEditorAction, CloseOneEditorAction.ID, CloseOneEditorAction.LABEL)); - // Breadcrumbs (are on a separate row below tabs and actions) const breadcrumbsContainer = document.createElement('div'); addClass(breadcrumbsContainer, 'tabs-breadcrumbs'); this.titleContainer.appendChild(breadcrumbsContainer); this.createBreadcrumbsControl(breadcrumbsContainer, { showFileIcons: true, showSymbolIcons: true, showDecorationColors: false, breadcrumbsBackground: breadcrumbsBackground }); - - // Tab Labels - this.tabResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER)); } private createTabsScrollbar(scrollable: HTMLElement): ScrollableElement { @@ -160,23 +158,23 @@ export class TabsTitleControl extends TitleControl { this.group.relayout(); } - private registerTabsContainerListeners(): void { + private registerTabsContainerListeners(tabsContainer: HTMLElement, tabsScrollbar: ScrollableElement): void { // Group dragging - this.enableGroupDragging(this.tabsContainer); + this.enableGroupDragging(tabsContainer); // Forward scrolling inside the container to our custom scrollbar - this._register(addDisposableListener(this.tabsContainer, EventType.SCROLL, () => { - if (hasClass(this.tabsContainer, 'scroll')) { - this.tabsScrollbar.setScrollPosition({ - scrollLeft: this.tabsContainer.scrollLeft // during DND the container gets scrolled so we need to update the custom scrollbar + this._register(addDisposableListener(tabsContainer, EventType.SCROLL, () => { + if (hasClass(tabsContainer, 'scroll')) { + tabsScrollbar.setScrollPosition({ + scrollLeft: tabsContainer.scrollLeft // during DND the container gets scrolled so we need to update the custom scrollbar }); } })); // New file when double clicking on tabs container (but not tabs) - this._register(addDisposableListener(this.tabsContainer, EventType.DBLCLICK, e => { - if (e.target === this.tabsContainer) { + this._register(addDisposableListener(tabsContainer, EventType.DBLCLICK, e => { + if (e.target === tabsContainer) { EventHelper.stop(e); this.group.openEditor(this.untitledEditorService.createOrGet(), { pinned: true /* untitled is always pinned */, index: this.group.count /* always at the end */ }); @@ -184,29 +182,31 @@ export class TabsTitleControl extends TitleControl { })); // Prevent auto-scrolling (https://github.com/Microsoft/vscode/issues/16690) - this._register(addDisposableListener(this.tabsContainer, EventType.MOUSE_DOWN, (e: MouseEvent) => { + this._register(addDisposableListener(tabsContainer, EventType.MOUSE_DOWN, (e: MouseEvent) => { if (e.button === 1) { e.preventDefault(); } })); - // Drop support - this._register(new DragAndDropObserver(this.tabsContainer, { + this._register(new DragAndDropObserver(tabsContainer, { onDragEnter: e => { // Always enable support to scroll while dragging - addClass(this.tabsContainer, 'scroll'); + addClass(tabsContainer, 'scroll'); // Return if the target is not on the tabs container - if (e.target !== this.tabsContainer) { - this.updateDropFeedback(this.tabsContainer, false); // fixes https://github.com/Microsoft/vscode/issues/52093 + if (e.target !== tabsContainer) { + this.updateDropFeedback(tabsContainer, false); // fixes https://github.com/Microsoft/vscode/issues/52093 return; } // Return if transfer is unsupported if (!this.isSupportedDropTransfer(e)) { - e.dataTransfer!.dropEffect = 'none'; + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'none'; + } + return; } @@ -215,38 +215,46 @@ export class TabsTitleControl extends TitleControl { if (this.editorTransfer.hasData(DraggedEditorIdentifier.prototype)) { isLocalDragAndDrop = true; - const localDraggedEditor = this.editorTransfer.getData(DraggedEditorIdentifier.prototype)![0].identifier; - if (this.group.id === localDraggedEditor.groupId && this.group.getIndexOfEditor(localDraggedEditor.editor) === this.group.count - 1) { - e.dataTransfer!.dropEffect = 'none'; - return; + const data = this.editorTransfer.getData(DraggedEditorIdentifier.prototype); + if (Array.isArray(data)) { + const localDraggedEditor = data[0].identifier; + if (this.group.id === localDraggedEditor.groupId && this.group.getIndexOfEditor(localDraggedEditor.editor) === this.group.count - 1) { + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'none'; + } + + return; + } } } // Update the dropEffect to "copy" if there is no local data to be dragged because // in that case we can only copy the data into and not move it from its source if (!isLocalDragAndDrop) { - e.dataTransfer!.dropEffect = 'copy'; + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'copy'; + } } - this.updateDropFeedback(this.tabsContainer, true); + this.updateDropFeedback(tabsContainer, true); }, onDragLeave: e => { - this.updateDropFeedback(this.tabsContainer, false); - removeClass(this.tabsContainer, 'scroll'); + this.updateDropFeedback(tabsContainer, false); + removeClass(tabsContainer, 'scroll'); }, onDragEnd: e => { - this.updateDropFeedback(this.tabsContainer, false); - removeClass(this.tabsContainer, 'scroll'); + this.updateDropFeedback(tabsContainer, false); + removeClass(tabsContainer, 'scroll'); }, onDrop: e => { - this.updateDropFeedback(this.tabsContainer, false); - removeClass(this.tabsContainer, 'scroll'); + this.updateDropFeedback(tabsContainer, false); + removeClass(tabsContainer, 'scroll'); - if (e.target === this.tabsContainer) { - this.onDrop(e, this.group.count); + if (e.target === tabsContainer) { + this.onDrop(e, this.group.count, tabsContainer); } } })); @@ -263,8 +271,9 @@ export class TabsTitleControl extends TitleControl { openEditor(editor: IEditorInput): void { // Create tabs as needed - for (let i = this.tabsContainer.children.length; i < this.group.count; i++) { - this.tabsContainer.appendChild(this.createTab(i)); + const [tabsContainer, tabsScrollbar] = assertAllDefined(this.tabsContainer, this.tabsScrollbar); + for (let i = tabsContainer.children.length; i < this.group.count; i++) { + tabsContainer.appendChild(this.createTab(i, tabsContainer, tabsScrollbar)); } // An add of a tab requires to recompute all labels @@ -295,13 +304,14 @@ export class TabsTitleControl extends TitleControl { if (this.group.activeEditor) { // Remove tabs that got closed - while (this.tabsContainer.children.length > this.group.count) { + const tabsContainer = assertIsDefined(this.tabsContainer); + while (tabsContainer.children.length > this.group.count) { // Remove one tab from container (must be the last to keep indexes in order!) - (this.tabsContainer.lastChild as HTMLElement).remove(); + (tabsContainer.lastChild as HTMLElement).remove(); // Remove associated tab label and widget - this.tabDisposables.pop()!.dispose(); + dispose(this.tabDisposables.pop()); } // A removal of a label requires to recompute all labels @@ -313,7 +323,9 @@ export class TabsTitleControl extends TitleControl { // No tabs to show else { - clearNode(this.tabsContainer); + if (this.tabsContainer) { + clearNode(this.tabsContainer); + } this.tabDisposables = dispose(this.tabDisposables); this.tabResourceLabels.clear(); @@ -343,7 +355,7 @@ export class TabsTitleControl extends TitleControl { } pinEditor(editor: IEditorInput): void { - this.withTab(editor, (tabContainer, tabLabelWidget, tabLabel) => this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel)); + this.withTab(editor, (editor, index, tabContainer, tabLabelWidget, tabLabel) => this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel)); } setActive(isGroupActive: boolean): void { @@ -379,7 +391,7 @@ export class TabsTitleControl extends TitleControl { } updateEditorDirty(editor: IEditorInput): void { - this.withTab(editor, (tabContainer, tabLabelWidget) => this.redrawEditorActiveAndDirty(this.accessor.activeGroup === this.group, editor, tabContainer, tabLabelWidget)); + this.withTab(editor, (editor, index, tabContainer, tabLabelWidget) => this.redrawEditorActiveAndDirty(this.accessor.activeGroup === this.group, editor, tabContainer, tabLabelWidget)); } updateOptions(oldOptions: IEditorPartOptions, newOptions: IEditorPartOptions): void { @@ -406,16 +418,27 @@ export class TabsTitleControl extends TitleControl { this.redraw(); } - private withTab(editor: IEditorInput, fn: (tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel) => void): void { - const editorIndex = this.group.getIndexOfEditor(editor); + private forEachTab(fn: (editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel) => void): void { + this.group.editors.forEach((editor, index) => { + this.doWithTab(index, editor, fn); + }); + } - const tabContainer = this.tabsContainer.children[editorIndex] as HTMLElement; - if (tabContainer) { - fn(tabContainer, this.tabResourceLabels.get(editorIndex), this.tabLabels[editorIndex]); + private withTab(editor: IEditorInput, fn: (editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel) => void): void { + this.doWithTab(this.group.getIndexOfEditor(editor), editor, fn); + } + + private doWithTab(index: number, editor: IEditorInput, fn: (editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel) => void): void { + const tabsContainer = assertIsDefined(this.tabsContainer); + const tabContainer = tabsContainer.children[index] as HTMLElement; + const tabResourceLabel = this.tabResourceLabels.get(index); + const tabLabel = this.tabLabels[index]; + if (tabContainer && tabResourceLabel && tabLabel) { + fn(editor, index, tabContainer, tabResourceLabel, tabLabel); } } - private createTab(index: number): HTMLElement { + private createTab(index: number, tabsContainer: HTMLElement, tabsScrollbar: ScrollableElement): HTMLElement { // Tab Container const tabContainer = document.createElement('div'); @@ -425,7 +448,7 @@ export class TabsTitleControl extends TitleControl { addClass(tabContainer, 'tab'); // Gesture Support - Gesture.addTarget(tabContainer); + this._register(Gesture.addTarget(tabContainer)); // Tab Border Top const tabBorderTopContainer = document.createElement('div'); @@ -452,14 +475,14 @@ export class TabsTitleControl extends TitleControl { tabActionBar.onDidBeforeRun(() => this.blockRevealActiveTabOnce()); // Eventing - const eventsDisposable = this.registerTabListeners(tabContainer, index); + const eventsDisposable = this.registerTabListeners(tabContainer, index, tabsContainer, tabsScrollbar); this.tabDisposables.push(combinedDisposable(eventsDisposable, tabActionBar, tabActionRunner, editorLabel)); return tabContainer; } - private registerTabListeners(tab: HTMLElement, index: number): IDisposable { + private registerTabListeners(tab: HTMLElement, index: number, tabsContainer: HTMLElement, tabsScrollbar: ScrollableElement): IDisposable { const disposables = new DisposableStore(); const handleClickOrTouch = (e: MouseEvent | GestureEvent): void => { @@ -501,7 +524,7 @@ export class TabsTitleControl extends TitleControl { // Touch Scroll Support disposables.add(addDisposableListener(tab, TouchEventType.Change, (e: GestureEvent) => { - this.tabsScrollbar.setScrollPosition({ scrollLeft: this.tabsScrollbar.getScrollPosition().scrollLeft - e.translationX }); + tabsScrollbar.setScrollPosition({ scrollLeft: tabsScrollbar.getScrollPosition().scrollLeft - e.translationX }); })); // Close on mouse middle click @@ -562,7 +585,7 @@ export class TabsTitleControl extends TitleControl { if (target) { handled = true; this.group.openEditor(target, { preserveFocus: true }); - (this.tabsContainer.childNodes[targetIndex]).focus(); + (tabsContainer.childNodes[targetIndex]).focus(); } } @@ -571,16 +594,21 @@ export class TabsTitleControl extends TitleControl { } // moving in the tabs container can have an impact on scrolling position, so we need to update the custom scrollbar - this.tabsScrollbar.setScrollPosition({ - scrollLeft: this.tabsContainer.scrollLeft + tabsScrollbar.setScrollPosition({ + scrollLeft: tabsContainer.scrollLeft }); })); - // Pin on double click + // Double click: either pin or toggle maximized disposables.add(addDisposableListener(tab, EventType.DBLCLICK, (e: MouseEvent) => { EventHelper.stop(e); - this.group.pinEditor(this.group.getEditor(index) || undefined); + const editor = this.group.getEditor(index); + if (editor && this.group.isPinned(editor)) { + this.accessor.arrangeGroups(GroupsArrangement.TOGGLE, this.group); + } else { + this.group.pinEditor(editor); + } })); // Context menu @@ -602,7 +630,9 @@ export class TabsTitleControl extends TitleControl { this.editorTransfer.setData([new DraggedEditorIdentifier({ editor, groupId: this.group.id })], DraggedEditorIdentifier.prototype); - e.dataTransfer!.effectAllowed = 'copyMove'; + if (e.dataTransfer) { + e.dataTransfer.effectAllowed = 'copyMove'; + } // Apply some datatransfer types to allow for dragging the element outside of the application const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); @@ -624,7 +654,10 @@ export class TabsTitleControl extends TitleControl { // Return if transfer is unsupported if (!this.isSupportedDropTransfer(e)) { - e.dataTransfer!.dropEffect = 'none'; + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'none'; + } + return; } @@ -633,17 +666,25 @@ export class TabsTitleControl extends TitleControl { if (this.editorTransfer.hasData(DraggedEditorIdentifier.prototype)) { isLocalDragAndDrop = true; - const localDraggedEditor = this.editorTransfer.getData(DraggedEditorIdentifier.prototype)![0].identifier; - if (localDraggedEditor.editor === this.group.getEditor(index) && localDraggedEditor.groupId === this.group.id) { - e.dataTransfer!.dropEffect = 'none'; - return; + const data = this.editorTransfer.getData(DraggedEditorIdentifier.prototype); + if (Array.isArray(data)) { + const localDraggedEditor = data[0].identifier; + if (localDraggedEditor.editor === this.group.getEditor(index) && localDraggedEditor.groupId === this.group.id) { + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'none'; + } + + return; + } } } // Update the dropEffect to "copy" if there is no local data to be dragged because // in that case we can only copy the data into and not move it from its source if (!isLocalDragAndDrop) { - e.dataTransfer!.dropEffect = 'copy'; + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'copy'; + } } this.updateDropFeedback(tab, true, index); @@ -665,7 +706,7 @@ export class TabsTitleControl extends TitleControl { removeClass(tab, 'dragged-over'); this.updateDropFeedback(tab, false, index); - this.onDrop(e, index); + this.onDrop(e, index, tabsContainer); } })); @@ -674,9 +715,12 @@ export class TabsTitleControl extends TitleControl { private isSupportedDropTransfer(e: DragEvent): boolean { if (this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype)) { - const group = this.groupTransfer.getData(DraggedEditorGroupIdentifier.prototype)![0]; - if (group.identifier === this.group.id) { - return false; // groups cannot be dropped on title area it originates from + const data = this.groupTransfer.getData(DraggedEditorGroupIdentifier.prototype); + if (Array.isArray(data)) { + const group = data[0]; + if (group.identifier === this.group.id) { + return false; // groups cannot be dropped on title area it originates from + } } return true; @@ -699,8 +743,8 @@ export class TabsTitleControl extends TitleControl { const isActiveTab = isTab && !!editor && this.group.isActive(editor); // Background - const noDNDBackgroundColor = isTab ? this.getColor(isActiveTab ? TAB_ACTIVE_BACKGROUND : TAB_INACTIVE_BACKGROUND) : null; - element.style.backgroundColor = isDND ? this.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND) : noDNDBackgroundColor; + const noDNDBackgroundColor = isTab ? this.getColor(isActiveTab ? TAB_ACTIVE_BACKGROUND : TAB_INACTIVE_BACKGROUND) : ''; + element.style.backgroundColor = (isDND ? this.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND) : noDNDBackgroundColor) || ''; // Outline const activeContrastBorderColor = this.getColor(activeContrastBorder); @@ -724,7 +768,7 @@ export class TabsTitleControl extends TitleControl { // Build labels and descriptions for each editor const labels = this.group.editors.map(editor => ({ editor, - name: editor.getName()!, + name: editor.getName(), description: editor.getDescription(verbosity), title: withNullAsUndefined(editor.getTitle(Verbosity.LONG)) })); @@ -833,15 +877,6 @@ export class TabsTitleControl extends TitleControl { this.layout(this.dimension); } - private forEachTab(fn: (editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel) => void): void { - this.group.editors.forEach((editor, index) => { - const tabContainer = this.tabsContainer.children[index] as HTMLElement; - if (tabContainer) { - fn(editor, index, tabContainer, this.tabResourceLabels.get(index), this.tabLabels[index]); - } - }); - } - private redrawTab(editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel): void { // Label @@ -849,7 +884,7 @@ export class TabsTitleControl extends TitleControl { // Borders / Outline const borderRightColor = (this.getColor(TAB_BORDER) || this.getColor(contrastBorder)); - tabContainer.style.borderRight = borderRightColor ? `1px solid ${borderRightColor}` : null; + tabContainer.style.borderRight = borderRightColor ? `1px solid ${borderRightColor}` : ''; tabContainer.style.outlineColor = this.getColor(activeContrastBorder) || ''; // Settings @@ -885,7 +920,7 @@ export class TabsTitleControl extends TitleControl { tabContainer.title = title; // Label - tabLabelWidget.setResource({ name, description, resource: toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }) || undefined }, { title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) }); + tabLabelWidget.setResource({ name, description, resource: toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }) }, { title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) }); } private redrawEditorActiveAndDirty(isGroupActive: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel): void { @@ -904,7 +939,7 @@ export class TabsTitleControl extends TitleControl { // Container addClass(tabContainer, 'active'); tabContainer.setAttribute('aria-selected', 'true'); - tabContainer.style.backgroundColor = this.getColor(isGroupActive ? TAB_ACTIVE_BACKGROUND : TAB_UNFOCUSED_ACTIVE_BACKGROUND); + tabContainer.style.backgroundColor = this.getColor(isGroupActive ? TAB_ACTIVE_BACKGROUND : TAB_UNFOCUSED_ACTIVE_BACKGROUND) || ''; const activeTabBorderColorBottom = this.getColor(isGroupActive ? TAB_ACTIVE_BORDER : TAB_UNFOCUSED_ACTIVE_BORDER); if (activeTabBorderColorBottom) { @@ -934,8 +969,8 @@ export class TabsTitleControl extends TitleControl { // Container removeClass(tabContainer, 'active'); tabContainer.setAttribute('aria-selected', 'false'); - tabContainer.style.backgroundColor = this.getColor(TAB_INACTIVE_BACKGROUND); - tabContainer.style.boxShadow = null; + tabContainer.style.backgroundColor = this.getColor(TAB_INACTIVE_BACKGROUND) || ''; + tabContainer.style.boxShadow = ''; // Label tabLabelWidget.element.style.color = this.getColor(isGroupActive ? TAB_INACTIVE_FOREGROUND : TAB_UNFOCUSED_INACTIVE_FOREGROUND); @@ -985,7 +1020,7 @@ export class TabsTitleControl extends TitleControl { return hasModifiedBorderColor; } - layout(dimension: Dimension): void { + layout(dimension: Dimension | undefined): void { this.dimension = dimension; const activeTab = this.group.activeEditor ? this.getTab(this.group.activeEditor) : undefined; @@ -998,7 +1033,9 @@ export class TabsTitleControl extends TitleControl { // this a little bit we try at least to schedule this work on the next animation frame. if (!this.layoutScheduled.value) { this.layoutScheduled.value = scheduleAtNextAnimationFrame(() => { - this.doLayout(this.dimension); + const dimension = assertIsDefined(this.dimension); + this.doLayout(dimension); + this.layoutScheduled.clear(); }); } @@ -1010,16 +1047,18 @@ export class TabsTitleControl extends TitleControl { return; } + const [tabsContainer, tabsScrollbar] = assertAllDefined(this.tabsContainer, this.tabsScrollbar); + if (this.breadcrumbsControl && !this.breadcrumbsControl.isHidden()) { this.breadcrumbsControl.layout({ width: dimension.width, height: BreadcrumbsControl.HEIGHT }); - this.tabsScrollbar.getDomNode().style.height = `${dimension.height - BreadcrumbsControl.HEIGHT}px`; + tabsScrollbar.getDomNode().style.height = `${dimension.height - BreadcrumbsControl.HEIGHT}px`; } - const visibleContainerWidth = this.tabsContainer.offsetWidth; - const totalContainerWidth = this.tabsContainer.scrollWidth; + const visibleContainerWidth = tabsContainer.offsetWidth; + const totalContainerWidth = tabsContainer.scrollWidth; - let activeTabPosX: number; - let activeTabWidth: number; + let activeTabPosX: number | undefined; + let activeTabWidth: number | undefined; if (!this.blockRevealActiveTab) { activeTabPosX = activeTab.offsetLeft; @@ -1027,33 +1066,33 @@ export class TabsTitleControl extends TitleControl { } // Update scrollbar - this.tabsScrollbar.setScrollDimensions({ + tabsScrollbar.setScrollDimensions({ width: visibleContainerWidth, scrollWidth: totalContainerWidth }); // Return now if we are blocked to reveal the active tab and clear flag - if (this.blockRevealActiveTab) { + if (this.blockRevealActiveTab || typeof activeTabPosX !== 'number' || typeof activeTabWidth !== 'number') { this.blockRevealActiveTab = false; return; } // Reveal the active one - const containerScrollPosX = this.tabsScrollbar.getScrollPosition().scrollLeft; - const activeTabFits = activeTabWidth! <= visibleContainerWidth; + const containerScrollPosX = tabsScrollbar.getScrollPosition().scrollLeft; + const activeTabFits = activeTabWidth <= visibleContainerWidth; // Tab is overflowing to the right: Scroll minimally until the element is fully visible to the right // Note: only try to do this if we actually have enough width to give to show the tab fully! - if (activeTabFits && containerScrollPosX + visibleContainerWidth < activeTabPosX! + activeTabWidth!) { - this.tabsScrollbar.setScrollPosition({ - scrollLeft: containerScrollPosX + ((activeTabPosX! + activeTabWidth!) /* right corner of tab */ - (containerScrollPosX + visibleContainerWidth) /* right corner of view port */) + if (activeTabFits && containerScrollPosX + visibleContainerWidth < activeTabPosX + activeTabWidth) { + tabsScrollbar.setScrollPosition({ + scrollLeft: containerScrollPosX + ((activeTabPosX + activeTabWidth) /* right corner of tab */ - (containerScrollPosX + visibleContainerWidth) /* right corner of view port */) }); } // Tab is overlflowng to the left or does not fit: Scroll it into view to the left - else if (containerScrollPosX > activeTabPosX! || !activeTabFits) { - this.tabsScrollbar.setScrollPosition({ - scrollLeft: activeTabPosX! + else if (containerScrollPosX > activeTabPosX || !activeTabFits) { + tabsScrollbar.setScrollPosition({ + scrollLeft: activeTabPosX }); } } @@ -1061,7 +1100,9 @@ export class TabsTitleControl extends TitleControl { private getTab(editor: IEditorInput): HTMLElement | undefined { const editorIndex = this.group.getIndexOfEditor(editor); if (editorIndex >= 0) { - return this.tabsContainer.children[editorIndex] as HTMLElement; + const tabsContainer = assertIsDefined(this.tabsContainer); + + return tabsContainer.children[editorIndex] as HTMLElement; } return undefined; @@ -1088,49 +1129,55 @@ export class TabsTitleControl extends TitleControl { return !!findParentWithClass(element, 'action-item', 'tab'); } - private onDrop(e: DragEvent, targetIndex: number): void { + private onDrop(e: DragEvent, targetIndex: number, tabsContainer: HTMLElement): void { EventHelper.stop(e, true); - this.updateDropFeedback(this.tabsContainer, false); - removeClass(this.tabsContainer, 'scroll'); + this.updateDropFeedback(tabsContainer, false); + removeClass(tabsContainer, 'scroll'); // Local Editor DND if (this.editorTransfer.hasData(DraggedEditorIdentifier.prototype)) { - const draggedEditor = this.editorTransfer.getData(DraggedEditorIdentifier.prototype)![0].identifier; - const sourceGroup = this.accessor.getGroup(draggedEditor.groupId); + const data = this.editorTransfer.getData(DraggedEditorIdentifier.prototype); + if (Array.isArray(data)) { + const draggedEditor = data[0].identifier; + const sourceGroup = this.accessor.getGroup(draggedEditor.groupId); - if (sourceGroup) { + if (sourceGroup) { - // Move editor to target position and index - if (this.isMoveOperation(e, draggedEditor.groupId)) { - sourceGroup.moveEditor(draggedEditor.editor, this.group, { index: targetIndex }); + // Move editor to target position and index + if (this.isMoveOperation(e, draggedEditor.groupId)) { + sourceGroup.moveEditor(draggedEditor.editor, this.group, { index: targetIndex }); + } + + // Copy editor to target position and index + else { + sourceGroup.copyEditor(draggedEditor.editor, this.group, { index: targetIndex }); + } } - // Copy editor to target position and index - else { - sourceGroup.copyEditor(draggedEditor.editor, this.group, { index: targetIndex }); - } + this.group.focus(); + this.editorTransfer.clearData(DraggedEditorIdentifier.prototype); } - - this.group.focus(); - this.editorTransfer.clearData(DraggedEditorIdentifier.prototype); } // Local Editor Group DND else if (this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype)) { - const sourceGroup = this.accessor.getGroup(this.groupTransfer.getData(DraggedEditorGroupIdentifier.prototype)![0].identifier); + const data = this.groupTransfer.getData(DraggedEditorGroupIdentifier.prototype); + if (data) { + const sourceGroup = this.accessor.getGroup(data[0].identifier); - if (sourceGroup) { - const mergeGroupOptions: IMergeGroupOptions = { index: targetIndex }; - if (!this.isMoveOperation(e, sourceGroup.id)) { - mergeGroupOptions.mode = MergeGroupMode.COPY_EDITORS; + if (sourceGroup) { + const mergeGroupOptions: IMergeGroupOptions = { index: targetIndex }; + if (!this.isMoveOperation(e, sourceGroup.id)) { + mergeGroupOptions.mode = MergeGroupMode.COPY_EDITORS; + } + + this.accessor.mergeGroup(sourceGroup, this.group, mergeGroupOptions); } - this.accessor.mergeGroup(sourceGroup, this.group, mergeGroupOptions); + this.group.focus(); + this.groupTransfer.clearData(DraggedEditorGroupIdentifier.prototype); } - - this.group.focus(); - this.groupTransfer.clearData(DraggedEditorGroupIdentifier.prototype); } // External DND @@ -1189,7 +1236,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { // High Contrast Border Color for Editor Actions const contrastBorderColor = theme.getColor(contrastBorder); - if (contrastBorder) { + if (contrastBorderColor) { collector.addRule(` .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions { outline: 1px solid ${contrastBorderColor} diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 30621785f1b..e4d132cc598 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as objects from 'vs/base/common/objects'; -import { isFunction, isObject, isArray } from 'vs/base/common/types'; +import { isFunction, isObject, isArray, assertIsDefined } from 'vs/base/common/types'; import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IDiffEditorOptions, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor'; @@ -30,7 +30,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; @@ -53,10 +53,10 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { @IThemeService themeService: IThemeService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, - @IWindowService windowService: IWindowService, + @IHostService hostService: IHostService, @IClipboardService private _clipboardService: IClipboardService, ) { - super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService); + super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); } protected getEditorMemento(editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento { @@ -100,7 +100,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { } // Set Editor Model - const diffEditor = this.getControl(); + const diffEditor = assertIsDefined(this.getControl()); const resolvedDiffEditorModel = resolvedModel; diffEditor.setModel(resolvedDiffEditorModel.textDiffEditorModel); @@ -113,7 +113,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { // Otherwise restore View State let hasPreviousViewState = false; if (!optionsGotApplied) { - hasPreviousViewState = this.restoreTextDiffEditorViewState(input); + hasPreviousViewState = this.restoreTextDiffEditorViewState(input, diffEditor); } // Diff navigator @@ -138,17 +138,18 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { setOptions(options: EditorOptions | undefined): void { const textOptions = options; if (textOptions && isFunction(textOptions.apply)) { - textOptions.apply(this.getControl(), ScrollType.Smooth); + const diffEditor = assertIsDefined(this.getControl()); + textOptions.apply(diffEditor, ScrollType.Smooth); } } - private restoreTextDiffEditorViewState(input: EditorInput): boolean { - if (input instanceof DiffEditorInput) { - const resource = this.toDiffEditorViewStateResource(input); + private restoreTextDiffEditorViewState(editor: EditorInput, control: IDiffEditor): boolean { + if (editor instanceof DiffEditorInput) { + const resource = this.toDiffEditorViewStateResource(editor); if (resource) { const viewState = this.loadTextEditorViewState(resource); if (viewState) { - this.getControl().restoreViewState(viewState); + control.restoreViewState(viewState); return true; } @@ -258,7 +259,10 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { this.saveTextDiffEditorViewState(this.input); // Clear Model - this.getControl().setModel(null); + const diffEditor = this.getControl(); + if (diffEditor) { + diffEditor.setModel(null); + } // Pass to super super.clearInput(); @@ -268,8 +272,8 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { return this.diffNavigator; } - getControl(): IDiffEditor { - return super.getControl() as IDiffEditor; + getControl(): IDiffEditor | undefined { + return super.getControl() as IDiffEditor | undefined; } protected loadTextEditorViewState(resource: URI): IDiffEditorViewState { @@ -307,7 +311,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { } private retrieveTextDiffEditorViewState(resource: URI): IDiffEditorViewState | null { - const control = this.getControl(); + const control = assertIsDefined(this.getControl()); const model = control.getModel(); if (!model || !model.modified || !model.original) { return null; // view state always needs a model diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index 796770b762e..ab5403342c3 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import * as objects from 'vs/base/common/objects'; -import * as types from 'vs/base/common/types'; -import * as DOM from 'vs/base/browser/dom'; +import { distinct, deepClone, assign } from 'vs/base/common/objects'; +import { isObject, assertIsDefined } from 'vs/base/common/types'; +import { Dimension } from 'vs/base/browser/dom'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { EditorInput, EditorOptions, IEditorMemento, ITextEditor } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; @@ -23,7 +23,7 @@ import { isDiffEditor, isCodeEditor, getCodeEditor } from 'vs/editor/browser/edi import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; const TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'textEditorViewState'; @@ -37,8 +37,8 @@ export interface IEditorConfiguration { * be subclassed and not instantiated. */ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { - private editorControl: IEditor; - private _editorContainer: HTMLElement; + private editorControl: IEditor | undefined; + private _editorContainer: HTMLElement | undefined; private hasPendingConfigurationChange: boolean | undefined; private lastAppliedEditorOptions?: IEditorOptions; private editorMemento: IEditorMemento; @@ -53,7 +53,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { @ITextFileService private readonly _textFileService: ITextFileService, @IEditorService protected editorService: IEditorService, @IEditorGroupsService protected editorGroupService: IEditorGroupsService, - @IWindowService private readonly windowService: IWindowService + @IHostService private readonly hostService: IHostService ) { super(id, telemetryService, themeService, storageService); @@ -96,8 +96,8 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { protected computeConfiguration(configuration: IEditorConfiguration): IEditorOptions { // Specific editor options always overwrite user configuration - const editorConfiguration: IEditorOptions = types.isObject(configuration.editor) ? objects.deepClone(configuration.editor) : Object.create(null); - objects.assign(editorConfiguration, this.getConfigurationOverrides()); + const editorConfiguration: IEditorOptions = isObject(configuration.editor) ? deepClone(configuration.editor) : Object.create(null); + assign(editorConfiguration, this.getConfigurationOverrides()); // ARIA label editorConfiguration.ariaLabel = this.computeAriaLabel(); @@ -111,7 +111,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { // Apply group information to help identify in which group we are if (ariaLabel) { if (this.group) { - ariaLabel = nls.localize('editorLabelWithGroup', "{0}, {1}.", ariaLabel, this.group.label); + ariaLabel = localize('editorLabelWithGroup', "{0}, {1}.", ariaLabel, this.group.label); } } @@ -120,7 +120,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { protected getConfigurationOverrides(): IEditorOptions { const overrides = {}; - objects.assign(overrides, { + assign(overrides, { overviewRulerLanes: 3, lineNumbersMinChars: 3, fixedOverflowWidgets: true @@ -133,7 +133,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { // Editor for Text this._editorContainer = parent; - this.editorControl = this._register(this.createEditorControl(parent, this.computeConfiguration(this.configurationService.getValue(this.getResource()!)))); + this.editorControl = this._register(this.createEditorControl(parent, this.computeConfiguration(this.configurationService.getValue(this.getResource())))); // Model & Language changes const codeEditor = getCodeEditor(this.editorControl); @@ -151,7 +151,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { } this._register(this.editorService.onDidActiveEditorChange(() => this.onEditorFocusLost())); - this._register(this.windowService.onDidChangeFocus(focused => this.onWindowFocusChange(focused))); + this._register(this.hostService.onDidChangeFocus(focused => this.onWindowFocusChange(focused))); } private onEditorFocusLost(): void { @@ -197,33 +197,40 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { // Update editor options after having set the input. We do this because there can be // editor input specific options (e.g. an ARIA label depending on the input showing) this.updateEditorConfiguration(); - this._editorContainer.setAttribute('aria-label', this.computeAriaLabel()); + + const editorContainer = assertIsDefined(this._editorContainer); + editorContainer.setAttribute('aria-label', this.computeAriaLabel()); } protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { // Pass on to Editor + const editorControl = assertIsDefined(this.editorControl); if (visible) { this.consumePendingConfigurationChangeEvent(); - this.editorControl.onVisible(); + editorControl.onVisible(); } else { - this.editorControl.onHide(); + editorControl.onHide(); } super.setEditorVisible(visible, group); } focus(): void { - this.editorControl.focus(); - } - - layout(dimension: DOM.Dimension): void { // Pass on to Editor - this.editorControl.layout(dimension); + const editorControl = assertIsDefined(this.editorControl); + editorControl.focus(); } - getControl(): IEditor { + layout(dimension: Dimension): void { + + // Pass on to Editor + const editorControl = assertIsDefined(this.editorControl); + editorControl.layout(dimension); + } + + getControl(): IEditor | undefined { return this.editorControl; } @@ -296,7 +303,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { // have been applied to the editor directly. let editorSettingsToApply = editorConfiguration; if (this.lastAppliedEditorOptions) { - editorSettingsToApply = objects.distinct(this.lastAppliedEditorOptions, editorSettingsToApply); + editorSettingsToApply = distinct(this.lastAppliedEditorOptions, editorSettingsToApply); } if (Object.keys(editorSettingsToApply).length > 0) { diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 7f7035c56c6..157918075dd 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as types from 'vs/base/common/types'; +import { assertIsDefined, isFunction } from 'vs/base/common/types'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { TextEditorOptions, EditorInput, EditorOptions } from 'vs/workbench/common/editor'; @@ -19,11 +19,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { Event } from 'vs/base/common/event'; -import { ScrollType } from 'vs/editor/common/editorCommon'; +import { ScrollType, IEditor } from 'vs/editor/common/editorCommon'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; /** * An editor implementation that is capable of showing the contents of resource inputs. Uses @@ -41,9 +41,9 @@ export class AbstractTextResourceEditor extends BaseTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IWindowService windowService: IWindowService + @IHostService hostService: IHostService ) { - super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService); + super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); } getTitle(): string | undefined { @@ -74,36 +74,37 @@ export class AbstractTextResourceEditor extends BaseTextEditor { } // Set Editor Model - const textEditor = this.getControl(); + const textEditor = assertIsDefined(this.getControl()); const textEditorModel = resolvedModel.textEditorModel; textEditor.setModel(textEditorModel); // Apply Options from TextOptions let optionsGotApplied = false; const textOptions = options; - if (textOptions && types.isFunction(textOptions.apply)) { + if (textOptions && isFunction(textOptions.apply)) { optionsGotApplied = textOptions.apply(textEditor, ScrollType.Immediate); } // Otherwise restore View State if (!optionsGotApplied) { - this.restoreTextResourceEditorViewState(input); + this.restoreTextResourceEditorViewState(input, textEditor); } } - private restoreTextResourceEditorViewState(input: EditorInput) { - if (input instanceof UntitledEditorInput || input instanceof ResourceEditorInput) { - const viewState = this.loadTextEditorViewState(input.getResource()); + private restoreTextResourceEditorViewState(editor: EditorInput, control: IEditor) { + if (editor instanceof UntitledEditorInput || editor instanceof ResourceEditorInput) { + const viewState = this.loadTextEditorViewState(editor.getResource()); if (viewState) { - this.getControl().restoreViewState(viewState); + control.restoreViewState(viewState); } } } setOptions(options: EditorOptions | undefined): void { const textOptions = options; - if (textOptions && types.isFunction(textOptions.apply)) { - textOptions.apply(this.getControl(), ScrollType.Smooth); + if (textOptions && isFunction(textOptions.apply)) { + const textEditor = assertIsDefined(this.getControl()); + textOptions.apply(textEditor, ScrollType.Smooth); } } @@ -120,7 +121,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { const isReadonly = !(this.input instanceof UntitledEditorInput); let ariaLabel: string; - const inputName = input && input.getName(); + const inputName = input?.getName(); if (isReadonly) { ariaLabel = inputName ? nls.localize('readonlyEditorWithInputAriaLabel', "{0}. Readonly text editor.", inputName) : nls.localize('readonlyEditorAriaLabel', "Readonly text editor."); } else { @@ -149,7 +150,10 @@ export class AbstractTextResourceEditor extends BaseTextEditor { this.saveTextResourceEditorViewState(this.input); // Clear Model - this.getControl().setModel(null); + const textEditor = this.getControl(); + if (textEditor) { + textEditor.setModel(null); + } super.clearInput(); } @@ -201,8 +205,8 @@ export class TextResourceEditor extends AbstractTextResourceEditor { @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, @IEditorGroupsService editorGroupService: IEditorGroupsService, - @IWindowService windowService: IWindowService + @IHostService hostService: IHostService ) { - super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, windowService); + super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService); } } diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 089bbbc8875..177dea50b85 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -39,7 +39,7 @@ import { Themable } from 'vs/workbench/common/theme'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { IFileService } from 'vs/platform/files/common/files'; -import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; export interface IToolbarActions { @@ -57,7 +57,7 @@ export abstract class TitleControl extends Themable { private currentPrimaryEditorActionIds: string[] = []; private currentSecondaryEditorActionIds: string[] = []; - private editorActionsToolbar: ToolBar; + private editorActionsToolbar: ToolBar | undefined; private resourceContext: ResourceContextKey; private editorPinnedContext: IContextKey; @@ -188,7 +188,8 @@ export abstract class TitleControl extends Themable { primaryEditorActions.some(action => action instanceof ExecuteCommandAction) || // execute command actions can have the same ID but different arguments secondaryEditorActions.some(action => action instanceof ExecuteCommandAction) // see also https://github.com/Microsoft/vscode/issues/16298 ) { - this.editorActionsToolbar.setActions(primaryEditorActions, secondaryEditorActions)(); + const editorActionsToolbar = assertIsDefined(this.editorActionsToolbar); + editorActionsToolbar.setActions(primaryEditorActions, secondaryEditorActions)(); this.currentPrimaryEditorActionIds = primaryEditorActionIds; this.currentSecondaryEditorActionIds = secondaryEditorActionIds; @@ -227,7 +228,7 @@ export abstract class TitleControl extends Themable { const activeControl = this.group.activeControl; if (activeControl instanceof BaseEditor) { const codeEditor = getCodeEditor(activeControl.getControl()); - const scopedContextKeyService = codeEditor && codeEditor.invokeWithinContext(accessor => accessor.get(IContextKeyService)) || this.contextKeyService; + const scopedContextKeyService = codeEditor?.invokeWithinContext(accessor => accessor.get(IContextKeyService)) || this.contextKeyService; const titleBarMenu = this.menuService.createMenu(MenuId.EditorTitle, scopedContextKeyService); this.editorToolBarMenuDisposables.add(titleBarMenu); this.editorToolBarMenuDisposables.add(titleBarMenu.onDidChange(() => { @@ -241,7 +242,9 @@ export abstract class TitleControl extends Themable { } protected clearEditorActionsToolbar(): void { - this.editorActionsToolbar.setActions([], [])(); + if (this.editorActionsToolbar) { + this.editorActionsToolbar.setActions([], [])(); + } this.currentPrimaryEditorActionIds = []; this.currentSecondaryEditorActionIds = []; @@ -257,7 +260,9 @@ export abstract class TitleControl extends Themable { // Set editor group as transfer this.groupTransfer.setData([new DraggedEditorGroupIdentifier(this.group.id)], DraggedEditorGroupIdentifier.prototype); - e.dataTransfer!.effectAllowed = 'copyMove'; + if (e.dataTransfer) { + e.dataTransfer.effectAllowed = 'copyMove'; + } // If tabs are disabled, treat dragging as if an editor tab was dragged if (!this.accessor.partOptions.showTabs) { diff --git a/src/vs/workbench/browser/parts/notifications/media/notificationsActions.css b/src/vs/workbench/browser/parts/notifications/media/notificationsActions.css index 0e36ce1d504..a83633737a0 100644 --- a/src/vs/workbench/browser/parts/notifications/media/notificationsActions.css +++ b/src/vs/workbench/browser/parts/notifications/media/notificationsActions.css @@ -11,6 +11,7 @@ height: 22px; margin-right: 4px; margin-left: 4px; + color: inherit; background-position: center; background-repeat: no-repeat; } diff --git a/src/vs/workbench/browser/parts/notifications/media/notificationsList.css b/src/vs/workbench/browser/parts/notifications/media/notificationsList.css index 4a000267835..1037e6a0672 100644 --- a/src/vs/workbench/browser/parts/notifications/media/notificationsList.css +++ b/src/vs/workbench/browser/parts/notifications/media/notificationsList.css @@ -38,6 +38,7 @@ height: 22px; margin-right: 4px; margin-left: 4px; + font-size: 18px; background-position: center; background-repeat: no-repeat; } @@ -50,6 +51,7 @@ text-overflow: ellipsis; flex: 1; /* let the message always grow */ user-select: text; + -webkit-user-select: text; } .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-message a:focus { @@ -105,7 +107,8 @@ } .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-button { - max-width: fit-content; + width: fit-content; + width: -moz-fit-content; padding: 5px 10px; margin: 4px 5px; /* allows button focus outline to be visible */ font-size: 12px; diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index c2c688d9073..94bfac3f5cf 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -43,7 +43,7 @@ export class ClearAllNotificationsAction extends Action { label: string, @ICommandService private readonly commandService: ICommandService ) { - super(id, label, 'codicon-close-all'); + super(id, label, 'codicon-clear-all'); } run(notification: INotificationViewItem): Promise { @@ -63,7 +63,7 @@ export class HideNotificationsCenterAction extends Action { label: string, @ICommandService private readonly commandService: ICommandService ) { - super(id, label, 'codicon-chevron-down'); + super(id, label, 'codicon-close'); } run(notification: INotificationViewItem): Promise { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index a0077787b11..b3444fa21e7 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -22,21 +22,23 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ClearAllNotificationsAction, HideNotificationsCenterAction, NotificationActionRunner } from 'vs/workbench/browser/parts/notifications/notificationsActions'; import { IAction } from 'vs/base/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { assertAllDefined, assertIsDefined } from 'vs/base/common/types'; export class NotificationsCenter extends Themable { - private static MAX_DIMENSIONS = new Dimension(450, 400); + private static readonly MAX_DIMENSIONS = new Dimension(450, 400); private readonly _onDidChangeVisibility: Emitter = this._register(new Emitter()); readonly onDidChangeVisibility: Event = this._onDidChangeVisibility.event; - private notificationsCenterContainer: HTMLElement; - private notificationsCenterHeader: HTMLElement; - private notificationsCenterTitle: HTMLSpanElement; - private notificationsList: NotificationsList; - private _isVisible: boolean; - private workbenchDimensions: Dimension; + private notificationsCenterContainer: HTMLElement | undefined; + private notificationsCenterHeader: HTMLElement | undefined; + private notificationsCenterTitle: HTMLSpanElement | undefined; + private notificationsList: NotificationsList | undefined; + private _isVisible: boolean | undefined; + private workbenchDimensions: Dimension | undefined; private notificationsCenterVisibleContextKey: IContextKey; + private clearAllAction: ClearAllNotificationsAction | undefined; constructor( private container: HTMLElement, @@ -61,12 +63,13 @@ export class NotificationsCenter extends Themable { } get isVisible(): boolean { - return this._isVisible; + return !!this._isVisible; } show(): void { if (this._isVisible) { - this.notificationsList.show(true /* focus */); + const notificationsList = assertIsDefined(this.notificationsList); + notificationsList.show(true /* focus */); return; // already visible } @@ -80,18 +83,19 @@ export class NotificationsCenter extends Themable { this.updateTitle(); // Make visible + const [notificationsList, notificationsCenterContainer] = assertAllDefined(this.notificationsList, this.notificationsCenterContainer); this._isVisible = true; - addClass(this.notificationsCenterContainer, 'visible'); - this.notificationsList.show(); + addClass(notificationsCenterContainer, 'visible'); + notificationsList.show(); // Layout this.layout(this.workbenchDimensions); // Show all notifications that are present now - this.notificationsList.updateNotificationsList(0, 0, this.model.notifications); + notificationsList.updateNotificationsList(0, 0, this.model.notifications); // Focus first - this.notificationsList.focusFirst(); + notificationsList.focusFirst(); // Theming this.updateStyles(); @@ -104,10 +108,14 @@ export class NotificationsCenter extends Themable { } private updateTitle(): void { + const [notificationsCenterTitle, clearAllAction] = assertAllDefined(this.notificationsCenterTitle, this.clearAllAction); + if (this.model.notifications.length === 0) { - this.notificationsCenterTitle.textContent = localize('notificationsEmpty', "No new notifications"); + notificationsCenterTitle.textContent = localize('notificationsEmpty', "No new notifications"); + clearAllAction.enabled = false; } else { - this.notificationsCenterTitle.textContent = localize('notifications', "Notifications"); + notificationsCenterTitle.textContent = localize('notifications', "Notifications"); + clearAllAction.enabled = true; } } @@ -139,12 +147,12 @@ export class NotificationsCenter extends Themable { actionRunner })); + this.clearAllAction = this._register(this.instantiationService.createInstance(ClearAllNotificationsAction, ClearAllNotificationsAction.ID, ClearAllNotificationsAction.LABEL)); + notificationsToolBar.push(this.clearAllAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(this.clearAllAction) }); + const hideAllAction = this._register(this.instantiationService.createInstance(HideNotificationsCenterAction, HideNotificationsCenterAction.ID, HideNotificationsCenterAction.LABEL)); notificationsToolBar.push(hideAllAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(hideAllAction) }); - const clearAllAction = this._register(this.instantiationService.createInstance(ClearAllNotificationsAction, ClearAllNotificationsAction.ID, ClearAllNotificationsAction.LABEL)); - notificationsToolBar.push(clearAllAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(clearAllAction) }); - // Notifications List this.notificationsList = this.instantiationService.createInstance(NotificationsList, this.notificationsCenterContainer, { ariaLabel: localize('notificationsList', "Notifications List") @@ -167,16 +175,17 @@ export class NotificationsCenter extends Themable { let focusGroup = false; // Update notifications list based on event + const [notificationsList, notificationsCenterContainer] = assertAllDefined(this.notificationsList, this.notificationsCenterContainer); switch (e.kind) { case NotificationChangeType.ADD: - this.notificationsList.updateNotificationsList(e.index, 0, [e.item]); + notificationsList.updateNotificationsList(e.index, 0, [e.item]); break; case NotificationChangeType.CHANGE: - this.notificationsList.updateNotificationsList(e.index, 1, [e.item]); + notificationsList.updateNotificationsList(e.index, 1, [e.item]); break; case NotificationChangeType.REMOVE: - focusGroup = isAncestor(document.activeElement, this.notificationsCenterContainer); - this.notificationsList.updateNotificationsList(e.index, 1); + focusGroup = isAncestor(document.activeElement, notificationsCenterContainer); + notificationsList.updateNotificationsList(e.index, 1); break; } @@ -195,7 +204,7 @@ export class NotificationsCenter extends Themable { } hide(): void { - if (!this._isVisible || !this.notificationsCenterContainer) { + if (!this._isVisible || !this.notificationsCenterContainer || !this.notificationsList) { return; // already hidden } @@ -219,22 +228,22 @@ export class NotificationsCenter extends Themable { } protected updateStyles(): void { - if (this.notificationsCenterContainer) { + if (this.notificationsCenterContainer && this.notificationsCenterHeader) { const widgetShadowColor = this.getColor(widgetShadow); - this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : null; + this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : ''; const borderColor = this.getColor(NOTIFICATIONS_CENTER_BORDER); - this.notificationsCenterContainer.style.border = borderColor ? `1px solid ${borderColor}` : null; + this.notificationsCenterContainer.style.border = borderColor ? `1px solid ${borderColor}` : ''; const headerForeground = this.getColor(NOTIFICATIONS_CENTER_HEADER_FOREGROUND); this.notificationsCenterHeader.style.color = headerForeground ? headerForeground.toString() : null; const headerBackground = this.getColor(NOTIFICATIONS_CENTER_HEADER_BACKGROUND); - this.notificationsCenterHeader.style.background = headerBackground ? headerBackground.toString() : null; + this.notificationsCenterHeader.style.background = headerBackground ? headerBackground.toString() : ''; } } - layout(dimension: Dimension): void { + layout(dimension: Dimension | undefined): void { this.workbenchDimensions = dimension; if (this._isVisible && this.notificationsCenterContainer) { @@ -264,7 +273,8 @@ export class NotificationsCenter extends Themable { } // Apply to list - this.notificationsList.layout(Math.min(maxWidth, availableWidth), Math.min(maxHeight, availableHeight)); + const notificationsList = assertIsDefined(this.notificationsList); + notificationsList.layout(Math.min(maxWidth, availableWidth), Math.min(maxHeight, availableHeight)); } } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index c69d0ff5bce..ba022d7fac7 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -16,10 +16,11 @@ import { NotificationsListDelegate, NotificationRenderer } from 'vs/workbench/br import { NotificationActionRunner, CopyNotificationMessageAction } from 'vs/workbench/browser/parts/notifications/notificationsActions'; import { NotificationFocusedContext } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; export class NotificationsList extends Themable { - private listContainer: HTMLElement; - private list: WorkbenchList; + private listContainer: HTMLElement | undefined; + private list: WorkbenchList | undefined; private viewModel: INotificationViewItem[]; private isVisible: boolean | undefined; @@ -38,7 +39,8 @@ export class NotificationsList extends Themable { show(focus?: boolean): void { if (this.isVisible) { if (focus) { - this.list.domFocus(); + const list = assertIsDefined(this.list); + list.domFocus(); } return; // already visible @@ -54,7 +56,8 @@ export class NotificationsList extends Themable { // Focus if (focus) { - this.list.domFocus(); + const list = assertIsDefined(this.list); + list.domFocus(); } } @@ -70,7 +73,7 @@ export class NotificationsList extends Themable { const renderer = this.instantiationService.createInstance(NotificationRenderer, actionRunner); // List - this.list = this._register(this.instantiationService.createInstance( + const list = this.list = this._register(this.instantiationService.createInstance>( WorkbenchList, 'NotificationsList', this.listContainer, @@ -85,13 +88,13 @@ export class NotificationsList extends Themable { // Context menu to copy message const copyAction = this._register(this.instantiationService.createInstance(CopyNotificationMessageAction, CopyNotificationMessageAction.ID, CopyNotificationMessageAction.LABEL)); - this._register((this.list.onContextMenu(e => { + this._register((list.onContextMenu(e => { if (!e.element) { return; } this.contextMenuService.showContextMenu({ - getAnchor: () => e.anchor!, + getAnchor: () => e.anchor, getActions: () => [copyAction], getActionsContext: () => e.element, actionRunner @@ -99,27 +102,27 @@ export class NotificationsList extends Themable { }))); // Toggle on double click - this._register((this.list.onMouseDblClick(event => (event.element as INotificationViewItem).toggle()))); + this._register((list.onMouseDblClick(event => (event.element as INotificationViewItem).toggle()))); // Clear focus when DOM focus moves out // Use document.hasFocus() to not clear the focus when the entire window lost focus - // This ensures that when the focus comes back, the notifciation is still focused - const listFocusTracker = this._register(trackFocus(this.list.getHTMLElement())); + // This ensures that when the focus comes back, the notification is still focused + const listFocusTracker = this._register(trackFocus(list.getHTMLElement())); this._register(listFocusTracker.onDidBlur(() => { if (document.hasFocus()) { - this.list.setFocus([]); + list.setFocus([]); } })); // Context key - NotificationFocusedContext.bindTo(this.list.contextKeyService); + NotificationFocusedContext.bindTo(list.contextKeyService); // Only allow for focus in notifications, as the // selection is too strong over the contents of // the notification - this._register(this.list.onSelectionChange(e => { + this._register(list.onSelectionChange(e => { if (e.indexes.length > 0) { - this.list.setSelection([]); + list.setSelection([]); } })); @@ -129,23 +132,24 @@ export class NotificationsList extends Themable { } updateNotificationsList(start: number, deleteCount: number, items: INotificationViewItem[] = []) { - const listHasDOMFocus = isAncestor(document.activeElement, this.listContainer); + const [list, listContainer] = assertAllDefined(this.list, this.listContainer); + const listHasDOMFocus = isAncestor(document.activeElement, listContainer); // Remember focus and relative top of that item - const focusedIndex = this.list.getFocus()[0]; + const focusedIndex = list.getFocus()[0]; const focusedItem = this.viewModel[focusedIndex]; let focusRelativeTop: number | null = null; if (typeof focusedIndex === 'number') { - focusRelativeTop = this.list.getRelativeTop(focusedIndex); + focusRelativeTop = list.getRelativeTop(focusedIndex); } // Update view model this.viewModel.splice(start, deleteCount, ...items); // Update list - this.list.splice(start, deleteCount, items); - this.list.layout(); + list.splice(start, deleteCount, items); + list.layout(); // Hide if no more notifications to show if (this.viewModel.length === 0) { @@ -167,15 +171,15 @@ export class NotificationsList extends Themable { } if (typeof focusRelativeTop === 'number') { - this.list.reveal(indexToFocus, focusRelativeTop); + list.reveal(indexToFocus, focusRelativeTop); } - this.list.setFocus([indexToFocus]); + list.setFocus([indexToFocus]); } // Restore DOM focus if we had focus before if (listHasDOMFocus) { - this.list.domFocus(); + list.domFocus(); } } @@ -204,7 +208,7 @@ export class NotificationsList extends Themable { } hasFocus(): boolean { - if (!this.isVisible || !this.list) { + if (!this.isVisible || !this.listContainer) { return false; // hidden } @@ -217,7 +221,7 @@ export class NotificationsList extends Themable { this.listContainer.style.color = foreground ? foreground.toString() : null; const background = this.getColor(NOTIFICATIONS_BACKGROUND); - this.listContainer.style.background = background ? background.toString() : null; + this.listContainer.style.background = background ? background.toString() : ''; const outlineColor = this.getColor(contrastBorder); this.listContainer.style.outlineColor = outlineColor ? outlineColor.toString() : ''; @@ -225,7 +229,7 @@ export class NotificationsList extends Themable { } layout(width: number, maxHeight?: number): void { - if (this.list) { + if (this.listContainer && this.list) { this.listContainer.style.width = `${width}px`; if (typeof maxHeight === 'number') { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts index 69c224d207b..97c9af2a622 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, INotificationViewItem, IStatusMessageChangeEvent, StatusMessageChangeType, IStatusMessageViewItem } from 'vs/workbench/common/notifications'; -import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { HIDE_NOTIFICATIONS_CENTER, SHOW_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { localize } from 'vs/nls'; diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index b949d8b0e08..63d8c084731 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -18,11 +18,12 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { NotificationsToastsVisibleContext } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { localize } from 'vs/nls'; -import { Severity } from 'vs/platform/notification/common/notification'; +import { Severity, NotificationsFilter } from 'vs/platform/notification/common/notification'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; import { timeout } from 'vs/base/common/async'; +import { assertIsDefined } from 'vs/base/common/types'; interface INotificationToast { item: INotificationViewItem; @@ -40,8 +41,8 @@ enum ToastVisibility { export class NotificationsToasts extends Themable { - private static MAX_WIDTH = 450; - private static MAX_NOTIFICATIONS = 3; + private static readonly MAX_WIDTH = 450; + private static readonly MAX_NOTIFICATIONS = 3; private static PURGE_TIMEOUT: { [severity: number]: number } = (() => { const intervals = Object.create(null); @@ -52,8 +53,8 @@ export class NotificationsToasts extends Themable { return intervals; })(); - private notificationsToastsContainer: HTMLElement; - private workbenchDimensions: Dimension; + private notificationsToastsContainer: HTMLElement | undefined; + private workbenchDimensions: Dimension | undefined; private isNotificationsCenterVisible: boolean | undefined; private mapNotificationToToast: Map; private notificationsToastsVisibleContextKey: IContextKey; @@ -67,7 +68,7 @@ export class NotificationsToasts extends Themable { @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IContextKeyService contextKeyService: IContextKeyService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IWindowService private readonly windowService: IWindowService + @IHostService private readonly hostService: IHostService ) { super(themeService); @@ -91,6 +92,13 @@ export class NotificationsToasts extends Themable { // Update toasts on notification changes this._register(this.model.onDidNotificationChange(e => this.onDidNotificationChange(e))); }); + + // Filter + this._register(this.model.onDidFilterChange(filter => { + if (filter === NotificationsFilter.SILENT || filter === NotificationsFilter.ERROR) { + this.hide(); + } + })); } private async onCanShowNotifications(): Promise { @@ -125,15 +133,16 @@ export class NotificationsToasts extends Themable { } // Lazily create toasts containers - if (!this.notificationsToastsContainer) { - this.notificationsToastsContainer = document.createElement('div'); - addClass(this.notificationsToastsContainer, 'notifications-toasts'); + let notificationsToastsContainer = this.notificationsToastsContainer; + if (!notificationsToastsContainer) { + notificationsToastsContainer = this.notificationsToastsContainer = document.createElement('div'); + addClass(notificationsToastsContainer, 'notifications-toasts'); - this.container.appendChild(this.notificationsToastsContainer); + this.container.appendChild(notificationsToastsContainer); } // Make Visible - addClass(this.notificationsToastsContainer, 'visible'); + addClass(notificationsToastsContainer, 'visible'); const itemDisposables = new DisposableStore(); @@ -141,11 +150,11 @@ export class NotificationsToasts extends Themable { const notificationToastContainer = document.createElement('div'); addClass(notificationToastContainer, 'notification-toast-container'); - const firstToast = this.notificationsToastsContainer.firstChild; + const firstToast = notificationsToastsContainer.firstChild; if (firstToast) { - this.notificationsToastsContainer.insertBefore(notificationToastContainer, firstToast); // always first + notificationsToastsContainer.insertBefore(notificationToastContainer, firstToast); // always first } else { - this.notificationsToastsContainer.appendChild(notificationToastContainer); + notificationsToastsContainer.appendChild(notificationToastContainer); } // Toast @@ -155,6 +164,7 @@ export class NotificationsToasts extends Themable { // Create toast with item and show const notificationList = this.instantiationService.createInstance(NotificationsList, notificationToast, { + ariaRole: 'dialog', // https://github.com/microsoft/vscode/issues/82728 ariaLabel: localize('notificationsToast', "Notification Toast"), verticalScrollMode: ScrollbarVisibility.Hidden }); @@ -164,8 +174,8 @@ export class NotificationsToasts extends Themable { this.mapNotificationToToast.set(item, toast); itemDisposables.add(toDisposable(() => { - if (this.isVisible(toast)) { - this.notificationsToastsContainer.removeChild(toast.container); + if (this.isVisible(toast) && notificationsToastsContainer) { + notificationsToastsContainer.removeChild(toast.container); } })); @@ -240,9 +250,9 @@ export class NotificationsToasts extends Themable { // again before triggering the timeout again. This prevents an issue where // focussing the window could immediately hide the notification because the // timeout was triggered again. - if (!this.windowService.hasFocus) { + if (!this.hostService.hasFocus) { if (!listener) { - listener = this.windowService.onDidChangeFocus(focus => { + listener = this.hostService.onDidChangeFocus(focus => { if (focus) { hideAfterTimeout(); } @@ -318,7 +328,7 @@ export class NotificationsToasts extends Themable { } hide(): void { - const focusGroup = isAncestor(document.activeElement, this.notificationsToastsContainer); + const focusGroup = this.notificationsToastsContainer ? isAncestor(document.activeElement, this.notificationsToastsContainer) : false; this.removeToasts(); @@ -412,10 +422,10 @@ export class NotificationsToasts extends Themable { protected updateStyles(): void { this.mapNotificationToToast.forEach(t => { const widgetShadowColor = this.getColor(widgetShadow); - t.toast.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : null; + t.toast.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : ''; const borderColor = this.getColor(NOTIFICATIONS_TOAST_BORDER); - t.toast.style.border = borderColor ? `1px solid ${borderColor}` : null; + t.toast.style.border = borderColor ? `1px solid ${borderColor}` : ''; }); } @@ -443,7 +453,7 @@ export class NotificationsToasts extends Themable { return notificationToasts.reverse(); // from newest to oldest } - layout(dimension: Dimension): void { + layout(dimension: Dimension | undefined): void { this.workbenchDimensions = dimension; const maxDimensions = this.computeMaxDimensions(); @@ -525,10 +535,11 @@ export class NotificationsToasts extends Themable { return; } + const notificationsToastsContainer = assertIsDefined(this.notificationsToastsContainer); if (visible) { - this.notificationsToastsContainer.appendChild(toast.container); + notificationsToastsContainer.appendChild(toast.container); } else { - this.notificationsToastsContainer.removeChild(toast.container); + notificationsToastsContainer.removeChild(toast.container); } } diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index cc1cf39379b..075a3d18a0f 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -110,7 +110,7 @@ text-align: center; display: inline-block; box-sizing: border-box; - } +} /** Actions */ @@ -121,9 +121,12 @@ .monaco-workbench .panel .monaco-action-bar .action-item .monaco-select-box { cursor: pointer; min-width: 110px; - margin-right: 10px; + min-height: 18px; + padding: 2px 8px; } +/* Rotate icons when panel is on right */ +.monaco-workbench .part.panel.right .title-actions .codicon-split-horizontal, .monaco-workbench .part.panel.right .title-actions .codicon-chevron-up, .monaco-workbench .part.panel.right .title-actions .codicon-chevron-down { transform: rotate(-90deg); diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index c8419eed7e7..30de9340067 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -21,7 +21,7 @@ import { ActivePanelContext, PanelPositionContext } from 'vs/workbench/common/pa export class ClosePanelAction extends Action { static readonly ID = 'workbench.action.closePanel'; - static LABEL = nls.localize('closePanel', "Close Panel"); + static readonly LABEL = nls.localize('closePanel', "Close Panel"); constructor( id: string, @@ -40,7 +40,7 @@ export class ClosePanelAction extends Action { export class TogglePanelAction extends Action { static readonly ID = 'workbench.action.togglePanel'; - static LABEL = nls.localize('togglePanel', "Toggle Panel"); + static readonly LABEL = nls.localize('togglePanel', "Toggle Panel"); constructor( id: string, @@ -209,7 +209,7 @@ export class SwitchPanelViewAction extends Action { export class PreviousPanelViewAction extends SwitchPanelViewAction { static readonly ID = 'workbench.action.previousPanelView'; - static LABEL = nls.localize('previousPanelView', 'Previous Panel View'); + static readonly LABEL = nls.localize('previousPanelView', 'Previous Panel View'); constructor( id: string, @@ -227,7 +227,7 @@ export class PreviousPanelViewAction extends SwitchPanelViewAction { export class NextPanelViewAction extends SwitchPanelViewAction { static readonly ID = 'workbench.action.nextPanelView'; - static LABEL = nls.localize('nextPanelView', 'Next Panel View'); + static readonly LABEL = nls.localize('nextPanelView', 'Next Panel View'); constructor( id: string, diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 103e0075498..be69e4c61e5 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/panelpart'; import { IAction } from 'vs/base/common/actions'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Event } from 'vs/base/common/event'; import { Registry } from 'vs/platform/registry/common/platform'; import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { IPanel, ActivePanelContext, PanelFocusContext } from 'vs/workbench/common/panel'; @@ -30,7 +30,7 @@ import { Dimension, trackFocus } from 'vs/base/browser/dom'; import { localize } from 'vs/nls'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { isUndefinedOrNull, withUndefinedAsNull, withNullAsUndefined } from 'vs/base/common/types'; +import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -60,28 +60,25 @@ export class PanelPart extends CompositePart implements IPanelService { readonly snap = true; get preferredHeight(): number | undefined { - const sidebarDimension = this.layoutService.getDimension(Parts.SIDEBAR_PART); - return sidebarDimension.height * 0.4; + // Don't worry about titlebar or statusbar visibility + // The difference is minimal and keeps this function clean + return this.layoutService.dimension.height * 0.4; } get preferredWidth(): number | undefined { - const statusbarPart = this.layoutService.getDimension(Parts.STATUSBAR_PART); - return statusbarPart.width * 0.4; + return this.layoutService.dimension.width * 0.4; } //#endregion - get onDidPanelOpen(): Event<{ panel: IPanel, focus: boolean }> { return Event.map(this.onDidCompositeOpen.event, compositeOpen => ({ panel: compositeOpen.composite, focus: compositeOpen.focus })); } + get onDidPanelOpen(): Event<{ panel: IPanel, focus: boolean; }> { return Event.map(this.onDidCompositeOpen.event, compositeOpen => ({ panel: compositeOpen.composite, focus: compositeOpen.focus })); } readonly onDidPanelClose: Event = this.onDidCompositeClose.event; - private _onDidVisibilityChange = this._register(new Emitter()); - readonly onDidVisibilityChange: Event = this._onDidVisibilityChange.event; - private activePanelContextKey: IContextKey; private panelFocusContextKey: IContextKey; private compositeBar: CompositeBar; - private compositeActions: Map = new Map(); + private compositeActions: Map = new Map(); private blockOpeningPanel = false; private _contentDimension: Dimension | undefined; @@ -123,7 +120,7 @@ export class PanelPart extends CompositePart implements IPanelService { openComposite: (compositeId: string) => Promise.resolve(this.openPanel(compositeId, true)), getActivityAction: (compositeId: string) => this.getCompositeActions(compositeId).activityAction, getCompositePinnedAction: (compositeId: string) => this.getCompositeActions(compositeId).pinnedAction, - getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(PanelActivityAction, this.getPanel(compositeId)), + getOnCompositeClickAction: (compositeId: string) => this.instantiationService.createInstance(PanelActivityAction, assertIsDefined(this.getPanel(compositeId))), getContextMenuActions: () => [ this.instantiationService.createInstance(TogglePanelPositionAction, TogglePanelPositionAction.ID, TogglePanelPositionAction.LABEL), this.instantiationService.createInstance(TogglePanelAction, TogglePanelAction.ID, localize('hidePanel', "Hide Panel")) @@ -208,19 +205,19 @@ export class PanelPart extends CompositePart implements IPanelService { updateStyles(): void { super.updateStyles(); - const container = this.getContainer(); - container.style.backgroundColor = this.getColor(PANEL_BACKGROUND); - container.style.borderLeftColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder); + const container = assertIsDefined(this.getContainer()); + container.style.backgroundColor = this.getColor(PANEL_BACKGROUND) || ''; + container.style.borderLeftColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder) || ''; const title = this.getTitleArea(); if (title) { - title.style.borderTopColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder); + title.style.borderTopColor = this.getColor(PANEL_BORDER) || this.getColor(contrastBorder) || ''; } } - openPanel(id: string, focus?: boolean): Panel | null { + openPanel(id: string, focus?: boolean): Panel | undefined { if (this.blockOpeningPanel) { - return null; // Workaround against a potential race condition + return undefined; // Workaround against a potential race condition } // First check if panel is hidden and show if so @@ -233,7 +230,7 @@ export class PanelPart extends CompositePart implements IPanelService { } } - return withUndefinedAsNull(this.openComposite(id, focus)); + return this.openComposite(id, focus); } showActivity(panelId: string, badge: IBadge, clazz?: string): IDisposable { @@ -241,15 +238,15 @@ export class PanelPart extends CompositePart implements IPanelService { } getPanel(panelId: string): IPanelIdentifier | undefined { - return withNullAsUndefined(Registry.as(PanelExtensions.Panels).getPanel(panelId)); + return Registry.as(PanelExtensions.Panels).getPanel(panelId); } - getPanels(): PanelDescriptor[] { + getPanels(): readonly PanelDescriptor[] { return Registry.as(PanelExtensions.Panels).getPanels() .sort((v1, v2) => typeof v1.order === 'number' && typeof v2.order === 'number' ? v1.order - v2.order : NaN); } - getPinnedPanels(): PanelDescriptor[] { + getPinnedPanels(): readonly PanelDescriptor[] { const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(c => c.id); return this.getPanels() .filter(p => pinnedCompositeIds.indexOf(p.id) !== -1) @@ -263,7 +260,7 @@ export class PanelPart extends CompositePart implements IPanelService { ]; } - getActivePanel(): IPanel | null { + getActivePanel(): IPanel | undefined { return this.getActiveComposite(); } @@ -303,9 +300,9 @@ export class PanelPart extends CompositePart implements IPanelService { } if (this.layoutService.getPanelPosition() === Position.RIGHT) { - this._contentDimension = new Dimension(width - 1, height!); // Take into account the 1px border when layouting + this._contentDimension = new Dimension(width - 1, height); // Take into account the 1px border when layouting } else { - this._contentDimension = new Dimension(width, height!); + this._contentDimension = new Dimension(width, height); } // Layout contents @@ -316,7 +313,7 @@ export class PanelPart extends CompositePart implements IPanelService { } private layoutCompositeBar(): void { - if (this._contentDimension) { + if (this._contentDimension && this.dimension) { let availableWidth = this._contentDimension.width - 40; // take padding into account if (this.toolBar) { availableWidth = Math.max(PanelPart.MIN_COMPOSITE_BAR_WIDTH, availableWidth - this.getToolbarWidth()); // adjust height for global actions showing @@ -326,11 +323,11 @@ export class PanelPart extends CompositePart implements IPanelService { } } - private getCompositeActions(compositeId: string): { activityAction: PanelActivityAction, pinnedAction: ToggleCompositePinnedAction } { + private getCompositeActions(compositeId: string): { activityAction: PanelActivityAction, pinnedAction: ToggleCompositePinnedAction; } { let compositeActions = this.compositeActions.get(compositeId); if (!compositeActions) { compositeActions = { - activityAction: this.instantiationService.createInstance(PanelActivityAction, this.getPanel(compositeId)), + activityAction: this.instantiationService.createInstance(PanelActivityAction, assertIsDefined(this.getPanel(compositeId))), pinnedAction: new ToggleCompositePinnedAction(this.getPanel(compositeId), this.compositeBar) }; @@ -357,7 +354,7 @@ export class PanelPart extends CompositePart implements IPanelService { private getToolbarWidth(): number { const activePanel = this.getActivePanel(); - if (!activePanel) { + if (!activePanel || !this.toolBar) { return 0; } @@ -446,10 +443,6 @@ export class PanelPart extends CompositePart implements IPanelService { this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL); } - setVisible(visible: boolean): void { - this._onDidVisibilityChange.fire(visible); - } - toJSON(): object { return { type: Parts.PANEL_PART diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index 32c171d44a0..fec32d605bf 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -62,13 +62,20 @@ const backButton = { interface QuickInputUI { container: HTMLElement; leftActionBar: ActionBar; + titleBar: HTMLElement; title: HTMLElement; rightActionBar: ActionBar; checkAll: HTMLInputElement; + filterContainer: HTMLElement; inputBox: QuickInputBox; + visibleCountContainer: HTMLElement; visibleCount: CountBadge; + countContainer: HTMLElement; count: CountBadge; + okContainer: HTMLElement; + ok: Button; message: HTMLElement; + customButtonContainer: HTMLElement; customButton: Button; progressBar: ProgressBar; list: QuickInputList; @@ -100,12 +107,12 @@ type Visibilities = { class QuickInput extends Disposable implements IQuickInput { - private _title: string; - private _steps: number; - private _totalSteps: number; + private _title: string | undefined; + private _steps: number | undefined; + private _totalSteps: number | undefined; protected visible = false; private _enabled = true; - private _contextKey: string; + private _contextKey: string | undefined; private _busy = false; private _ignoreFocusOut = false; private _buttons: IQuickInputButton[] = []; @@ -115,7 +122,7 @@ class QuickInput extends Disposable implements IQuickInput { protected readonly visibleDisposables = this._register(new DisposableStore()); - private busyDelay: TimeoutTimer | null; + private busyDelay: TimeoutTimer | undefined; constructor( protected ui: QuickInputUI @@ -127,7 +134,7 @@ class QuickInput extends Disposable implements IQuickInput { return this._title; } - set title(title: string) { + set title(title: string | undefined) { this._title = title; this.update(); } @@ -136,7 +143,7 @@ class QuickInput extends Disposable implements IQuickInput { return this._steps; } - set step(step: number) { + set step(step: number | undefined) { this._steps = step; this.update(); } @@ -145,7 +152,7 @@ class QuickInput extends Disposable implements IQuickInput { return this._totalSteps; } - set totalSteps(totalSteps: number) { + set totalSteps(totalSteps: number | undefined) { this._totalSteps = totalSteps; this.update(); } @@ -163,7 +170,7 @@ class QuickInput extends Disposable implements IQuickInput { return this._contextKey; } - set contextKey(contextKey: string) { + set contextKey(contextKey: string | undefined) { this._contextKey = contextKey; this.update(); } @@ -248,7 +255,7 @@ class QuickInput extends Disposable implements IQuickInput { if (!this.busy && this.busyDelay) { this.ui.progressBar.stop(); this.busyDelay.cancel(); - this.busyDelay = null; + this.busyDelay = undefined; } if (this.buttonsUpdated) { this.buttonsUpdated = false; @@ -305,8 +312,8 @@ class QuickInput extends Disposable implements IQuickInput { this.ui.inputBox.showDecoration(severity); if (severity === Severity.Error) { const styles = this.ui.inputBox.stylesForType(severity); - this.ui.message.style.backgroundColor = styles.background ? `${styles.background}` : null; - this.ui.message.style.border = styles.border ? `1px solid ${styles.border}` : null; + this.ui.message.style.backgroundColor = styles.background ? `${styles.background}` : ''; + this.ui.message.style.border = styles.border ? `1px solid ${styles.border}` : ''; this.ui.message.style.paddingBottom = '4px'; } else { this.ui.message.style.backgroundColor = ''; @@ -323,10 +330,10 @@ class QuickInput extends Disposable implements IQuickInput { class QuickPick extends QuickInput implements IQuickPick { - private static INPUT_BOX_ARIA_LABEL = localize('quickInputBox.ariaLabel', "Type to narrow down results."); + private static readonly INPUT_BOX_ARIA_LABEL = localize('quickInputBox.ariaLabel', "Type to narrow down results."); private _value = ''; - private _placeholder: string; + private _placeholder: string | undefined; private readonly onDidChangeValueEmitter = this._register(new Emitter()); private readonly onDidAcceptEmitter = this._register(new Emitter()); private readonly onDidCustomEmitter = this._register(new Emitter()); @@ -346,15 +353,15 @@ class QuickPick extends QuickInput implements IQuickPi private selectedItemsToConfirm: T[] | null = []; private readonly onDidChangeSelectionEmitter = this._register(new Emitter()); private readonly onDidTriggerItemButtonEmitter = this._register(new Emitter>()); - private _valueSelection: Readonly<[number, number]>; + private _valueSelection: Readonly<[number, number]> | undefined; private valueSelectionUpdated = true; - private _validationMessage: string; - private _ok: boolean; - private _customButton: boolean; - private _customButtonLabel: string; - private _customButtonHover: string; + private _validationMessage: string | undefined; + private _ok = false; + private _customButton = false; + private _customButtonLabel: string | undefined; + private _customButtonHover: string | undefined; - quickNavigate: IQuickNavigateConfiguration; + quickNavigate: IQuickNavigateConfiguration | undefined; get value() { @@ -370,7 +377,7 @@ class QuickPick extends QuickInput implements IQuickPi return this._placeholder; } - set placeholder(placeholder: string) { + set placeholder(placeholder: string | undefined) { this._placeholder = placeholder; this.update(); } @@ -472,7 +479,7 @@ class QuickPick extends QuickInput implements IQuickPi return this._validationMessage; } - set validationMessage(validationMessage: string) { + set validationMessage(validationMessage: string | undefined) { this._validationMessage = validationMessage; this.update(); } @@ -490,7 +497,7 @@ class QuickPick extends QuickInput implements IQuickPi return this._customButtonLabel; } - set customLabel(label: string) { + set customLabel(label: string | undefined) { this._customButtonLabel = label; this.update(); } @@ -499,7 +506,7 @@ class QuickPick extends QuickInput implements IQuickPi return this._customButtonHover; } - set customHover(hover: string) { + set customHover(hover: string | undefined) { this._customButtonHover = hover; this.update(); } @@ -749,8 +756,8 @@ class QuickPick extends QuickInput implements IQuickPi this.ui.message.textContent = null; this.showMessageDecoration(Severity.Ignore); } - this.ui.customButton.label = this.customLabel; - this.ui.customButton.element.title = this.customHover; + this.ui.customButton.label = this.customLabel || ''; + this.ui.customButton.element.title = this.customHover || ''; this.ui.list.matchOnDescription = this.matchOnDescription; this.ui.list.matchOnDetail = this.matchOnDetail; this.ui.list.matchOnLabel = this.matchOnLabel; @@ -762,16 +769,16 @@ class QuickPick extends QuickInput implements IQuickPi class InputBox extends QuickInput implements IInputBox { - private static noPromptMessage = localize('inputModeEntry', "Press 'Enter' to confirm your input or 'Escape' to cancel"); + private static readonly noPromptMessage = localize('inputModeEntry', "Press 'Enter' to confirm your input or 'Escape' to cancel"); private _value = ''; - private _valueSelection: Readonly<[number, number]>; + private _valueSelection: Readonly<[number, number]> | undefined; private valueSelectionUpdated = true; - private _placeholder: string; + private _placeholder: string | undefined; private _password = false; - private _prompt: string; + private _prompt: string | undefined; private noValidationMessage = InputBox.noPromptMessage; - private _validationMessage: string; + private _validationMessage: string | undefined; private readonly onDidValueChangeEmitter = this._register(new Emitter()); private readonly onDidAcceptEmitter = this._register(new Emitter()); @@ -794,7 +801,7 @@ class InputBox extends QuickInput implements IInputBox { return this._placeholder; } - set placeholder(placeholder: string) { + set placeholder(placeholder: string | undefined) { this._placeholder = placeholder; this.update(); } @@ -812,7 +819,7 @@ class InputBox extends QuickInput implements IInputBox { return this._prompt; } - set prompt(prompt: string) { + set prompt(prompt: string | undefined) { this._prompt = prompt; this.noValidationMessage = prompt ? localize('inputModeEntryDescription', "{0} (Press 'Enter' to confirm or 'Escape' to cancel)", prompt) @@ -824,7 +831,7 @@ class InputBox extends QuickInput implements IInputBox { return this._validationMessage; } - set validationMessage(validationMessage: string) { + set validationMessage(validationMessage: string | undefined) { this._validationMessage = validationMessage; this.update(); } @@ -887,14 +894,7 @@ export class QuickInputService extends Component implements IQuickInputService { private static readonly MAX_WIDTH = 600; // Max total width of quick open widget private idPrefix = 'quickInput_'; // Constant since there is still only one. - private titleBar: HTMLElement; - private filterContainer: HTMLElement; - private visibleCountContainer: HTMLElement; - private countContainer: HTMLElement; - private okContainer: HTMLElement; - private ok: Button; - private customButtonContainer: HTMLElement; - private ui: QuickInputUI; + private ui: QuickInputUI | undefined; private comboboxAccessibility = false; private enabled = true; private inQuickOpenWidgets: Record = {}; @@ -1003,9 +1003,9 @@ export class QuickInputService extends Component implements IQuickInputService { })); } - private create() { + private getUI() { if (this.ui) { - return; + return this.ui; } const workbench = this.layoutService.getWorkbenchElement(); @@ -1013,14 +1013,14 @@ export class QuickInputService extends Component implements IQuickInputService { container.tabIndex = -1; container.style.display = 'none'; - this.titleBar = dom.append(container, $('.quick-input-titlebar')); + const titleBar = dom.append(container, $('.quick-input-titlebar')); - const leftActionBar = this._register(new ActionBar(this.titleBar)); + const leftActionBar = this._register(new ActionBar(titleBar)); leftActionBar.domNode.classList.add('quick-input-left-action-bar'); - const title = dom.append(this.titleBar, $('.quick-input-title')); + const title = dom.append(titleBar, $('.quick-input-title')); - const rightActionBar = this._register(new ActionBar(this.titleBar)); + const rightActionBar = this._register(new ActionBar(titleBar)); rightActionBar.domNode.classList.add('quick-input-right-action-bar'); const headerContainer = dom.append(container, $('.quick-input-header')); @@ -1038,31 +1038,31 @@ export class QuickInputService extends Component implements IQuickInputService { })); const extraContainer = dom.append(headerContainer, $('.quick-input-and-message')); - this.filterContainer = dom.append(extraContainer, $('.quick-input-filter')); + const filterContainer = dom.append(extraContainer, $('.quick-input-filter')); - const inputBox = this._register(new QuickInputBox(this.filterContainer)); + const inputBox = this._register(new QuickInputBox(filterContainer)); inputBox.setAttribute('aria-describedby', `${this.idPrefix}message`); - this.visibleCountContainer = dom.append(this.filterContainer, $('.quick-input-visible-count')); - this.visibleCountContainer.setAttribute('aria-live', 'polite'); - this.visibleCountContainer.setAttribute('aria-atomic', 'true'); - const visibleCount = new CountBadge(this.visibleCountContainer, { countFormat: localize({ key: 'quickInput.visibleCount', comment: ['This tells the user how many items are shown in a list of items to select from. The items can be anything. Currently not visible, but read by screen readers.'] }, "{0} Results") }); + const visibleCountContainer = dom.append(filterContainer, $('.quick-input-visible-count')); + visibleCountContainer.setAttribute('aria-live', 'polite'); + visibleCountContainer.setAttribute('aria-atomic', 'true'); + const visibleCount = new CountBadge(visibleCountContainer, { countFormat: localize({ key: 'quickInput.visibleCount', comment: ['This tells the user how many items are shown in a list of items to select from. The items can be anything. Currently not visible, but read by screen readers.'] }, "{0} Results") }); - this.countContainer = dom.append(this.filterContainer, $('.quick-input-count')); - this.countContainer.setAttribute('aria-live', 'polite'); - const count = new CountBadge(this.countContainer, { countFormat: localize({ key: 'quickInput.countSelected', comment: ['This tells the user how many items are selected in a list of items to select from. The items can be anything.'] }, "{0} Selected") }); + const countContainer = dom.append(filterContainer, $('.quick-input-count')); + countContainer.setAttribute('aria-live', 'polite'); + const count = new CountBadge(countContainer, { countFormat: localize({ key: 'quickInput.countSelected', comment: ['This tells the user how many items are selected in a list of items to select from. The items can be anything.'] }, "{0} Selected") }); this._register(attachBadgeStyler(count, this.themeService)); - this.okContainer = dom.append(headerContainer, $('.quick-input-action')); - this.ok = new Button(this.okContainer); - attachButtonStyler(this.ok, this.themeService); - this.ok.label = localize('ok', "OK"); - this._register(this.ok.onDidClick(e => { + const okContainer = dom.append(headerContainer, $('.quick-input-action')); + const ok = new Button(okContainer); + attachButtonStyler(ok, this.themeService); + ok.label = localize('ok', "OK"); + this._register(ok.onDidClick(e => { this.onDidAcceptEmitter.fire(); })); - this.customButtonContainer = dom.append(headerContainer, $('.quick-input-action')); - const customButton = new Button(this.customButtonContainer); + const customButtonContainer = dom.append(headerContainer, $('.quick-input-action')); + const customButton = new Button(customButtonContainer); attachButtonStyler(customButton, this.themeService); customButton.label = localize('custom', "Custom"); this._register(customButton.onDidClick(e => { @@ -1096,14 +1096,14 @@ export class QuickInputService extends Component implements IQuickInputService { })); this._register(list.onDidChangeFocus(() => { if (this.comboboxAccessibility) { - this.ui.inputBox.setAttribute('aria-activedescendant', this.ui.list.getActiveDescendant() || ''); + this.getUI().inputBox.setAttribute('aria-activedescendant', this.getUI().list.getActiveDescendant() || ''); } })); const focusTracker = dom.trackFocus(container); this._register(focusTracker); this._register(focusTracker.onDidBlur(() => { - if (!this.ui.ignoreFocusOut && !this.environmentService.args['sticky-quickopen'] && this.configurationService.getValue(CLOSE_ON_FOCUS_LOST_CONFIG)) { + if (!this.getUI().ignoreFocusOut && !this.environmentService.args['sticky-quickopen'] && this.configurationService.getValue(CLOSE_ON_FOCUS_LOST_CONFIG)) { this.hide(true); } })); @@ -1129,7 +1129,7 @@ export class QuickInputService extends Component implements IQuickInputService { } else { selectors.push('input[type=text]'); } - if (this.ui.list.isDisplayed()) { + if (this.getUI().list.isDisplayed()) { selectors.push('.monaco-list'); } const stops = container.querySelectorAll(selectors.join(', ')); @@ -1150,13 +1150,20 @@ export class QuickInputService extends Component implements IQuickInputService { this.ui = { container, leftActionBar, + titleBar, title, rightActionBar, checkAll, + filterContainer, inputBox, + visibleCountContainer, visibleCount, + countContainer, count, + okContainer, + ok, message, + customButtonContainer, customButton, progressBar, list, @@ -1174,6 +1181,7 @@ export class QuickInputService extends Component implements IQuickInputService { setContextKey: contextKey => this.setContextKey(contextKey), }; this.updateStyles(); + return this.ui; } pick>(picks: Promise[]> | QuickPickInput[], options: O = {}, token: CancellationToken = CancellationToken.None): Promise { @@ -1334,17 +1342,17 @@ export class QuickInputService extends Component implements IQuickInputService { backButton = backButton; createQuickPick(): IQuickPick { - this.create(); - return new QuickPick(this.ui); + const ui = this.getUI(); + return new QuickPick(ui); } createInputBox(): IInputBox { - this.create(); - return new InputBox(this.ui); + const ui = this.getUI(); + return new InputBox(ui); } private show(controller: QuickInput) { - this.create(); + const ui = this.getUI(); this.quickOpenService.close(); const oldController = this.controller; this.controller = controller; @@ -1353,25 +1361,25 @@ export class QuickInputService extends Component implements IQuickInputService { } this.setEnabled(true); - this.ui.leftActionBar.clear(); - this.ui.title.textContent = ''; - this.ui.rightActionBar.clear(); - this.ui.checkAll.checked = false; - // this.ui.inputBox.value = ''; Avoid triggering an event. - this.ui.inputBox.placeholder = ''; - this.ui.inputBox.password = false; - this.ui.inputBox.showDecoration(Severity.Ignore); - this.ui.visibleCount.setCount(0); - this.ui.count.setCount(0); - this.ui.message.textContent = ''; - this.ui.progressBar.stop(); - this.ui.list.setElements([]); - this.ui.list.matchOnDescription = false; - this.ui.list.matchOnDetail = false; - this.ui.list.matchOnLabel = true; - this.ui.ignoreFocusOut = false; + ui.leftActionBar.clear(); + ui.title.textContent = ''; + ui.rightActionBar.clear(); + ui.checkAll.checked = false; + // ui.inputBox.value = ''; Avoid triggering an event. + ui.inputBox.placeholder = ''; + ui.inputBox.password = false; + ui.inputBox.showDecoration(Severity.Ignore); + ui.visibleCount.setCount(0); + ui.count.setCount(0); + ui.message.textContent = ''; + ui.progressBar.stop(); + ui.list.setElements([]); + ui.list.matchOnDescription = false; + ui.list.matchOnDetail = false; + ui.list.matchOnLabel = true; + ui.ignoreFocusOut = false; this.setComboboxAccessibility(false); - this.ui.inputBox.removeAttribute('aria-label'); + ui.inputBox.removeAttribute('aria-label'); const keybinding = this.keybindingService.lookupKeybinding(BackAction.ID); backButton.tooltip = keybinding ? localize('quickInput.backWithKeybinding', "Back ({0})", keybinding.getLabel()) : localize('quickInput.back', "Back"); @@ -1379,38 +1387,40 @@ export class QuickInputService extends Component implements IQuickInputService { this.inQuickOpen('quickInput', true); this.resetContextKeys(); - this.ui.container.style.display = ''; + ui.container.style.display = ''; this.updateLayout(); - this.ui.inputBox.setFocus(); + ui.inputBox.setFocus(); } private setVisibilities(visibilities: Visibilities) { - this.ui.title.style.display = visibilities.title ? '' : 'none'; - this.ui.checkAll.style.display = visibilities.checkAll ? '' : 'none'; - this.filterContainer.style.display = visibilities.inputBox ? '' : 'none'; - this.visibleCountContainer.style.display = visibilities.visibleCount ? '' : 'none'; - this.countContainer.style.display = visibilities.count ? '' : 'none'; - this.okContainer.style.display = visibilities.ok ? '' : 'none'; - this.customButtonContainer.style.display = visibilities.customButton ? '' : 'none'; - this.ui.message.style.display = visibilities.message ? '' : 'none'; - this.ui.list.display(!!visibilities.list); - this.ui.container.classList[visibilities.checkAll ? 'add' : 'remove']('show-checkboxes'); + const ui = this.getUI(); + ui.title.style.display = visibilities.title ? '' : 'none'; + ui.checkAll.style.display = visibilities.checkAll ? '' : 'none'; + ui.filterContainer.style.display = visibilities.inputBox ? '' : 'none'; + ui.visibleCountContainer.style.display = visibilities.visibleCount ? '' : 'none'; + ui.countContainer.style.display = visibilities.count ? '' : 'none'; + ui.okContainer.style.display = visibilities.ok ? '' : 'none'; + ui.customButtonContainer.style.display = visibilities.customButton ? '' : 'none'; + ui.message.style.display = visibilities.message ? '' : 'none'; + ui.list.display(!!visibilities.list); + ui.container.classList[visibilities.checkAll ? 'add' : 'remove']('show-checkboxes'); this.updateLayout(); // TODO } private setComboboxAccessibility(enabled: boolean) { if (enabled !== this.comboboxAccessibility) { + const ui = this.getUI(); this.comboboxAccessibility = enabled; if (this.comboboxAccessibility) { - this.ui.inputBox.setAttribute('role', 'combobox'); - this.ui.inputBox.setAttribute('aria-haspopup', 'true'); - this.ui.inputBox.setAttribute('aria-autocomplete', 'list'); - this.ui.inputBox.setAttribute('aria-activedescendant', this.ui.list.getActiveDescendant() || ''); + ui.inputBox.setAttribute('role', 'combobox'); + ui.inputBox.setAttribute('aria-haspopup', 'true'); + ui.inputBox.setAttribute('aria-autocomplete', 'list'); + ui.inputBox.setAttribute('aria-activedescendant', ui.list.getActiveDescendant() || ''); } else { - this.ui.inputBox.removeAttribute('role'); - this.ui.inputBox.removeAttribute('aria-haspopup'); - this.ui.inputBox.removeAttribute('aria-autocomplete'); - this.ui.inputBox.removeAttribute('aria-activedescendant'); + ui.inputBox.removeAttribute('role'); + ui.inputBox.removeAttribute('aria-haspopup'); + ui.inputBox.removeAttribute('aria-autocomplete'); + ui.inputBox.removeAttribute('aria-activedescendant'); } } } @@ -1424,16 +1434,16 @@ export class QuickInputService extends Component implements IQuickInputService { private setEnabled(enabled: boolean) { if (enabled !== this.enabled) { this.enabled = enabled; - for (const item of this.ui.leftActionBar.viewItems) { + for (const item of this.getUI().leftActionBar.viewItems) { (item as ActionViewItem).getAction().enabled = enabled; } - for (const item of this.ui.rightActionBar.viewItems) { + for (const item of this.getUI().rightActionBar.viewItems) { (item as ActionViewItem).getAction().enabled = enabled; } - this.ui.checkAll.disabled = !enabled; - // this.ui.inputBox.enabled = enabled; Avoid loosing focus. - this.ok.enabled = enabled; - this.ui.list.enabled = enabled; + this.getUI().checkAll.disabled = !enabled; + // this.getUI().inputBox.enabled = enabled; Avoid loosing focus. + this.getUI().ok.enabled = enabled; + this.getUI().list.enabled = enabled; } } @@ -1443,7 +1453,7 @@ export class QuickInputService extends Component implements IQuickInputService { this.controller = null; this.inQuickOpen('quickInput', false); this.resetContextKeys(); - this.ui.container.style.display = 'none'; + this.getUI().container.style.display = 'none'; if (!focusLost) { this.editorGroupService.activeGroup.focus(); } @@ -1453,19 +1463,19 @@ export class QuickInputService extends Component implements IQuickInputService { focus() { if (this.isDisplayed()) { - this.ui.inputBox.setFocus(); + this.getUI().inputBox.setFocus(); } } toggle() { if (this.isDisplayed() && this.controller instanceof QuickPick && this.controller.canSelectMany) { - this.ui.list.toggleCheckbox(); + this.getUI().list.toggleCheckbox(); } } navigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration) { - if (this.isDisplayed() && this.ui.list.isDisplayed()) { - this.ui.list.focus(next ? 'Next' : 'Previous'); + if (this.isDisplayed() && this.getUI().list.isDisplayed()) { + this.getUI().list.focus(next ? 'Next' : 'Previous'); if (quickNavigate && this.controller instanceof QuickPick) { this.controller.quickNavigate = quickNavigate; } @@ -1511,16 +1521,16 @@ export class QuickInputService extends Component implements IQuickInputService { if (this.ui) { // TODO const titleColor = { dark: 'rgba(255, 255, 255, 0.105)', light: 'rgba(0,0,0,.06)', hc: 'black' }[theme.type]; - this.titleBar.style.backgroundColor = titleColor ? titleColor.toString() : null; + this.ui.titleBar.style.backgroundColor = titleColor ? titleColor.toString() : ''; this.ui.inputBox.style(theme); const quickInputBackground = theme.getColor(QUICK_INPUT_BACKGROUND); - this.ui.container.style.backgroundColor = quickInputBackground ? quickInputBackground.toString() : null; + this.ui.container.style.backgroundColor = quickInputBackground ? quickInputBackground.toString() : ''; const quickInputForeground = theme.getColor(QUICK_INPUT_FOREGROUND); this.ui.container.style.color = quickInputForeground ? quickInputForeground.toString() : null; const contrastBorderColor = theme.getColor(contrastBorder); - this.ui.container.style.border = contrastBorderColor ? `1px solid ${contrastBorderColor}` : null; + this.ui.container.style.border = contrastBorderColor ? `1px solid ${contrastBorderColor}` : ''; const widgetShadowColor = theme.getColor(widgetShadow); - this.ui.container.style.boxShadow = widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : null; + this.ui.container.style.boxShadow = widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : ''; } } diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index 4c992ffd94f..f49a302fa42 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -11,7 +11,7 @@ import { WorkbenchList } from 'vs/platform/list/browser/listService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { IMatch } from 'vs/base/common/filters'; -import { matchesFuzzyOcticonAware, parseOcticons } from 'vs/base/common/octicon'; +import { matchesFuzzyCodiconAware, parseCodicons } from 'vs/base/common/codicon'; import { compareAnything } from 'vs/base/common/comparers'; import { Emitter, Event } from 'vs/base/common/event'; import { assign } from 'vs/base/common/objects'; @@ -44,9 +44,9 @@ interface IListElement { } class ListElement implements IListElement { - index: number; - item: IQuickPickItem; - saneLabel: string; + index!: number; + item!: IQuickPickItem; + saneLabel!: string; saneDescription?: string; saneDetail?: string; hidden = false; @@ -66,7 +66,7 @@ class ListElement implements IListElement { labelHighlights?: IMatch[]; descriptionHighlights?: IMatch[]; detailHighlights?: IMatch[]; - fireButtonTriggered: (event: IQuickPickItemButtonEvent) => void; + fireButtonTriggered!: (event: IQuickPickItemButtonEvent) => void; constructor(init: IListElement) { assign(this, init); @@ -114,7 +114,7 @@ class ListElementRenderer implements IListRenderer s && parseOcticons(s).text) + .map(s => s && parseCodicons(s).text) .filter(s => !!s) .join(', ')); // Separator if (element.separator && element.separator.label) { data.separator.textContent = element.separator.label; - data.separator.style.display = null; + data.separator.style.display = ''; } else { data.separator.style.display = 'none'; } @@ -216,7 +216,7 @@ export class QuickInputList { readonly id: string; private container: HTMLElement; private list: WorkbenchList; - private inputElements: Array; + private inputElements: Array = []; private elements: ListElement[] = []; private elementsToIndexes = new Map(); matchOnDescription = false; @@ -490,12 +490,12 @@ export class QuickInputList { }); } - // Filter by value (since we support octicons, use octicon aware fuzzy matching) + // Filter by value (since we support codicons, use codicon aware fuzzy matching) else { this.elements.forEach(element => { - const labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesFuzzyOcticonAware(query, parseOcticons(element.saneLabel))) : undefined; - const descriptionHighlights = this.matchOnDescription ? withNullAsUndefined(matchesFuzzyOcticonAware(query, parseOcticons(element.saneDescription || ''))) : undefined; - const detailHighlights = this.matchOnDetail ? withNullAsUndefined(matchesFuzzyOcticonAware(query, parseOcticons(element.saneDetail || ''))) : undefined; + const labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesFuzzyCodiconAware(query, parseCodicons(element.saneLabel))) : undefined; + const descriptionHighlights = this.matchOnDescription ? withNullAsUndefined(matchesFuzzyCodiconAware(query, parseCodicons(element.saneDescription || ''))) : undefined; + const detailHighlights = this.matchOnDetail ? withNullAsUndefined(matchesFuzzyCodiconAware(query, parseCodicons(element.saneDetail || ''))) : undefined; if (labelHighlights || descriptionHighlights || detailHighlights) { element.labelHighlights = labelHighlights; diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 6db4dd3c4f8..945da6272a8 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -69,21 +69,21 @@ export class QuickOpenController extends Component implements IQuickOpenService private readonly _onHide: Emitter = this._register(new Emitter()); readonly onHide: Event = this._onHide.event; - private preserveInput: boolean; - private isQuickOpen: boolean; - private lastInputValue: string; - private lastSubmittedInputValue: string; - private quickOpenWidget: QuickOpenWidget; + private preserveInput: boolean | undefined; + private isQuickOpen: boolean | undefined; + private lastInputValue: string | undefined; + private lastSubmittedInputValue: string | undefined; + private quickOpenWidget: QuickOpenWidget | undefined; private mapResolvedHandlersToPrefix: Map> = new Map(); private mapContextKeyToContext: Map> = new Map(); private handlerOnOpenCalled: Set = new Set(); private promisesToCompleteOnHide: ValueCallback[] = []; - private previousActiveHandlerDescriptor: QuickOpenHandlerDescriptor | null; + private previousActiveHandlerDescriptor: QuickOpenHandlerDescriptor | null | undefined; private actionProvider = new ContributableActionProvider(); - private closeOnFocusLost: boolean; - private searchInEditorHistory: boolean; + private closeOnFocusLost: boolean | undefined; + private searchInEditorHistory: boolean | undefined; private editorHistoryHandler: EditorHistoryHandler; - private pendingGetResultsInvocation: CancellationTokenSource | null; + private pendingGetResultsInvocation: CancellationTokenSource | null = null; constructor( @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @@ -107,7 +107,7 @@ export class QuickOpenController extends Component implements IQuickOpenService private registerListeners(): void { this._register(this.configurationService.onDidChangeConfiguration(() => this.updateConfiguration())); - this._register(this.layoutService.onTitleBarVisibilityChange(() => this.positionQuickOpenWidget())); + this._register(this.layoutService.onPartVisibilityChange(() => this.positionQuickOpenWidget())); this._register(browser.onDidChangeZoomLevel(() => this.positionQuickOpenWidget())); this._register(this.layoutService.onLayout(dimension => this.layout(dimension))); } @@ -173,12 +173,12 @@ export class QuickOpenController extends Component implements IQuickOpenService // Create upon first open if (!this.quickOpenWidget) { - this.quickOpenWidget = this._register(new QuickOpenWidget( + const quickOpenWidget: QuickOpenWidget = this.quickOpenWidget = this._register(new QuickOpenWidget( this.layoutService.getWorkbenchElement(), { onOk: () => this.onOk(), onCancel: () => { /* ignore */ }, - onType: (value: string) => this.onType(value || ''), + onType: (value: string) => this.onType(quickOpenWidget, value || ''), onShow: () => this.handleOnShow(), onHide: (reason) => this.handleOnHide(reason), onFocusLost: () => !this.closeOnFocusLost @@ -186,8 +186,7 @@ export class QuickOpenController extends Component implements IQuickOpenService inputPlaceHolder: this.hasHandler(HELP_PREFIX) ? nls.localize('quickOpenInput', "Type '?' to get help on the actions you can take from here") : '', keyboardSupport: false, treeCreator: (container, config, opts) => this.instantiationService.createInstance(WorkbenchTree, container, config, opts) - } - )); + })); this._register(attachQuickOpenStyler(this.quickOpenWidget, this.themeService, { background: QUICK_INPUT_BACKGROUND, foreground: QUICK_INPUT_FOREGROUND })); const quickOpenContainer = this.quickOpenWidget.create(); @@ -307,7 +306,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } } - if (key && key.get()) { + if (key?.get()) { return; // already active context } @@ -339,7 +338,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } } - private onType(value: string): void { + private onType(quickOpenWidget: QuickOpenWidget, value: string): void { // cancel any pending get results invocation and create new this.cancelPendingGetResultsInvocation(); @@ -351,16 +350,16 @@ export class QuickOpenController extends Component implements IQuickOpenService const registry = Registry.as(Extensions.Quickopen); const handlerDescriptor = registry.getQuickOpenHandler(value); const defaultHandlerDescriptor = registry.getDefaultQuickOpenHandler(); - const instantProgress = handlerDescriptor && handlerDescriptor.instantProgress; + const instantProgress = handlerDescriptor?.instantProgress; const contextKey = handlerDescriptor ? handlerDescriptor.contextKey : defaultHandlerDescriptor.contextKey; // Reset Progress if (!instantProgress) { - this.quickOpenWidget.getProgressBar().stop().hide(); + quickOpenWidget.getProgressBar().stop().hide(); } // Reset Extra Class - this.quickOpenWidget.setExtraClass(null); + quickOpenWidget.setExtraClass(null); // Update context this.setQuickOpenContextKey(contextKey); @@ -374,7 +373,7 @@ export class QuickOpenController extends Component implements IQuickOpenService // Trigger onOpen this.resolveHandler(handlerDescriptor || defaultHandlerDescriptor); - this.quickOpenWidget.setInput(this.getEditorHistoryWithGroupLabel(), { autoFocusFirstEntry: true }); + quickOpenWidget.setInput(this.getEditorHistoryWithGroupLabel(), { autoFocusFirstEntry: true }); // If quickOpen entered empty we have to clear the prefill-cache this.lastInputValue = ''; @@ -388,7 +387,7 @@ export class QuickOpenController extends Component implements IQuickOpenService if (handlerDescriptor) { this.isQuickOpen = false; - resultPromise = this.handleSpecificHandler(handlerDescriptor, value, pendingResultsInvocationToken); + resultPromise = this.handleSpecificHandler(quickOpenWidget, handlerDescriptor, value, pendingResultsInvocationToken); } // Otherwise handle default handlers if no specific handler present @@ -396,7 +395,7 @@ export class QuickOpenController extends Component implements IQuickOpenService this.isQuickOpen = true; // Cache the value for prefilling the quickOpen next time is opened this.lastInputValue = trimmedValue; - resultPromise = this.handleDefaultHandler(defaultHandlerDescriptor, value, pendingResultsInvocationToken); + resultPromise = this.handleDefaultHandler(quickOpenWidget, defaultHandlerDescriptor, value, pendingResultsInvocationToken); } // Remember as the active one @@ -405,7 +404,7 @@ export class QuickOpenController extends Component implements IQuickOpenService // Progress if task takes a long time setTimeout(() => { if (!resultPromiseDone && !pendingResultsInvocationToken.isCancellationRequested) { - this.quickOpenWidget.getProgressBar().infinite().show(); + quickOpenWidget.getProgressBar().infinite().show(); } }, instantProgress ? 0 : 800); @@ -414,7 +413,7 @@ export class QuickOpenController extends Component implements IQuickOpenService resultPromiseDone = true; if (!pendingResultsInvocationToken.isCancellationRequested) { - this.quickOpenWidget.getProgressBar().hide(); + quickOpenWidget.getProgressBar().hide(); } pendingResultsInvocationTokenSource.dispose(); @@ -428,7 +427,7 @@ export class QuickOpenController extends Component implements IQuickOpenService }); } - private async handleDefaultHandler(handler: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): Promise { + private async handleDefaultHandler(quickOpenWidget: QuickOpenWidget, handler: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): Promise { // Fill in history results if matching and we are configured to search in history let matchingHistoryEntries: QuickOpenEntry[]; @@ -451,8 +450,8 @@ export class QuickOpenController extends Component implements IQuickOpenService // If we have matching entries from history we want to show them directly and not wait for the other results to come in // This also applies when we used to have entries from a previous run and now there are no more history results matching - const previousInput = this.quickOpenWidget.getInput(); - const wasShowingHistory = previousInput && previousInput.entries && previousInput.entries.some(e => e instanceof EditorHistoryEntry || e instanceof EditorHistoryEntryGroup); + const previousInput = quickOpenWidget.getInput(); + const wasShowingHistory = previousInput?.entries?.some(e => e instanceof EditorHistoryEntry || e instanceof EditorHistoryEntryGroup); if (wasShowingHistory || matchingHistoryEntries.length > 0) { (async () => { if (resolvedHandler.hasShortResponseTime()) { @@ -460,7 +459,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } if (!token.isCancellationRequested && !inputSet) { - this.quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true }); + quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true }); inputSet = true; } })(); @@ -472,17 +471,17 @@ export class QuickOpenController extends Component implements IQuickOpenService // now is the time to show the input if we did not have set it before if (!inputSet) { - this.quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true }); + quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true }); inputSet = true; } // merge history and default handler results - const handlerResults = (result && result.entries) || []; - this.mergeResults(quickOpenModel, handlerResults, types.withNullAsUndefined(resolvedHandler.getGroupLabel())); + const handlerResults = result?.entries || []; + this.mergeResults(quickOpenWidget, quickOpenModel, handlerResults, types.withNullAsUndefined(resolvedHandler.getGroupLabel())); } } - private mergeResults(quickOpenModel: QuickOpenModel, handlerResults: QuickOpenEntry[], groupLabel: string | undefined): void { + private mergeResults(quickOpenWidget: QuickOpenWidget, quickOpenModel: QuickOpenModel, handlerResults: QuickOpenEntry[], groupLabel: string | undefined): void { // Remove results already showing by checking for a "resource" property const mapEntryToResource = this.mapEntriesToResource(quickOpenModel); @@ -501,17 +500,17 @@ export class QuickOpenController extends Component implements IQuickOpenService const useTopBorder = quickOpenModel.getEntries().length > 0; additionalHandlerResults[0] = new QuickOpenEntryGroup(additionalHandlerResults[0], groupLabel, useTopBorder); quickOpenModel.addEntries(additionalHandlerResults); - this.quickOpenWidget.refresh(quickOpenModel, { autoFocusFirstEntry }); + quickOpenWidget.refresh(quickOpenModel, { autoFocusFirstEntry }); } // Otherwise if no results are present (even from histoy) indicate this to the user else if (quickOpenModel.getEntries().length === 0) { quickOpenModel.addEntries([new PlaceholderQuickOpenEntry(nls.localize('noResultsFound1', "No results found"))]); - this.quickOpenWidget.refresh(quickOpenModel, { autoFocusFirstEntry: true }); + quickOpenWidget.refresh(quickOpenModel, { autoFocusFirstEntry: true }); } } - private async handleSpecificHandler(handlerDescriptor: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): Promise { + private async handleSpecificHandler(quickOpenWidget: QuickOpenWidget, handlerDescriptor: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): Promise { const resolvedHandler = await this.resolveHandler(handlerDescriptor); // Remove handler prefix from search value @@ -523,7 +522,7 @@ export class QuickOpenController extends Component implements IQuickOpenService const placeHolderLabel = (typeof canRun === 'string') ? canRun : nls.localize('canNotRunPlaceholder', "This quick open handler can not be used in the current context"); const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(placeHolderLabel)], this.actionProvider); - this.showModel(model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel())); + this.showModel(quickOpenWidget, model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel())); return; } @@ -531,12 +530,12 @@ export class QuickOpenController extends Component implements IQuickOpenService // Support extra class from handler const extraClass = resolvedHandler.getClass(); if (extraClass) { - this.quickOpenWidget.setExtraClass(extraClass); + quickOpenWidget.setExtraClass(extraClass); } // When handlers change, clear the result list first before loading the new results if (this.previousActiveHandlerDescriptor !== handlerDescriptor) { - this.clearModel(); + this.clearModel(quickOpenWidget); } // Receive Results from Handler and apply @@ -544,28 +543,28 @@ export class QuickOpenController extends Component implements IQuickOpenService if (!token.isCancellationRequested) { if (!result || !result.entries.length) { const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(resolvedHandler.getEmptyLabel(value))]); - this.showModel(model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel())); + this.showModel(quickOpenWidget, model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel())); } else { - this.showModel(result, resolvedHandler.getAutoFocus(value, { model: result, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel())); + this.showModel(quickOpenWidget, result, resolvedHandler.getAutoFocus(value, { model: result, quickNavigateConfiguration: quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel())); } } } - private showModel(model: IModel, autoFocus?: IAutoFocus, ariaLabel?: string): void { + private showModel(quickOpenWidget: QuickOpenWidget, model: IModel, autoFocus?: IAutoFocus, ariaLabel?: string): void { // If the given model is already set in the widget, refresh and return early - if (this.quickOpenWidget.getInput() === model) { - this.quickOpenWidget.refresh(model, autoFocus); + if (quickOpenWidget.getInput() === model) { + quickOpenWidget.refresh(model, autoFocus); return; } // Otherwise just set it - this.quickOpenWidget.setInput(model, autoFocus, ariaLabel); + quickOpenWidget.setInput(model, autoFocus, ariaLabel); } - private clearModel(): void { - this.showModel(new QuickOpenModel(), undefined); + private clearModel(quickOpenWidget: QuickOpenWidget): void { + this.showModel(quickOpenWidget, new QuickOpenModel(), undefined); } private mapEntriesToResource(model: QuickOpenModel): { [resource: string]: QuickOpenEntry; } { diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index c3b76e31974..809316c6777 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -32,6 +32,7 @@ import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { LayoutPriority } from 'vs/base/browser/ui/grid/grid'; +import { assertIsDefined } from 'vs/base/common/types'; export class SidebarPart extends CompositePart implements IViewletService { @@ -58,7 +59,6 @@ export class SidebarPart extends CompositePart implements IViewletServi } const width = viewlet.getOptimalWidth(); - if (typeof width !== 'number') { return; } @@ -70,9 +70,6 @@ export class SidebarPart extends CompositePart implements IViewletServi get onDidViewletRegister(): Event { return >this.viewletRegistry.onDidRegister; } - private _onDidVisibilityChange = this._register(new Emitter()); - readonly onDidVisibilityChange: Event = this._onDidVisibilityChange.event; - private _onDidViewletDeregister = this._register(new Emitter()); readonly onDidViewletDeregister: Event = this._onDidViewletDeregister.event; @@ -173,19 +170,19 @@ export class SidebarPart extends CompositePart implements IViewletServi super.updateStyles(); // Part container - const container = this.getContainer(); + const container = assertIsDefined(this.getContainer()); - container.style.backgroundColor = this.getColor(SIDE_BAR_BACKGROUND); + container.style.backgroundColor = this.getColor(SIDE_BAR_BACKGROUND) || ''; container.style.color = this.getColor(SIDE_BAR_FOREGROUND); const borderColor = this.getColor(SIDE_BAR_BORDER) || this.getColor(contrastBorder); const isPositionLeft = this.layoutService.getSideBarPosition() === SideBarPosition.LEFT; - container.style.borderRightWidth = borderColor && isPositionLeft ? '1px' : null; - container.style.borderRightStyle = borderColor && isPositionLeft ? 'solid' : null; - container.style.borderRightColor = isPositionLeft ? borderColor : null; - container.style.borderLeftWidth = borderColor && !isPositionLeft ? '1px' : null; - container.style.borderLeftStyle = borderColor && !isPositionLeft ? 'solid' : null; - container.style.borderLeftColor = !isPositionLeft ? borderColor : null; + container.style.borderRightWidth = borderColor && isPositionLeft ? '1px' : ''; + container.style.borderRightStyle = borderColor && isPositionLeft ? 'solid' : ''; + container.style.borderRightColor = isPositionLeft ? borderColor || '' : ''; + container.style.borderLeftWidth = borderColor && !isPositionLeft ? '1px' : ''; + container.style.borderLeftStyle = borderColor && !isPositionLeft ? 'solid' : ''; + container.style.borderLeftColor = !isPositionLeft ? borderColor || '' : ''; } layout(width: number, height: number): void { @@ -198,7 +195,7 @@ export class SidebarPart extends CompositePart implements IViewletServi // Viewlet service - getActiveViewlet(): IViewlet | null { + getActiveViewlet(): IViewlet | undefined { return this.getActiveComposite(); } @@ -210,7 +207,7 @@ export class SidebarPart extends CompositePart implements IViewletServi this.hideActiveComposite(); } - async openViewlet(id: string | undefined, focus?: boolean): Promise { + async openViewlet(id: string | undefined, focus?: boolean): Promise { if (typeof id === 'string' && this.getViewlet(id)) { return this.doOpenViewlet(id, focus); } @@ -221,12 +218,21 @@ export class SidebarPart extends CompositePart implements IViewletServi return this.doOpenViewlet(id, focus); } - return null; + return undefined; } getViewlets(): ViewletDescriptor[] { - return this.viewletRegistry.getViewlets() - .sort((v1, v2) => v1.order! - v2.order!); + return this.viewletRegistry.getViewlets().sort((v1, v2) => { + if (typeof v1.order !== 'number') { + return -1; + } + + if (typeof v2.order !== 'number') { + return 1; + } + + return v1.order - v2.order; + }); } getDefaultViewletId(): string { @@ -237,9 +243,9 @@ export class SidebarPart extends CompositePart implements IViewletServi return this.getViewlets().filter(viewlet => viewlet.id === id)[0]; } - private doOpenViewlet(id: string, focus?: boolean): Viewlet | null { + private doOpenViewlet(id: string, focus?: boolean): Viewlet | undefined { if (this.blockOpeningViewlet) { - return null; // Workaround against a potential race condition + return undefined; // Workaround against a potential race condition } // First check if sidebar is hidden and show if so @@ -275,10 +281,6 @@ export class SidebarPart extends CompositePart implements IViewletServi } } - setVisible(visible: boolean): void { - this._onDidVisibilityChange.fire(visible); - } - toJSON(): object { return { type: Parts.SIDEBAR_PART @@ -308,7 +310,7 @@ class FocusSideBarAction extends Action { } // Focus into active viewlet - let viewlet = this.viewletService.getActiveViewlet(); + const viewlet = this.viewletService.getActiveViewlet(); if (viewlet) { viewlet.focus(); } diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index 92c49501535..a1c0c07debd 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -10,6 +10,7 @@ height: 22px; font-size: 12px; display: flex; + overflow: visible; } .monaco-workbench .part.statusbar.status-border-top::after { @@ -52,7 +53,7 @@ .monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-beak:before { content: ''; position: absolute; - left: calc(50% - 8px); /* 3px (margin) + 5px (padding) = 8px */ + left: calc(50% - 9px); /* 3px (margin) + 5px (padding) + 1px (icon) = 9px */ top: -5px; border-bottom-width: 5px; border-bottom-style: solid; @@ -89,10 +90,11 @@ .monaco-workbench .part.statusbar > .items-container > .statusbar-item > a { cursor: pointer; - display: inline-block; + display: flex; height: 100%; padding: 0 5px 0 5px; white-space: pre; /* gives some degree of styling */ + align-items: center } .monaco-workbench .part.statusbar > .items-container > .statusbar-item > a:hover { @@ -103,7 +105,8 @@ pointer-events: none; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item span.octicon { +.monaco-workbench .part.statusbar > .items-container > .statusbar-item span.codicon { text-align: center; font-size: 14px; + color: inherit; } diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 4d1f1025aa0..b52002f7824 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -7,13 +7,13 @@ import 'vs/css!./media/statusbarpart'; import * as nls from 'vs/nls'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { dispose, IDisposable, Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; -import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; +import { CodiconLabel } from 'vs/base/browser/ui/codiconLabel/codiconLabel'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Part } from 'vs/workbench/browser/part'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; +import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/common/statusbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { Action, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector, ThemeColor } from 'vs/platform/theme/common/themeService'; @@ -27,11 +27,12 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { coalesce } from 'vs/base/common/arrays'; +import { coalesce, find } from 'vs/base/common/arrays'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { ToggleStatusbarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { values } from 'vs/base/common/map'; +import { assertIsDefined } from 'vs/base/common/types'; interface IPendingStatusbarEntry { id: string; @@ -175,13 +176,7 @@ class StatusbarViewModel extends Disposable { } findEntry(container: HTMLElement): IStatusbarViewModelEntry | undefined { - for (const entry of this._entries) { - if (entry.container === container) { - return entry; - } - } - - return undefined; + return find(this._entries, entry => entry.container === container); } getEntries(alignment: StatusbarAlignment): IStatusbarViewModelEntry[] { @@ -238,7 +233,10 @@ class StatusbarViewModel extends Disposable { return entryB.priority - entryA.priority; // higher priority towards the left } - return mapEntryToIndex.get(entryA)! - mapEntryToIndex.get(entryB)!; // otherwise maintain stable order + const indexA = mapEntryToIndex.get(entryA); + const indexB = mapEntryToIndex.get(entryB); + + return indexA! - indexB!; // otherwise maintain stable order (both values known to be in map) } if (entryA.alignment === StatusbarAlignment.LEFT) { @@ -310,8 +308,8 @@ class ToggleStatusbarEntryVisibilityAction extends Action { class HideStatusbarEntryAction extends Action { - constructor(id: string, private model: StatusbarViewModel) { - super(id, nls.localize('hide', "Hide"), undefined, true); + constructor(id: string, name: string, private model: StatusbarViewModel) { + super(id, nls.localize('hide', "Hide '{0}'", name), undefined, true); } run(): Promise { @@ -334,14 +332,14 @@ export class StatusbarPart extends Part implements IStatusbarService { //#endregion - private styleElement!: HTMLStyleElement; + private styleElement: HTMLStyleElement | undefined; private pendingEntries: IPendingStatusbarEntry[] = []; private readonly viewModel: StatusbarViewModel; - private leftItemsContainer!: HTMLElement; - private rightItemsContainer!: HTMLElement; + private leftItemsContainer: HTMLElement | undefined; + private rightItemsContainer: HTMLElement | undefined; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -475,7 +473,7 @@ export class StatusbarPart extends Part implements IStatusbarService { ...this.viewModel.getEntries(StatusbarAlignment.LEFT), ...this.viewModel.getEntries(StatusbarAlignment.RIGHT).reverse() // reversing due to flex: row-reverse ].forEach(entry => { - const target = entry.alignment === StatusbarAlignment.LEFT ? this.leftItemsContainer : this.rightItemsContainer; + const target = assertIsDefined(entry.alignment === StatusbarAlignment.LEFT ? this.leftItemsContainer : this.rightItemsContainer); target.appendChild(entry.container); }); @@ -488,7 +486,7 @@ export class StatusbarPart extends Part implements IStatusbarService { entries.reverse(); // reversing due to flex: row-reverse } - const target = alignment === StatusbarAlignment.LEFT ? this.leftItemsContainer : this.rightItemsContainer; + const target = assertIsDefined(alignment === StatusbarAlignment.LEFT ? this.leftItemsContainer : this.rightItemsContainer); // find an entry that has lower priority than the new one // and then insert the item before that one @@ -562,7 +560,7 @@ export class StatusbarPart extends Part implements IStatusbarService { if (statusEntryUnderMouse) { actions.push(new Separator()); - actions.push(new HideStatusbarEntryAction(statusEntryUnderMouse.id, this.viewModel)); + actions.push(new HideStatusbarEntryAction(statusEntryUnderMouse.id, statusEntryUnderMouse.name, this.viewModel)); } return actions; @@ -571,10 +569,10 @@ export class StatusbarPart extends Part implements IStatusbarService { updateStyles(): void { super.updateStyles(); - const container = this.getContainer(); + const container = assertIsDefined(this.getContainer()); // Background colors - const backgroundColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND); + const backgroundColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND) || ''; container.style.backgroundColor = backgroundColor; container.style.color = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND); @@ -630,7 +628,7 @@ class StatusbarEntryItem extends Disposable { private entry!: IStatusbarEntry; private labelContainer!: HTMLElement; - private label!: OcticonLabel; + private label!: CodiconLabel; private readonly foregroundListener = this._register(new MutableDisposable()); private readonly backgroundListener = this._register(new MutableDisposable()); @@ -659,7 +657,7 @@ class StatusbarEntryItem extends Disposable { this.labelContainer.tabIndex = -1; // allows screen readers to read title, but still prevents tab focus. // Label - this.label = new OcticonLabel(this.labelContainer); + this.label = new CodiconLabel(this.labelContainer); // Add to parent this.container.appendChild(this.labelContainer); @@ -691,8 +689,9 @@ class StatusbarEntryItem extends Disposable { if (!this.entry || entry.command !== this.entry.command) { this.commandListener.clear(); - if (entry.command) { - this.commandListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(entry.command!, entry.arguments)); + const command = entry.command; + if (command) { + this.commandListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command, entry.arguments)); removeClass(this.labelContainer, 'disabled'); } else { @@ -779,7 +778,7 @@ class StatusbarEntryItem extends Disposable { } if (isBackground) { - container.style.backgroundColor = colorResult; + container.style.backgroundColor = colorResult || ''; } else { container.style.color = colorResult; } diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 2b1d303976e..2f312f55819 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -12,6 +12,7 @@ align-items: center; justify-content: center; user-select: none; + -webkit-user-select: none; zoom: 1; /* prevent zooming */ line-height: 22px; height: 22px; @@ -106,54 +107,29 @@ .monaco-workbench.fullscreen .part.titlebar > .window-controls-container { display: none; + background-color: transparent; } -.monaco-workbench .part.titlebar > .window-controls-container > .window-icon-bg { +.monaco-workbench .part.titlebar > .window-controls-container > .window-icon { display: inline-block; - -webkit-app-region: no-drag; + line-height: 30px; height: 100%; - width: 33.34%; + width: 46px; + font-size: 16px; } -.monaco-workbench .part.titlebar > .window-controls-container .window-icon svg { - shape-rendering: crispEdges; - text-align: center; -} - -.monaco-workbench .part.titlebar.titlebar > .window-controls-container .window-close { - -webkit-mask: url('chrome-close.svg') no-repeat 50% 50%; -} - -.monaco-workbench .part.titlebar.titlebar > .window-controls-container .window-unmaximize { - -webkit-mask: url('chrome-restore.svg') no-repeat 50% 50%; -} - -.monaco-workbench .part.titlebar > .window-controls-container .window-maximize { - -webkit-mask: url('chrome-maximize.svg') no-repeat 50% 50%; -} - -.monaco-workbench .part.titlebar > .window-controls-container .window-minimize { - -webkit-mask: url('chrome-minimize.svg') no-repeat 50% 50%; -} - -.monaco-workbench .part.titlebar > .window-controls-container > .window-icon-bg > .window-icon { - height: 100%; - width: 100%; - -webkit-mask-size: 23.1%; -} - -.monaco-workbench .part.titlebar > .window-controls-container > .window-icon-bg:hover { +.monaco-workbench .part.titlebar > .window-controls-container > .window-icon:hover { background-color: rgba(255, 255, 255, 0.1); } -.monaco-workbench .part.titlebar.light > .window-controls-container > .window-icon-bg:hover { +.monaco-workbench .part.titlebar.light > .window-controls-container > .window-icon:hover { background-color: rgba(0, 0, 0, 0.1); } -.monaco-workbench .part.titlebar > .window-controls-container > .window-icon-bg.window-close-bg:hover { +.monaco-workbench .part.titlebar > .window-controls-container > .window-icon.window-close:hover { background-color: rgba(232, 17, 35, 0.9); } .monaco-workbench .part.titlebar > .window-controls-container .window-icon.window-close:hover { - background-color: white; + color: white; } diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index a81f34cc3ae..dac036e01dc 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { IMenuService, MenuId, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService'; -import { IWindowService, MenuBarVisibility, IWindowsService, getTitleBarStyle, IWindowOpenable } from 'vs/platform/windows/common/windows'; +import { MenuBarVisibility, getTitleBarStyle, IWindowOpenable, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IAction, Action } from 'vs/base/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -16,18 +16,18 @@ import { isMacintosh, isWeb } from 'vs/base/common/platform'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IRecentlyOpened, isRecentFolder, IRecent, isRecentWorkspace } from 'vs/platform/history/common/history'; +import { IRecentlyOpened, isRecentFolder, IRecent, isRecentWorkspace, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { MENUBAR_SELECTION_FOREGROUND, MENUBAR_SELECTION_BACKGROUND, MENUBAR_SELECTION_BORDER, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND } from 'vs/workbench/common/theme'; +import { MENUBAR_SELECTION_FOREGROUND, MENUBAR_SELECTION_BACKGROUND, MENUBAR_SELECTION_BORDER, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND } from 'vs/workbench/common/theme'; import { URI } from 'vs/base/common/uri'; import { ILabelService } from 'vs/platform/label/common/label'; import { IUpdateService, StateType } from 'vs/platform/update/common/update'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { MenuBar } from 'vs/base/browser/ui/menu/menubar'; -import { SubmenuAction } from 'vs/base/browser/ui/menu/menu'; +import { SubmenuAction, Direction } from 'vs/base/browser/ui/menu/menu'; import { attachMenuStyler } from 'vs/platform/theme/common/styler'; import { assign } from 'vs/base/common/objects'; import { mnemonicMenuLabel, unmnemonicLabel } from 'vs/base/common/labels'; @@ -36,12 +36,20 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la import { isFullscreen } from 'vs/base/browser/browser'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +// TODO@sbatten https://github.com/microsoft/vscode/issues/81360 +// tslint:disable-next-line: import-patterns layering TODO@sbatten +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { optional } from 'vs/platform/instantiation/common/instantiation'; +// tslint:disable-next-line: import-patterns layering TODO@sbatten +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; + export abstract class MenubarControl extends Disposable { protected keys = [ 'window.menuBarVisibility', 'window.enableMenuBarMnemonics', 'window.customMenuBarAltFocus', + 'workbench.sideBar.location', 'window.nativeTabs' ]; @@ -69,16 +77,15 @@ export abstract class MenubarControl extends Disposable { 'Help': nls.localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help") }; - protected recentlyOpened: IRecentlyOpened; + protected recentlyOpened: IRecentlyOpened = { files: [], workspaces: [] }; protected menuUpdater: RunOnceScheduler; - protected static MAX_MENU_RECENT_ENTRIES = 10; + protected static readonly MAX_MENU_RECENT_ENTRIES = 10; constructor( protected readonly menuService: IMenuService, - protected readonly windowService: IWindowService, - protected readonly windowsService: IWindowsService, + protected readonly workspacesService: IWorkspacesService, protected readonly contextKeyService: IContextKeyService, protected readonly keybindingService: IKeybindingService, protected readonly configurationService: IConfigurationService, @@ -87,9 +94,9 @@ export abstract class MenubarControl extends Disposable { protected readonly storageService: IStorageService, protected readonly notificationService: INotificationService, protected readonly preferencesService: IPreferencesService, - protected readonly environmentService: IEnvironmentService, + protected readonly environmentService: IWorkbenchEnvironmentService, protected readonly accessibilityService: IAccessibilityService, - private readonly hostService: IHostService + protected readonly hostService: IHostService ) { super(); @@ -113,6 +120,9 @@ export abstract class MenubarControl extends Disposable { protected abstract doUpdateMenubar(firstTime: boolean): void; protected registerListeners(): void { + // Listen for window focus changes + this._register(this.hostService.onDidChangeFocus(e => this.onDidChangeWindowFocus(e))); + // Update when config changes this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e))); @@ -120,7 +130,7 @@ export abstract class MenubarControl extends Disposable { this.updateService.onStateChange(() => this.updateMenubar()); // Listen for changes in recently opened menu - this._register(this.windowsService.onRecentlyOpenedChange(() => { this.onRecentlyOpenedChange(); })); + this._register(this.workspacesService.onRecentlyOpenedChange(() => { this.onRecentlyOpenedChange(); })); // Listen to keybindings change this._register(this.keybindingService.onDidUpdateKeybindings(() => this.updateMenubar())); @@ -171,6 +181,13 @@ export abstract class MenubarControl extends Disposable { return result; } + protected onDidChangeWindowFocus(hasFocus: boolean): void { + // When we regain focus, update the recent menu items + if (hasFocus) { + this.onRecentlyOpenedChange(); + } + } + private onConfigurationUpdated(event: IConfigurationChangeEvent): void { if (this.keys.some(key => event.affectsConfiguration(key))) { this.updateMenubar(); @@ -182,7 +199,7 @@ export abstract class MenubarControl extends Disposable { } private onRecentlyOpenedChange(): void { - this.windowService.getRecentlyOpened().then(recentlyOpened => { + this.workspacesService.getRecentlyOpened().then(recentlyOpened => { this.recentlyOpened = recentlyOpened; this.updateMenubar(); }); @@ -215,7 +232,7 @@ export abstract class MenubarControl extends Disposable { const ret: IAction = new Action(commandId, unmnemonicLabel(label), undefined, undefined, (event) => { const openInNewWindow = event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey))); - return this.hostService.openInWindow([openable], { + return this.hostService.openWindow([openable], { forceNewWindow: openInNewWindow }); }); @@ -252,18 +269,17 @@ export abstract class MenubarControl extends Disposable { } export class CustomMenubarControl extends MenubarControl { - private menubar: MenuBar; - private container: HTMLElement; - private alwaysOnMnemonics: boolean; - private focusInsideMenubar: boolean; + private menubar: MenuBar | undefined; + private container: HTMLElement | undefined; + private alwaysOnMnemonics: boolean = false; + private focusInsideMenubar: boolean = false; private readonly _onVisibilityChange: Emitter; private readonly _onFocusStateChange: Emitter; constructor( @IMenuService menuService: IMenuService, - @IWindowService windowService: IWindowService, - @IWindowsService windowsService: IWindowsService, + @IWorkspacesService workspacesService: IWorkspacesService, @IContextKeyService contextKeyService: IContextKeyService, @IKeybindingService keybindingService: IKeybindingService, @IConfigurationService configurationService: IConfigurationService, @@ -272,17 +288,19 @@ export class CustomMenubarControl extends MenubarControl { @IStorageService storageService: IStorageService, @INotificationService notificationService: INotificationService, @IPreferencesService preferencesService: IPreferencesService, - @IEnvironmentService environmentService: IEnvironmentService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IAccessibilityService accessibilityService: IAccessibilityService, @IThemeService private readonly themeService: IThemeService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, - @IHostService hostService: IHostService + @IHostService protected readonly hostService: IHostService, + @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, + @optional(IElectronService) private readonly electronService: IElectronService, + @optional(IElectronEnvironmentService) private readonly electronEnvironmentService: IElectronEnvironmentService ) { super( menuService, - windowService, - windowsService, + workspacesService, contextKeyService, keybindingService, configurationService, @@ -299,7 +317,7 @@ export class CustomMenubarControl extends MenubarControl { this._onVisibilityChange = this._register(new Emitter()); this._onFocusStateChange = this._register(new Emitter()); - this.windowService.getRecentlyOpened().then((recentlyOpened) => { + this.workspacesService.getRecentlyOpened().then((recentlyOpened) => { this.recentlyOpened = recentlyOpened; }); @@ -319,14 +337,45 @@ export class CustomMenubarControl extends MenubarControl { `); } + const activityBarInactiveFgColor = theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND); + if (activityBarInactiveFgColor) { + collector.addRule(` + .monaco-workbench .menubar.compact > .menubar-menu-button { + color: ${activityBarInactiveFgColor}; + } + + .monaco-workbench .menubar.compact .toolbar-toggle-more { + background-color: ${activityBarInactiveFgColor} + } + `); + + } + + const activityBarFgColor = theme.getColor(ACTIVITY_BAR_FOREGROUND); + if (activityBarFgColor) { + collector.addRule(` + .monaco-workbench .menubar.compact > .menubar-menu-button.open, + .monaco-workbench .menubar.compact > .menubar-menu-button:focus, + .monaco-workbench .menubar.compact:not(:focus-within) > .menubar-menu-button:hover { + color: ${activityBarFgColor}; + } + + .monaco-workbench .menubar.compact > .menubar-menu-button.open .toolbar-toggle-more, + .monaco-workbench .menubar.compact > .menubar-menu-button:focus .toolbar-toggle-more, + .monaco-workbench .menubar.compact:not(:focus-within) > .menubar-menu-button:hover .toolbar-toggle-more { + background-color: ${activityBarFgColor} + } + `); + } + const menubarInactiveWindowFgColor = theme.getColor(TITLE_BAR_INACTIVE_FOREGROUND); if (menubarInactiveWindowFgColor) { collector.addRule(` - .monaco-workbench .menubar.inactive > .menubar-menu-button { + .monaco-workbench .menubar.inactive:not(.compact) > .menubar-menu-button { color: ${menubarInactiveWindowFgColor}; } - .monaco-workbench .menubar.inactive > .menubar-menu-button .toolbar-toggle-more { + .monaco-workbench .menubar.inactive:not(.compact) > .menubar-menu-button .toolbar-toggle-more { background-color: ${menubarInactiveWindowFgColor} } `); @@ -336,15 +385,15 @@ export class CustomMenubarControl extends MenubarControl { const menubarSelectedFgColor = theme.getColor(MENUBAR_SELECTION_FOREGROUND); if (menubarSelectedFgColor) { collector.addRule(` - .monaco-workbench .menubar > .menubar-menu-button.open, - .monaco-workbench .menubar > .menubar-menu-button:focus, - .monaco-workbench .menubar:not(:focus-within) > .menubar-menu-button:hover { + .monaco-workbench .menubar:not(.compact) > .menubar-menu-button.open, + .monaco-workbench .menubar:not(.compact) > .menubar-menu-button:focus, + .monaco-workbench .menubar:not(:focus-within):not(.compact) > .menubar-menu-button:hover { color: ${menubarSelectedFgColor}; } - .monaco-workbench .menubar > .menubar-menu-button.open .toolbar-toggle-more, - .monaco-workbench .menubar > .menubar-menu-button:focus .toolbar-toggle-more, - .monaco-workbench .menubar:not(:focus-within) > .menubar-menu-button:hover .toolbar-toggle-more { + .monaco-workbench .menubar:not(.compact) > .menubar-menu-button.open .toolbar-toggle-more, + .monaco-workbench .menubar:not(.compact) > .menubar-menu-button:focus .toolbar-toggle-more, + .monaco-workbench .menubar:not(:focus-within):not(.compact) > .menubar-menu-button:hover .toolbar-toggle-more { background-color: ${menubarSelectedFgColor} } `); @@ -353,9 +402,9 @@ export class CustomMenubarControl extends MenubarControl { const menubarSelectedBgColor = theme.getColor(MENUBAR_SELECTION_BACKGROUND); if (menubarSelectedBgColor) { collector.addRule(` - .monaco-workbench .menubar > .menubar-menu-button.open, - .monaco-workbench .menubar > .menubar-menu-button:focus, - .monaco-workbench .menubar:not(:focus-within) > .menubar-menu-button:hover { + .monaco-workbench .menubar:not(.compact) > .menubar-menu-button.open, + .monaco-workbench .menubar:not(.compact) > .menubar-menu-button:focus, + .monaco-workbench .menubar:not(:focus-within):not(.compact) > .menubar-menu-button:hover { background-color: ${menubarSelectedBgColor}; } `); @@ -396,9 +445,8 @@ export class CustomMenubarControl extends MenubarControl { return null; case StateType.Idle: - const windowId = this.windowService.windowId; return new Action('update.check', nls.localize({ key: 'checkForUpdates', comment: ['&& denotes a mnemonic'] }, "Check for &&Updates..."), undefined, true, () => - this.updateService.checkForUpdates({ windowId })); + this.updateService.checkForUpdates(this.workbenchEnvironmentService.configuration.sessionId)); case StateType.CheckingForUpdates: return new Action('update.checking', nls.localize('checkingForUpdates', "Checking for Updates..."), undefined, false); @@ -424,7 +472,7 @@ export class CustomMenubarControl extends MenubarControl { } private get currentMenubarVisibility(): MenuBarVisibility { - return this.configurationService.getValue('window.menuBarVisibility'); + return getMenuBarVisibility(this.configurationService, this.environmentService); } private get currentDisableMenuBarAltFocus(): boolean { @@ -470,7 +518,21 @@ export class CustomMenubarControl extends MenubarControl { return enableMenuBarMnemonics && (!isWeb || isFullscreen()); } + private get currentCompactMenuMode(): Direction | undefined { + if (this.currentMenubarVisibility !== 'compact') { + return undefined; + } + + const currentSidebarLocation = this.configurationService.getValue('workbench.sideBar.location'); + return currentSidebarLocation === 'right' ? Direction.Left : Direction.Right; + } + private setupCustomMenubar(firstTime: boolean): void { + // If there is no container, we cannot setup the menubar + if (!this.container) { + return; + } + if (firstTime) { this.menubar = this._register(new MenuBar( this.container, { @@ -478,12 +540,14 @@ export class CustomMenubarControl extends MenubarControl { disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), - } - )); + compactMode: this.currentCompactMenuMode + })); this.accessibilityService.alwaysUnderlineAccessKeys().then(val => { this.alwaysOnMnemonics = val; - this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics }); + if (this.menubar) { + this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode }); + } }); this._register(this.menubar.onFocusStateChange(focused => { @@ -509,7 +573,9 @@ export class CustomMenubarControl extends MenubarControl { this._register(attachMenuStyler(this.menubar, this.themeService)); } else { - this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics }); + if (this.menubar) { + this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode }); + } } // Update the menu actions @@ -522,19 +588,20 @@ export class CustomMenubarControl extends MenubarControl { for (let action of actions) { this.insertActionsBefore(action, target); if (action instanceof SubmenuItemAction) { - if (!this.menus[action.item.submenu]) { - this.menus[action.item.submenu] = this.menuService.createMenu(action.item.submenu, this.contextKeyService); - const submenu = this.menus[action.item.submenu]; - this._register(submenu!.onDidChange(() => { + let submenu = this.menus[action.item.submenu]; + if (!submenu) { + submenu = this.menus[action.item.submenu] = this.menuService.createMenu(action.item.submenu, this.contextKeyService); + this._register(submenu.onDidChange(() => { if (!this.focusInsideMenubar) { const actions: IAction[] = []; updateActions(menu, actions, topLevelTitle); - this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) }); + if (this.menubar) { + this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) }); + } } }, this)); } - const submenu = this.menus[action.item.submenu]!; const submenuActions: SubmenuAction[] = []; updateActions(submenu, submenuActions, topLevelTitle); target.push(new SubmenuAction(mnemonicMenuLabel(action.label), submenuActions)); @@ -557,7 +624,9 @@ export class CustomMenubarControl extends MenubarControl { if (!this.focusInsideMenubar) { const actions: IAction[] = []; updateActions(menu, actions, title); - this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); + if (this.menubar) { + this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); + } } })); } @@ -567,21 +636,27 @@ export class CustomMenubarControl extends MenubarControl { updateActions(menu, actions, title); } - if (!firstTime) { - this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); - } else { - this.menubar.push({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); + if (this.menubar) { + if (!firstTime) { + this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); + } else { + this.menubar.push({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); + } } } } - private onDidChangeWindowFocus(hasFocus: boolean): void { + protected onDidChangeWindowFocus(hasFocus: boolean): void { + super.onDidChangeWindowFocus(hasFocus); + if (this.container) { if (hasFocus) { DOM.removeClass(this.container, 'inactive'); } else { DOM.addClass(this.container, 'inactive'); - this.menubar.blur(); + if (this.menubar) { + this.menubar.blur(); + } } } } @@ -589,13 +664,18 @@ export class CustomMenubarControl extends MenubarControl { protected registerListeners(): void { super.registerListeners(); - // Listen for window focus changes - this._register(this.windowService.onDidChangeFocus(e => this.onDidChangeWindowFocus(e))); - - this._register(this.windowService.onDidChangeMaximize(e => this.updateMenubar())); + // Listen for maximize/unmaximize + if (!isWeb) { + this._register(Event.any( + Event.map(Event.filter(this.electronService.onWindowMaximize, id => id === this.electronEnvironmentService.windowId), _ => true), + Event.map(Event.filter(this.electronService.onWindowUnmaximize, id => id === this.electronEnvironmentService.windowId), _ => false) + )(e => this.updateMenubar())); + } this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, () => { - this.menubar.blur(); + if (this.menubar) { + this.menubar.blur(); + } })); // Mnemonics require fullscreen in web @@ -637,7 +717,7 @@ export class CustomMenubarControl extends MenubarControl { } if (this.menubar) { - this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics }); + this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode }); } } } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 0224a4447f2..35465984468 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -8,7 +8,7 @@ import * as resources from 'vs/base/common/resources'; import { Part } from 'vs/workbench/browser/part'; import { ITitleService, ITitleProperties } from 'vs/workbench/services/title/common/titleService'; import { getZoomFactor } from 'vs/base/browser/browser'; -import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows'; +import { MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IAction } from 'vs/base/common/actions'; @@ -18,14 +18,14 @@ import { DisposableStore, dispose } from 'vs/base/common/lifecycle'; import * as nls from 'vs/nls'; import { EditorInput, toResource, Verbosity, SideBySideEditor } from 'vs/workbench/common/editor'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER } from 'vs/workbench/common/theme'; import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { Color } from 'vs/base/common/color'; import { trim } from 'vs/base/common/strings'; -import { EventType, EventHelper, Dimension, isAncestor, hide, show, removeClass, addClass, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; +import { EventType, EventHelper, Dimension, isAncestor, hide, show, removeClass, addClass, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame, removeNode } from 'vs/base/browser/dom'; import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl'; import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; import { template } from 'vs/base/common/labels'; @@ -38,10 +38,14 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenuService, IMenu, MenuId } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IProductService } from 'vs/platform/product/common/productService'; // TODO@sbatten https://github.com/microsoft/vscode/issues/81360 // tslint:disable-next-line: import-patterns layering import { IElectronService } from 'vs/platform/electron/node/electron'; +// tslint:disable-next-line: import-patterns layering +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; export class TitlebarPart extends Part implements ITitleService { @@ -55,8 +59,8 @@ export class TitlebarPart extends Part implements ITitleService { readonly minimumWidth: number = 0; readonly maximumWidth: number = Number.POSITIVE_INFINITY; - get minimumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.configurationService.getValue('window.menuBarVisibility') === 'hidden' ? getZoomFactor() : 1)); } - get maximumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.configurationService.getValue('window.menuBarVisibility') === 'hidden' ? getZoomFactor() : 1)); } + get minimumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.currentMenubarVisibility === 'hidden' ? getZoomFactor() : 1)); } + get maximumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.currentMenubarVisibility === 'hidden' ? getZoomFactor() : 1)); } //#endregion @@ -65,19 +69,20 @@ export class TitlebarPart extends Part implements ITitleService { _serviceBrand: undefined; - private title: HTMLElement; - private dragRegion: HTMLElement; - private windowControls: HTMLElement; - private maxRestoreControl: HTMLElement; - private appIcon: HTMLElement; + private title!: HTMLElement; + private dragRegion: HTMLElement | undefined; + private windowControls: HTMLElement | undefined; + private maxRestoreControl: HTMLElement | undefined; + private appIcon: HTMLElement | undefined; private customMenubar: CustomMenubarControl | undefined; - private menubar: HTMLElement; - private resizer: HTMLElement; - private lastLayoutDimensions: Dimension; + private menubar?: HTMLElement; + private resizer: HTMLElement | undefined; + private lastLayoutDimensions: Dimension | undefined; + private titleBarStyle: 'native' | 'custom'; - private pendingTitle: string; + private pendingTitle: string | undefined; - private isInactive: boolean; + private isInactive: boolean = false; private readonly properties: ITitleProperties = { isPure: true, isAdmin: false }; private readonly activeEditorListeners = this._register(new DisposableStore()); @@ -88,7 +93,6 @@ export class TitlebarPart extends Part implements ITitleService { constructor( @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IWindowService private readonly windowService: IWindowService, @IConfigurationService private readonly configurationService: IConfigurationService, @IEditorService private readonly editorService: IEditorService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @@ -100,17 +104,22 @@ export class TitlebarPart extends Part implements ITitleService { @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IMenuService menuService: IMenuService, @IContextKeyService contextKeyService: IContextKeyService, - @optional(IElectronService) private electronService: IElectronService + @IHostService private readonly hostService: IHostService, + @IProductService private readonly productService: IProductService, + @optional(IElectronService) private electronService: IElectronService, + @optional(IElectronEnvironmentService) private readonly electronEnvironmentService: IElectronEnvironmentService ) { super(Parts.TITLEBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); this.contextMenu = this._register(menuService.createMenu(MenuId.TitleBarContext, contextKeyService)); + this.titleBarStyle = getTitleBarStyle(this.configurationService, this.environmentService); + this.registerListeners(); } private registerListeners(): void { - this._register(this.windowService.onDidChangeFocus(focused => focused ? this.onFocus() : this.onBlur())); + this._register(this.hostService.onDidChangeFocus(focused => focused ? this.onFocus() : this.onBlur())); this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChanged(e))); this._register(this.editorService.onDidActiveEditorChange(() => this.onActiveEditorChange())); this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.titleUpdater.schedule())); @@ -134,6 +143,16 @@ export class TitlebarPart extends Part implements ITitleService { this.titleUpdater.schedule(); } + if (this.titleBarStyle !== 'native') { + if (event.affectsConfiguration('window.menuBarVisibility')) { + if (this.currentMenubarVisibility === 'compact') { + this.uninstallMenubar(); + } else { + this.installMenubar(); + } + } + } + if (event.affectsConfiguration('window.doubleClickIconToClose')) { if (this.appIcon) { this.onUpdateAppIconDragBehavior(); @@ -144,10 +163,12 @@ export class TitlebarPart extends Part implements ITitleService { private onMenubarVisibilityChanged(visible: boolean) { if (isWeb || isWindows || isLinux) { // Hide title when toggling menu bar - if (!isWeb && this.configurationService.getValue('window.menuBarVisibility') === 'toggle' && visible) { + if (!isWeb && this.currentMenubarVisibility === 'toggle' && visible) { // Hack to fix issue #52522 with layered webkit-app-region elements appearing under cursor - hide(this.dragRegion); - setTimeout(() => show(this.dragRegion), 50); + if (this.dragRegion) { + hide(this.dragRegion); + setTimeout(() => show(this.dragRegion!), 50); + } } this.adjustTitleMarginToCenter(); @@ -157,7 +178,7 @@ export class TitlebarPart extends Part implements ITitleService { } private onMenubarFocusChanged(focused: boolean) { - if (!isWeb && (isWindows || isLinux)) { + if (!isWeb && (isWindows || isLinux) && this.currentMenubarVisibility === 'compact' && this.dragRegion) { if (focused) { hide(this.dragRegion); } else { @@ -188,7 +209,7 @@ export class TitlebarPart extends Part implements ITitleService { // Always set the native window title to identify us properly to the OS let nativeTitle = title; if (!trim(nativeTitle)) { - nativeTitle = this.environmentService.appNameLong; + nativeTitle = this.productService.nameLong; } window.document.title = nativeTitle; @@ -210,15 +231,15 @@ export class TitlebarPart extends Part implements ITitleService { let title = this.doGetWindowTitle(); if (this.properties.isAdmin) { - title = `${title || this.environmentService.appNameLong} ${TitlebarPart.NLS_USER_IS_ADMIN}`; + title = `${title || this.productService.nameLong} ${TitlebarPart.NLS_USER_IS_ADMIN}`; } if (!this.properties.isPure) { - title = `${title || this.environmentService.appNameLong} ${TitlebarPart.NLS_UNSUPPORTED}`; + title = `${title || this.productService.nameLong} ${TitlebarPart.NLS_UNSUPPORTED}`; } if (this.environmentService.isExtensionDevelopment) { - title = `${TitlebarPart.NLS_EXTENSION_HOST} - ${title || this.environmentService.appNameLong}`; + title = `${TitlebarPart.NLS_EXTENSION_HOST} - ${title || this.productService.nameLong}`; } return title; @@ -269,14 +290,22 @@ export class TitlebarPart extends Part implements ITitleService { // Compute active editor folder const editorResource = editor ? toResource(editor) : undefined; let editorFolderResource = editorResource ? resources.dirname(editorResource) : undefined; - if (editorFolderResource && editorFolderResource.path === '.') { + if (editorFolderResource?.path === '.') { editorFolderResource = undefined; } // Compute folder resource // Single Root Workspace: always the root single workspace in this case // Otherwise: root folder of the currently active file if any - const folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER })!); + let folder: IWorkspaceFolder | null = null; + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + folder = workspace.folders[0]; + } else { + const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); + if (resource) { + folder = this.contextService.getWorkspaceFolder(resource); + } + } // Variables const activeEditorShort = editor ? editor.getTitle(Verbosity.SHORT) : ''; @@ -289,8 +318,8 @@ export class TitlebarPart extends Part implements ITitleService { const rootPath = root ? this.labelService.getUriLabel(root) : ''; const folderName = folder ? folder.name : ''; const folderPath = folder ? this.labelService.getUriLabel(folder.uri) : ''; - const dirty = editor && editor.isDirty() ? TitlebarPart.TITLE_DIRTY : ''; - const appName = this.environmentService.appNameLong; + const dirty = editor?.isDirty() ? TitlebarPart.TITLE_DIRTY : ''; + const appName = this.productService.nameLong; const remoteName = this.environmentService.configuration.remoteAuthority; const separator = TitlebarPart.TITLE_SEPARATOR; const titleTemplate = this.configurationService.getValue('window.title'); @@ -313,6 +342,36 @@ export class TitlebarPart extends Part implements ITitleService { }); } + private uninstallMenubar(): void { + if (this.customMenubar) { + this.customMenubar.dispose(); + this.customMenubar = undefined; + } + + if (this.menubar) { + removeNode(this.menubar); + this.menubar = undefined; + } + } + + private installMenubar(): void { + // If the menubar is already installed, skip + if (this.menubar) { + return; + } + + this.customMenubar = this._register(this.instantiationService.createInstance(CustomMenubarControl)); + + this.menubar = this.element.insertBefore($('div.menubar'), this.title); + + this.menubar.setAttribute('role', 'menubar'); + + this.customMenubar.create(this.menubar); + + this._register(this.customMenubar.onVisibilityChange(e => this.onMenubarVisibilityChanged(e))); + this._register(this.customMenubar.onFocusStateChange(e => this.onMenubarFocusChanged(e))); + } + createContentArea(parent: HTMLElement): HTMLElement { this.element = parent; @@ -332,15 +391,11 @@ export class TitlebarPart extends Part implements ITitleService { } // Menubar: install a custom menu bar depending on configuration - if (getTitleBarStyle(this.configurationService, this.environmentService) !== 'native' && (!isMacintosh || isWeb)) { - this.customMenubar = this._register(this.instantiationService.createInstance(CustomMenubarControl)); - this.menubar = append(this.element, $('div.menubar')); - this.menubar.setAttribute('role', 'menubar'); - - this.customMenubar.create(this.menubar); - - this._register(this.customMenubar.onVisibilityChange(e => this.onMenubarVisibilityChanged(e))); - this._register(this.customMenubar.onFocusStateChange(e => this.onMenubarFocusChanged(e))); + // and when not in activity bar + if (this.titleBarStyle !== 'native' + && (!isMacintosh || isWeb) + && this.currentMenubarVisibility !== 'compact') { + this.installMenubar(); } // Title @@ -367,17 +422,13 @@ export class TitlebarPart extends Part implements ITitleService { this.windowControls = append(this.element, $('div.window-controls-container')); // Minimize - const minimizeIconContainer = append(this.windowControls, $('div.window-icon-bg')); - const minimizeIcon = append(minimizeIconContainer, $('div.window-icon')); - addClass(minimizeIcon, 'window-minimize'); + const minimizeIcon = append(this.windowControls, $('div.window-icon.window-minimize.codicon.codicon-chrome-minimize')); this._register(addDisposableListener(minimizeIcon, EventType.CLICK, e => { this.electronService.minimizeWindow(); })); // Restore - const restoreIconContainer = append(this.windowControls, $('div.window-icon-bg')); - this.maxRestoreControl = append(restoreIconContainer, $('div.window-icon')); - addClass(this.maxRestoreControl, 'window-max-restore'); + this.maxRestoreControl = append(this.windowControls, $('div.window-icon.window-max-restore.codicon')); this._register(addDisposableListener(this.maxRestoreControl, EventType.CLICK, async e => { const maximized = await this.electronService.isMaximized(); if (maximized) { @@ -388,10 +439,7 @@ export class TitlebarPart extends Part implements ITitleService { })); // Close - const closeIconContainer = append(this.windowControls, $('div.window-icon-bg')); - addClass(closeIconContainer, 'window-close-bg'); - const closeIcon = append(closeIconContainer, $('div.window-icon')); - addClass(closeIcon, 'window-close'); + const closeIcon = append(this.windowControls, $('div.window-icon.window-close.codicon.codicon-chrome-close')); this._register(addDisposableListener(closeIcon, EventType.CLICK, e => { this.electronService.closeWindow(); })); @@ -401,13 +449,17 @@ export class TitlebarPart extends Part implements ITitleService { const isMaximized = this.environmentService.configuration.maximized ? true : false; this.onDidChangeMaximized(isMaximized); - this._register(this.windowService.onDidChangeMaximize(this.onDidChangeMaximized, this)); + + this._register(Event.any( + Event.map(Event.filter(this.electronService.onWindowMaximize, id => id === this.electronEnvironmentService.windowId), _ => true), + Event.map(Event.filter(this.electronService.onWindowUnmaximize, id => id === this.electronEnvironmentService.windowId), _ => false) + )(e => this.onDidChangeMaximized(e))); } // Since the title area is used to drag the window, we do not want to steal focus from the // currently active element. So we restore focus after a timeout back to where it was. this._register(addDisposableListener(this.element, EventType.MOUSE_DOWN, e => { - if (e.target && isAncestor(e.target as HTMLElement, this.menubar)) { + if (e.target && this.menubar && isAncestor(e.target as HTMLElement, this.menubar)) { return; } @@ -427,11 +479,11 @@ export class TitlebarPart extends Part implements ITitleService { private onDidChangeMaximized(maximized: boolean) { if (this.maxRestoreControl) { if (maximized) { - removeClass(this.maxRestoreControl, 'window-maximize'); - addClass(this.maxRestoreControl, 'window-unmaximize'); + removeClass(this.maxRestoreControl, 'codicon-chrome-maximize'); + addClass(this.maxRestoreControl, 'codicon-chrome-restore'); } else { - removeClass(this.maxRestoreControl, 'window-unmaximize'); - addClass(this.maxRestoreControl, 'window-maximize'); + removeClass(this.maxRestoreControl, 'codicon-chrome-restore'); + addClass(this.maxRestoreControl, 'codicon-chrome-maximize'); } } @@ -457,7 +509,7 @@ export class TitlebarPart extends Part implements ITitleService { removeClass(this.element, 'inactive'); } - const titleBackground = this.getColor(this.isInactive ? TITLE_BAR_INACTIVE_BACKGROUND : TITLE_BAR_ACTIVE_BACKGROUND); + const titleBackground = this.getColor(this.isInactive ? TITLE_BAR_INACTIVE_BACKGROUND : TITLE_BAR_ACTIVE_BACKGROUND) || ''; this.element.style.backgroundColor = titleBackground; if (titleBackground && Color.fromHex(titleBackground).isLighter()) { addClass(this.element, 'light'); @@ -469,15 +521,15 @@ export class TitlebarPart extends Part implements ITitleService { this.element.style.color = titleForeground; const titleBorder = this.getColor(TITLE_BAR_BORDER); - this.element.style.borderBottom = titleBorder ? `1px solid ${titleBorder}` : null; + this.element.style.borderBottom = titleBorder ? `1px solid ${titleBorder}` : ''; } } private onUpdateAppIconDragBehavior() { const setting = this.configurationService.getValue('window.doubleClickIconToClose'); - if (setting) { + if (setting && this.appIcon) { (this.appIcon.style as any)['-webkit-app-region'] = 'no-drag'; - } else { + } else if (this.appIcon) { (this.appIcon.style as any)['-webkit-app-region'] = 'drag'; } } @@ -501,7 +553,7 @@ export class TitlebarPart extends Part implements ITitleService { } private adjustTitleMarginToCenter(): void { - if (this.customMenubar) { + if (this.customMenubar && this.menubar) { const leftMarker = (this.appIcon ? this.appIcon.clientWidth : 0) + this.menubar.clientWidth + 10; const rightMarker = this.element.clientWidth - (this.windowControls ? this.windowControls.clientWidth : 0) - 10; @@ -509,8 +561,8 @@ export class TitlebarPart extends Part implements ITitleService { // Center between menu and window controls if (leftMarker > (this.element.clientWidth - this.title.clientWidth) / 2 || rightMarker < (this.element.clientWidth + this.title.clientWidth) / 2) { - this.title.style.position = null; - this.title.style.left = null; + this.title.style.position = ''; + this.title.style.left = ''; this.title.style.transform = ''; return; } @@ -521,22 +573,36 @@ export class TitlebarPart extends Part implements ITitleService { this.title.style.transform = 'translate(-50%, 0)'; } + private get currentMenubarVisibility(): MenuBarVisibility { + return getMenuBarVisibility(this.configurationService, this.environmentService); + } + updateLayout(dimension: Dimension): void { this.lastLayoutDimensions = dimension; if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { // Only prevent zooming behavior on macOS or when the menubar is not visible - if ((!isWeb && isMacintosh) || this.configurationService.getValue('window.menuBarVisibility') === 'hidden') { + if ((!isWeb && isMacintosh) || this.currentMenubarVisibility === 'hidden') { this.title.style.zoom = `${1 / getZoomFactor()}`; if (!isWeb && (isWindows || isLinux)) { - this.appIcon.style.zoom = `${1 / getZoomFactor()}`; - this.windowControls.style.zoom = `${1 / getZoomFactor()}`; + if (this.appIcon) { + this.appIcon.style.zoom = `${1 / getZoomFactor()}`; + } + + if (this.windowControls) { + this.windowControls.style.zoom = `${1 / getZoomFactor()}`; + } } } else { this.title.style.zoom = null; if (!isWeb && (isWindows || isLinux)) { - this.appIcon.style.zoom = null; - this.windowControls.style.zoom = null; + if (this.appIcon) { + this.appIcon.style.zoom = null; + } + + if (this.windowControls) { + this.windowControls.style.zoom = null; + } } } @@ -567,7 +633,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { if (titlebarActiveFg) { collector.addRule(` .monaco-workbench .part.titlebar > .window-controls-container .window-icon { - background-color: ${titlebarActiveFg}; + color: ${titlebarActiveFg}; } `); } @@ -576,7 +642,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { if (titlebarInactiveFg) { collector.addRule(` .monaco-workbench .part.titlebar.inactive > .window-controls-container .window-icon { - background-color: ${titlebarInactiveFg}; + color: ${titlebarInactiveFg}; } `); } diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 03c709a0e06..2d6dc484f22 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -32,7 +32,7 @@ import { WorkbenchAsyncDataTree, TreeResourceNavigator2 } from 'vs/platform/list import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { localize } from 'vs/nls'; import { timeout } from 'vs/base/common/async'; -import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry'; +import { textLinkForeground, textCodeBlockBackground, focusBorder, listFilterMatchHighlight, listFilterMatchHighlightBorder } from 'vs/platform/theme/common/colorRegistry'; import { isString } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -673,15 +673,15 @@ class TreeDataSource implements IAsyncDataSource { // todo@joh,sandy make this proper and contributable from extensions registerThemingParticipant((theme, collector) => { - const findMatchHighlightColor = theme.getColor(editorFindMatchHighlight); - if (findMatchHighlightColor) { - collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; background-color: ${findMatchHighlightColor}; }`); - collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; background-color: ${findMatchHighlightColor}; }`); + const matchBackgroundColor = theme.getColor(listFilterMatchHighlight); + if (matchBackgroundColor) { + collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; background-color: ${matchBackgroundColor}; }`); + collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; background-color: ${matchBackgroundColor}; }`); } - const findMatchHighlightColorBorder = theme.getColor(editorFindMatchHighlightBorder); - if (findMatchHighlightColorBorder) { - collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${findMatchHighlightColorBorder}; box-sizing: border-box; }`); - collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${findMatchHighlightColorBorder}; box-sizing: border-box; }`); + const matchBorderColor = theme.getColor(listFilterMatchHighlightBorder); + if (matchBorderColor) { + collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${matchBorderColor}; box-sizing: border-box; }`); + collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${matchBorderColor}; box-sizing: border-box; }`); } const link = theme.getColor(textLinkForeground); if (link) { @@ -753,6 +753,23 @@ class TreeRenderer extends Disposable implements ITreeRenderer { + if ((Math.abs(start) > label.length) || (Math.abs(end) >= label.length)) { + return ({ start: 0, end: 0 }); + } + if (start < 0) { + start = label.length + start; + } + if (end < 0) { + end = label.length + end; + } + if (start > end) { + const swap = start; + start = end; + end = swap; + } + return ({ start, end }); + }) : undefined; const icon = this.themeService.getTheme().type === LIGHT ? node.icon : node.iconDark; const iconUrl = icon ? URI.revive(icon) : null; const title = node.tooltip ? node.tooltip : resource ? undefined : label; @@ -762,9 +779,9 @@ class TreeRenderer extends Disposable implements ITreeRenderer('explorer.decorations'); - templateData.resourceLabel.setResource({ name: label, description, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: createMatches(element.filterData) }); + templateData.resourceLabel.setResource({ name: label, description, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: matches ? matches : createMatches(element.filterData) }); } else { - templateData.resourceLabel.setResource({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: createMatches(element.filterData) }); + templateData.resourceLabel.setResource({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: matches ? matches : createMatches(element.filterData) }); } templateData.icon.style.backgroundImage = iconUrl ? DOM.asCSSUrl(iconUrl) : ''; diff --git a/src/vs/workbench/browser/parts/views/media/tree-collapsed-dark.svg b/src/vs/workbench/browser/parts/views/media/tree-collapsed-dark.svg deleted file mode 100644 index c2c2298dd5c..00000000000 --- a/src/vs/workbench/browser/parts/views/media/tree-collapsed-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/views/media/tree-collapsed-hc.svg b/src/vs/workbench/browser/parts/views/media/tree-collapsed-hc.svg deleted file mode 100644 index 3732cbc04b8..00000000000 --- a/src/vs/workbench/browser/parts/views/media/tree-collapsed-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/views/media/tree-collapsed-light.svg b/src/vs/workbench/browser/parts/views/media/tree-collapsed-light.svg deleted file mode 100644 index 1952ad63f84..00000000000 --- a/src/vs/workbench/browser/parts/views/media/tree-collapsed-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/views/media/tree-expanded-dark.svg b/src/vs/workbench/browser/parts/views/media/tree-expanded-dark.svg deleted file mode 100644 index 5570923e175..00000000000 --- a/src/vs/workbench/browser/parts/views/media/tree-expanded-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/views/media/tree-expanded-hc.svg b/src/vs/workbench/browser/parts/views/media/tree-expanded-hc.svg deleted file mode 100644 index b370009330c..00000000000 --- a/src/vs/workbench/browser/parts/views/media/tree-expanded-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/views/media/tree-expanded-light.svg b/src/vs/workbench/browser/parts/views/media/tree-expanded-light.svg deleted file mode 100644 index 939ebc8b969..00000000000 --- a/src/vs/workbench/browser/parts/views/media/tree-expanded-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/views/media/views.css b/src/vs/workbench/browser/parts/views/media/views.css index 1127eae5c34..fb062a7a3af 100644 --- a/src/vs/workbench/browser/parts/views/media/views.css +++ b/src/vs/workbench/browser/parts/views/media/views.css @@ -20,31 +20,6 @@ content: ' '; } -.file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before { - background-image: url("tree-expanded-light.svg"); -} - -.file-icon-themable-tree .monaco-tree-row.has-children .content::before { - display: inline-block; - background-image: url("tree-collapsed-light.svg"); -} - -.vs-dark .file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before { - background-image: url("tree-expanded-dark.svg"); -} - -.vs-dark .file-icon-themable-tree .monaco-tree-row.has-children .content::before { - background-image: url("tree-collapsed-dark.svg"); -} - -.hc-black .file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before { - background-image: url("tree-expanded-hc.svg"); -} - -.hc-black .file-icon-themable-tree .monaco-tree-row.has-children .content::before { - background-image: url("tree-collapsed-hc.svg"); -} - .file-icon-themable-tree.align-icons-and-twisties .monaco-tree-row:not(.has-children) .content::before, .file-icon-themable-tree.hide-arrows .monaco-tree-row .content::before { display: none; @@ -58,6 +33,7 @@ background-image: none !important; width: 0 !important; margin-right: 0 !important; + visibility: hidden; } /* Misc */ @@ -69,7 +45,8 @@ .monaco-workbench .tree-explorer-viewlet-tree-view .message { display: flex; padding: 4px 12px 0px 18px; - user-select: text + user-select: text; + -webkit-user-select: text; } .monaco-workbench .tree-explorer-viewlet-tree-view .message p { @@ -132,6 +109,7 @@ width: 16px; height: 22px; -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } .customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .custom-view-tree-node-item-resourceLabel .monaco-icon-label-description-container { diff --git a/src/vs/workbench/browser/parts/views/panelViewlet.ts b/src/vs/workbench/browser/parts/views/panelViewlet.ts index 4a5a2a0cbc3..7a6e3e450ce 100644 --- a/src/vs/workbench/browser/parts/views/panelViewlet.ts +++ b/src/vs/workbench/browser/parts/views/panelViewlet.ts @@ -29,6 +29,7 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IView, FocusedViewContext } from 'vs/workbench/common/views'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { assertIsDefined } from 'vs/base/common/types'; export interface IPanelColors extends IColorMapping { dropBackground?: ColorIdentifier; @@ -46,7 +47,7 @@ export interface IViewletPanelOptions extends IPanelOptions { export abstract class ViewletPanel extends Panel implements IView { - private static AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions'; + private static readonly AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions'; private _onDidFocus = this._register(new Emitter()); readonly onDidFocus: Event = this._onDidFocus.event; @@ -67,10 +68,11 @@ export abstract class ViewletPanel extends Panel implements IView { readonly title: string; protected actionRunner?: IActionRunner; - protected toolbar: ToolBar; + protected toolbar?: ToolBar; private readonly showActionsAlways: boolean = false; - private headerContainer: HTMLElement; - private titleContainer: HTMLElement; + private headerContainer?: HTMLElement; + private titleContainer?: HTMLElement; + protected twistiesContainer?: HTMLElement; constructor( options: IViewletPanelOptions, @@ -133,6 +135,8 @@ export abstract class ViewletPanel extends Panel implements IView { protected renderHeader(container: HTMLElement): void { this.headerContainer = container; + this.renderTwisties(container); + this.renderHeaderTitle(container, this.title); const actions = append(container, $('.actions')); @@ -153,12 +157,18 @@ export abstract class ViewletPanel extends Panel implements IView { this.updateActionsVisibility(); } + protected renderTwisties(container: HTMLElement): void { + this.twistiesContainer = append(container, $('.twisties.codicon.codicon-chevron-right')); + } + protected renderHeaderTitle(container: HTMLElement, title: string): void { this.titleContainer = append(container, $('h3.title', undefined, title)); } protected updateTitle(title: string): void { - this.titleContainer.textContent = title; + if (this.titleContainer) { + this.titleContainer.textContent = title; + } this._onDidChangeTitleArea.fire(); } @@ -170,11 +180,16 @@ export abstract class ViewletPanel extends Panel implements IView { } private setActions(): void { - this.toolbar.setActions(prepareActions(this.getActions()), prepareActions(this.getSecondaryActions()))(); - this.toolbar.context = this.getActionsContext(); + if (this.toolbar) { + this.toolbar.setActions(prepareActions(this.getActions()), prepareActions(this.getSecondaryActions()))(); + this.toolbar.context = this.getActionsContext(); + } } private updateActionsVisibility(): void { + if (!this.headerContainer) { + return; + } const shouldAlwaysShowActions = this.configurationService.getValue('workbench.view.alwaysShowHeaderActions'); toggleClass(this.headerContainer, 'actions-always-visible', shouldAlwaysShowActions); } @@ -222,10 +237,10 @@ export class PanelViewlet extends Viewlet { private lastFocusedPanel: ViewletPanel | undefined; private panelItems: IViewletPanelItem[] = []; - private panelview: PanelView; + private panelview?: PanelView; get onDidSashChange(): Event { - return this.panelview.onDidSashChange; + return assertIsDefined(this.panelview).onDidSashChange; } protected get panels(): ViewletPanel[] { @@ -267,7 +282,7 @@ export class PanelViewlet extends Viewlet { event.stopPropagation(); event.preventDefault(); - let anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; + let anchor: { x: number, y: number; } = { x: event.posx, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, getActions: () => this.getContextMenuActions() @@ -325,7 +340,9 @@ export class PanelViewlet extends Viewlet { } layout(dimension: Dimension): void { - this.panelview.layout(dimension.height, dimension.width); + if (this.panelview) { + this.panelview.layout(dimension.height, dimension.width); + } } getOptimalWidth(): number { @@ -335,7 +352,7 @@ export class PanelViewlet extends Viewlet { return Math.max(...sizes); } - addPanels(panels: { panel: ViewletPanel, size: number, index?: number }[]): void { + addPanels(panels: { panel: ViewletPanel, size: number, index?: number; }[]): void { const wasSingleView = this.isSingleView(); for (const { panel, size, index } of panels) { @@ -371,7 +388,7 @@ export class PanelViewlet extends Viewlet { const panelItem: IViewletPanelItem = { panel, disposable }; this.panelItems.splice(index, 0, panelItem); - this.panelview.addPanel(panel, size, index); + assertIsDefined(this.panelview).addPanel(panel, size, index); } removePanels(panels: ViewletPanel[]): void { @@ -396,7 +413,7 @@ export class PanelViewlet extends Viewlet { this.lastFocusedPanel = undefined; } - this.panelview.removePanel(panel); + assertIsDefined(this.panelview).removePanel(panel); const [panelItem] = this.panelItems.splice(index, 1); panelItem.disposable.dispose(); @@ -417,15 +434,15 @@ export class PanelViewlet extends Viewlet { const [panelItem] = this.panelItems.splice(fromIndex, 1); this.panelItems.splice(toIndex, 0, panelItem); - this.panelview.movePanel(from, to); + assertIsDefined(this.panelview).movePanel(from, to); } resizePanel(panel: ViewletPanel, size: number): void { - this.panelview.resizePanel(panel, size); + assertIsDefined(this.panelview).resizePanel(panel, size); } getPanelSize(panel: ViewletPanel): number { - return this.panelview.getPanelSize(panel); + return assertIsDefined(this.panelview).getPanelSize(panel); } protected updateViewHeaders(): void { @@ -444,6 +461,8 @@ export class PanelViewlet extends Viewlet { dispose(): void { super.dispose(); this.panelItems.forEach(i => i.disposable.dispose()); - this.panelview.dispose(); + if (this.panelview) { + this.panelview.dispose(); + } } } diff --git a/src/vs/workbench/browser/parts/views/views.ts b/src/vs/workbench/browser/parts/views/views.ts index 87c08909cff..9a0a307dd5c 100644 --- a/src/vs/workbench/browser/parts/views/views.ts +++ b/src/vs/workbench/browser/parts/views/views.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/views'; -import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IViewsService, IViewsViewlet, ViewContainer, IViewDescriptor, IViewContainersRegistry, Extensions as ViewExtensions, IView, IViewDescriptorCollection, IViewsRegistry } from 'vs/workbench/common/views'; import { Registry } from 'vs/platform/registry/common/platform'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; @@ -22,14 +22,14 @@ import { IFileIconTheme, IWorkbenchThemeService } from 'vs/workbench/services/th import { toggleClass, addClass } from 'vs/base/browser/dom'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -function filterViewRegisterEvent(container: ViewContainer, event: Event<{ viewContainer: ViewContainer, views: IViewDescriptor[] }>): Event { +function filterViewRegisterEvent(container: ViewContainer, event: Event<{ viewContainer: ViewContainer, views: IViewDescriptor[]; }>): Event { return Event.chain(event) .map(({ views, viewContainer }) => viewContainer === container ? views : []) .filter(views => views.length > 0) .event; } -function filterViewMoveEvent(container: ViewContainer, event: Event<{ from: ViewContainer, to: ViewContainer, views: IViewDescriptor[] }>): Event<{ added?: IViewDescriptor[], removed?: IViewDescriptor[] }> { +function filterViewMoveEvent(container: ViewContainer, event: Event<{ from: ViewContainer, to: ViewContainer, views: IViewDescriptor[]; }>): Event<{ added?: IViewDescriptor[], removed?: IViewDescriptor[]; }> { return Event.chain(event) .map(({ views, from, to }) => from === container ? { removed: views } : to === container ? { added: views } : {}) .filter(({ added, removed }) => isNonEmptyArray(added) || isNonEmptyArray(removed)) @@ -78,8 +78,8 @@ class ViewDescriptorCollection extends Disposable implements IViewDescriptorColl private contextKeys = new CounterSet(); private items: IViewItem[] = []; - private _onDidChange: Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[] }> = this._register(new Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[] }>()); - readonly onDidChangeActiveViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[] }> = this._onDidChange.event; + private _onDidChange: Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }> = this._register(new Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }>()); + readonly onDidChangeActiveViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[]; }> = this._onDidChange.event; get activeViewDescriptors(): IViewDescriptor[] { return this.items @@ -356,7 +356,7 @@ export class ContributableViewsModel extends Disposable { return viewDescriptor.workspace ? !!viewState.visibleWorkspace : !!viewState.visibleGlobal; } - private find(id: string): { index: number, visibleIndex: number, viewDescriptor: IViewDescriptor, state: IViewState } { + private find(id: string): { index: number, visibleIndex: number, viewDescriptor: IViewDescriptor, state: IViewState; } { for (let i = 0, visibleIndex = 0; i < this.viewDescriptors.length; i++) { const viewDescriptor = this.viewDescriptors[i]; const state = this.viewStates.get(viewDescriptor.id); @@ -436,8 +436,8 @@ export class ContributableViewsModel extends Disposable { (a, b) => a.id === b.id ? 0 : a.id < b.id ? -1 : 1 ).reverse(); - const toRemove: { index: number, viewDescriptor: IViewDescriptor }[] = []; - const toAdd: { index: number, viewDescriptor: IViewDescriptor, size?: number, collapsed: boolean }[] = []; + const toRemove: { index: number, viewDescriptor: IViewDescriptor; }[] = []; + const toAdd: { index: number, viewDescriptor: IViewDescriptor, size?: number, collapsed: boolean; }[] = []; for (const splice of splices) { const startViewDescriptor = this.viewDescriptors[splice.start]; @@ -521,7 +521,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { } private saveWorkspaceViewsStates(): void { - const storedViewsStates: { [id: string]: IStoredWorkspaceViewState } = JSON.parse(this.storageService.get(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}')); + const storedViewsStates: { [id: string]: IStoredWorkspaceViewState; } = JSON.parse(this.storageService.get(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}')); for (const viewDescriptor of this.viewDescriptors) { const viewState = this.viewStates.get(viewDescriptor.id); if (viewState) { @@ -557,7 +557,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { private static loadViewsStates(workspaceViewsStateStorageId: string, globalViewsStateStorageId: string, storageService: IStorageService): Map { const viewStates = new Map(); - const workspaceViewsStates = <{ [id: string]: IStoredWorkspaceViewState }>JSON.parse(storageService.get(workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}')); + const workspaceViewsStates = <{ [id: string]: IStoredWorkspaceViewState; }>JSON.parse(storageService.get(workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}')); for (const id of Object.keys(workspaceViewsStates)) { const workspaceViewState = workspaceViewsStates[id]; viewStates.set(id, { @@ -636,7 +636,7 @@ export class ViewsService extends Disposable implements IViewsService { _serviceBrand: undefined; - private readonly viewDescriptorCollections: Map; + private readonly viewDescriptorCollections: Map; private readonly viewDisposable: Map; private readonly activeViewContextKeys: Map>; @@ -646,7 +646,7 @@ export class ViewsService extends Disposable implements IViewsService { ) { super(); - this.viewDescriptorCollections = new Map(); + this.viewDescriptorCollections = new Map(); this.viewDisposable = new Map(); this.activeViewContextKeys = new Map>(); @@ -692,13 +692,13 @@ export class ViewsService extends Disposable implements IViewsService { } private onDidRegisterViewContainer(viewContainer: ViewContainer): void { - const viewDescriptorCollection = new ViewDescriptorCollection(viewContainer, this.contextKeyService); - const disposables: IDisposable[] = [viewDescriptorCollection]; + const disposables = new DisposableStore(); + const viewDescriptorCollection = disposables.add(new ViewDescriptorCollection(viewContainer, this.contextKeyService)); this.onDidChangeActiveViews({ added: viewDescriptorCollection.activeViewDescriptors, removed: [] }); viewDescriptorCollection.onDidChangeActiveViews(changed => this.onDidChangeActiveViews(changed), this, disposables); - this.viewDescriptorCollections.set(viewContainer, { viewDescriptorCollection, disposable: toDisposable(() => dispose(disposables)) }); + this.viewDescriptorCollections.set(viewContainer, { viewDescriptorCollection, disposable: disposables }); } private onDidDeregisterViewContainer(viewContainer: ViewContainer): void { @@ -709,7 +709,7 @@ export class ViewsService extends Disposable implements IViewsService { } } - private onDidChangeActiveViews({ added, removed }: { added: IViewDescriptor[], removed: IViewDescriptor[] }): void { + private onDidChangeActiveViews({ added, removed }: { added: IViewDescriptor[], removed: IViewDescriptor[]; }): void { added.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(true)); removed.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(false)); } @@ -717,7 +717,7 @@ export class ViewsService extends Disposable implements IViewsService { private onDidRegisterViews(container: ViewContainer, views: IViewDescriptor[]): void { const viewlet = this.viewletService.getViewlet(container.id); for (const viewDescriptor of views) { - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); const command: ICommandAction = { id: viewDescriptor.focusCommand ? viewDescriptor.focusCommand.id : `${viewDescriptor.id}.focus`, title: { original: `Focus on ${viewDescriptor.name} View`, value: localize('focus view', "Focus on {0} View", viewDescriptor.name) }, @@ -725,9 +725,9 @@ export class ViewsService extends Disposable implements IViewsService { }; const when = ContextKeyExpr.has(`${viewDescriptor.id}.active`); - disposables.push(CommandsRegistry.registerCommand(command.id, () => this.openView(viewDescriptor.id, true))); + disposables.add(CommandsRegistry.registerCommand(command.id, () => this.openView(viewDescriptor.id, true))); - disposables.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + disposables.add(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command, when })); @@ -745,7 +745,7 @@ export class ViewsService extends Disposable implements IViewsService { }); } - this.viewDisposable.set(viewDescriptor, toDisposable(() => dispose(disposables))); + this.viewDisposable.set(viewDescriptor, disposables); } } diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 76d8302ca88..239514051a2 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -64,6 +64,9 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView super(id, { showHeaderInTitleWhenSingleView, dnd: new DefaultPanelDndController() }, configurationService, layoutService, contextMenuService, telemetryService, themeService, storageService); const container = Registry.as(ViewContainerExtensions.ViewContainersRegistry).get(id); + if (!container) { + throw new Error('Could not find container'); + } this.viewsModel = this._register(this.instantiationService.createInstance(PersistentContributableViewsModel, container, viewletStateStorageId)); this.viewletState = this.getMemento(StorageScope.WORKSPACE); diff --git a/src/vs/workbench/browser/quickopen.ts b/src/vs/workbench/browser/quickopen.ts index 230a461907f..0c4b67f1f29 100644 --- a/src/vs/workbench/browser/quickopen.ts +++ b/src/vs/workbench/browser/quickopen.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import * as objects from 'vs/base/common/objects'; -import * as arrays from 'vs/base/common/arrays'; -import * as strings from 'vs/base/common/strings'; -import * as types from 'vs/base/common/types'; +import { localize } from 'vs/nls'; +import { mixin, assign } from 'vs/base/common/objects'; +import { first } from 'vs/base/common/arrays'; +import { startsWith } from 'vs/base/common/strings'; +import { isString, assertIsDefined, withNullAsUndefined } from 'vs/base/common/types'; import { Registry } from 'vs/platform/registry/common/platform'; import { Action } from 'vs/base/common/actions'; import { Mode, IEntryRunContext, IAutoFocus, IModel, IQuickNavigateConfiguration } from 'vs/base/parts/quickopen/common/quickOpen'; @@ -111,9 +111,9 @@ export class QuickOpenHandler { */ getEmptyLabel(searchString: string): string { if (searchString.length > 0) { - return nls.localize('noResultsMatching', "No results matching"); + return localize('noResultsMatching', "No results matching"); } - return nls.localize('noResultsFound2', "No results found"); + return localize('noResultsFound2', "No results found"); } } @@ -128,9 +128,9 @@ export interface QuickOpenHandlerHelpEntry { */ export class QuickOpenHandlerDescriptor { prefix: string; - description: string; + description?: string; contextKey?: string; - helpEntries: QuickOpenHandlerHelpEntry[]; + helpEntries?: QuickOpenHandlerHelpEntry[]; instantProgress: boolean; private id: string; @@ -145,7 +145,7 @@ export class QuickOpenHandlerDescriptor { this.contextKey = contextKey; this.instantProgress = instantProgress; - if (types.isString(param)) { + if (isString(param)) { this.description = param; } else { this.helpEntries = param; @@ -195,7 +195,7 @@ export interface IQuickOpenRegistry { class QuickOpenRegistry implements IQuickOpenRegistry { private handlers: QuickOpenHandlerDescriptor[] = []; - private defaultHandler: QuickOpenHandlerDescriptor; + private defaultHandler: QuickOpenHandlerDescriptor | undefined; registerQuickOpenHandler(descriptor: QuickOpenHandlerDescriptor): void { this.handlers.push(descriptor); @@ -214,11 +214,11 @@ class QuickOpenRegistry implements IQuickOpenRegistry { } getQuickOpenHandler(text: string): QuickOpenHandlerDescriptor | null { - return text ? (arrays.first(this.handlers, h => strings.startsWith(text, h.prefix)) || null) : null; + return text ? (first(this.handlers, h => startsWith(text, h.prefix)) || null) : null; } getDefaultQuickOpenHandler(): QuickOpenHandlerDescriptor { - return this.defaultHandler; + return assertIsDefined(this.defaultHandler); } } @@ -275,17 +275,17 @@ export class EditorQuickOpenEntry extends QuickOpenEntry implements IEditorQuick if (input instanceof EditorInput) { let opts = this.getOptions(); if (opts) { - opts = objects.mixin(opts, openOptions, true); + opts = mixin(opts, openOptions, true); } else if (openOptions) { opts = EditorOptions.create(openOptions); } - this.editorService.openEditor(input, types.withNullAsUndefined(opts), sideBySide ? SIDE_GROUP : ACTIVE_GROUP); + this.editorService.openEditor(input, withNullAsUndefined(opts), sideBySide ? SIDE_GROUP : ACTIVE_GROUP); } else { const resourceInput = input; if (openOptions) { - resourceInput.options = objects.assign(resourceInput.options || Object.create(null), openOptions); + resourceInput.options = assign(resourceInput.options || Object.create(null), openOptions); } this.editorService.openEditor(resourceInput, sideBySide ? SIDE_GROUP : ACTIVE_GROUP); diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index deaaf4953ed..23b39b5f4f3 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -7,7 +7,10 @@ import 'vs/css!./media/style'; import { registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; import { iconForeground, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; -import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; +import { WORKBENCH_BACKGROUND, TITLE_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; +import { isWeb } from 'vs/base/common/platform'; +import { createMetaElement } from 'vs/base/browser/dom'; +import { isSafari } from 'vs/base/browser/browser'; registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { @@ -32,8 +35,16 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { // Input placeholder const placeholderForeground = theme.getColor(inputPlaceholderForeground); if (placeholderForeground) { - collector.addRule(`.monaco-workbench input::-webkit-input-placeholder { color: ${placeholderForeground}; }`); - collector.addRule(`.monaco-workbench textarea::-webkit-input-placeholder { color: ${placeholderForeground}; }`); + collector.addRule(` + .monaco-workbench input::placeholder { color: ${placeholderForeground}; } + .monaco-workbench input::-webkit-input-placeholder { color: ${placeholderForeground}; } + .monaco-workbench input::-moz-placeholder { color: ${placeholderForeground}; } + `); + collector.addRule(` + .monaco-workbench textarea::placeholder { color: ${placeholderForeground}; } + .monaco-workbench textarea::-webkit-input-placeholder { color: ${placeholderForeground}; } + .monaco-workbench textarea::-moz-placeholder { color: ${placeholderForeground}; } + `); } // List highlight @@ -143,4 +154,31 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { `); } + // Update based on selected theme + if (isWeb) { + const titleBackground = theme.getColor(TITLE_BAR_ACTIVE_BACKGROUND); + if (titleBackground) { + const metaElementId = 'monaco-workbench-meta-theme-color'; + let metaElement = document.getElementById(metaElementId) as HTMLMetaElement | null; + if (!metaElement) { + metaElement = createMetaElement(); + metaElement.name = 'theme-color'; + metaElement.id = metaElementId; + } + + metaElement.content = titleBackground.toString(); + } + } + + // We disable user select on the root element, however on Safari this seems + // to prevent any text selection in the monaco editor. As a workaround we + // allow to select text in monaco editor instances. + if (isSafari) { + collector.addRule(` + .monaco-workbench .monaco-editor .view-lines { + user-select: text; + -webkit-user-select: text; + } + `); + } }); diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 368e56b41c7..6ddf85eb74b 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -21,6 +21,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IStorageService } from 'vs/platform/storage/common/storage'; import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { AbstractTree } from 'vs/base/browser/ui/tree/abstractTree'; +import { assertIsDefined } from 'vs/base/common/types'; export abstract class Viewlet extends Composite implements IViewlet { @@ -34,8 +35,8 @@ export abstract class Viewlet extends Composite implements IViewlet { super(id, telemetryService, themeService, storageService); } - getOptimalWidth(): number | null { - return null; + getOptimalWidth(): number | undefined { + return undefined; } getContextMenuActions(): IAction[] { @@ -76,7 +77,7 @@ export const Extensions = { }; export class ViewletRegistry extends CompositeRegistry { - private defaultViewletId!: string; + private defaultViewletId: string | undefined; /** * Registers a viewlet to the platform. @@ -120,7 +121,7 @@ export class ViewletRegistry extends CompositeRegistry { * Gets the id of the viewlet that should open on startup by default. */ getDefaultViewletId(): string { - return this.defaultViewletId; + return assertIsDefined(this.defaultViewletId); } } @@ -166,8 +167,9 @@ export class ShowViewletAction extends Action { private sidebarHasFocus(): boolean { const activeViewlet = this.viewletService.getActiveViewlet(); const activeElement = document.activeElement; + const sidebarPart = this.layoutService.getContainer(Parts.SIDEBAR_PART); - return !!(activeViewlet && activeElement && DOM.isAncestor(activeElement, this.layoutService.getContainer(Parts.SIDEBAR_PART))); + return !!(activeViewlet && activeElement && sidebarPart && DOM.isAncestor(activeElement, sidebarPart)); } } diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 59a528f66d8..d5dc15571fd 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { mark } from 'vs/base/common/performance'; -import { domContentLoaded, addDisposableListener, EventType, addClass } from 'vs/base/browser/dom'; +import { domContentLoaded, addDisposableListener, EventType, addClass, EventHelper } from 'vs/base/browser/dom'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILogService, ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log'; import { Disposable } from 'vs/base/common/lifecycle'; import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { Workbench } from 'vs/workbench/browser/workbench'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; +import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; @@ -25,6 +25,7 @@ import { Schemas } from 'vs/base/common/network'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { onUnexpectedError } from 'vs/base/common/errors'; +import * as browser from 'vs/base/browser/browser'; import { URI } from 'vs/base/common/uri'; import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; @@ -32,7 +33,7 @@ import { ConfigurationCache } from 'vs/workbench/services/configuration/browser/ import { ISignService } from 'vs/platform/sign/common/sign'; import { SignService } from 'vs/platform/sign/browser/signService'; import { hash } from 'vs/base/common/hash'; -import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api'; +import { IWorkbenchConstructionOptions, IWorkspace } from 'vs/workbench/workbench.web.api'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; import { BACKUPS } from 'vs/platform/environment/common/environment'; import { joinPath } from 'vs/base/common/resources'; @@ -46,8 +47,10 @@ import { FileLogService } from 'vs/platform/log/common/fileLogService'; import { toLocalISOString } from 'vs/base/common/date'; import { IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedDBLogProvider'; import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider'; +import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows'; +import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; -class CodeRendererMain extends Disposable { +class BrowserMain extends Disposable { constructor( private readonly domElement: HTMLElement, @@ -72,26 +75,8 @@ class CodeRendererMain extends Disposable { services.logService ); - // Layout - this._register(addDisposableListener(window, EventType.RESIZE, () => workbench.layout())); - - // Prevent the back/forward gestures in macOS - this._register(addDisposableListener(this.domElement, EventType.WHEEL, (e) => { - e.preventDefault(); - }, { passive: false })); - - // Workbench Lifecycle - this._register(workbench.onBeforeShutdown(event => { - if (services.storageService.hasPendingUpdate) { - console.warn('Unload prevented: pending storage update'); - event.veto(true); // prevent data loss from pending storage update - } - })); - this._register(workbench.onWillShutdown(() => { - services.storageService.close(); - this.saveBaseTheme(); - })); - this._register(workbench.onShutdown(() => this.dispose())); + // Listeners + this.registerListeners(workbench, services.storageService); // Driver if (this.configuration.driver) { @@ -102,8 +87,46 @@ class CodeRendererMain extends Disposable { workbench.startup(); } + private registerListeners(workbench: Workbench, storageService: BrowserStorageService): void { + + // Layout + this._register(addDisposableListener(window, EventType.RESIZE, () => workbench.layout())); + + // Prevent the back/forward gestures in macOS + this._register(addDisposableListener(this.domElement, EventType.WHEEL, (e) => { + e.preventDefault(); + }, { passive: false })); + + // Prevent native context menus in web + this._register(addDisposableListener(this.domElement, EventType.CONTEXT_MENU, (e) => EventHelper.stop(e, true))); + + // Workbench Lifecycle + this._register(workbench.onBeforeShutdown(event => { + if (storageService.hasPendingUpdate) { + console.warn('Unload prevented: pending storage update'); + event.veto(true); // prevent data loss from pending storage update + } + })); + this._register(workbench.onWillShutdown(() => { + storageService.close(); + this.saveBaseTheme(); + })); + this._register(workbench.onShutdown(() => this.dispose())); + + // Fullscreen + [EventType.FULLSCREEN_CHANGE, EventType.WK_FULLSCREEN_CHANGE].forEach(event => { + this._register(addDisposableListener(document, event, () => { + if (document.fullscreenElement || (document).webkitFullscreenElement || (document).webkitIsFullScreen) { + browser.setFullscreen(true); + } else { + browser.setFullscreen(false); + } + })); + }); + } + private restoreBaseTheme(): void { - addClass(this.domElement, window.localStorage.getItem('baseTheme') || getThemeTypeSelector(DARK)); + addClass(this.domElement, window.localStorage.getItem('vscode.baseTheme') || getThemeTypeSelector(DARK)); } private saveBaseTheme(): void { @@ -111,7 +134,7 @@ class CodeRendererMain extends Disposable { const baseThemes = [DARK, LIGHT, HIGH_CONTRAST].map(baseTheme => getThemeTypeSelector(baseTheme)); for (const baseTheme of baseThemes) { if (classes.indexOf(baseTheme) >= 0) { - window.localStorage.setItem('baseTheme', baseTheme); + window.localStorage.setItem('vscode.baseTheme', baseTheme); break; } } @@ -139,10 +162,7 @@ class CodeRendererMain extends Disposable { // Product const productService = { _serviceBrand: undefined, - ...{ - ...product, // dev or built time config - ...{ urlProtocol: '' } // web related overrides from us - } + ...product }; serviceCollection.set(IProductService, productService); @@ -191,17 +211,21 @@ class CodeRendererMain extends Disposable { private registerFileSystemProviders(environmentService: IWorkbenchEnvironmentService, fileService: IFileService, remoteAgentService: IRemoteAgentService, logService: BufferLogService, logsPath: URI): void { // Logger - const indexedDBLogProvider = new IndexedDBLogProvider(logsPath.scheme); (async () => { - try { - await indexedDBLogProvider.database; - - fileService.registerProvider(logsPath.scheme, indexedDBLogProvider); - } catch (error) { - (logService).info('Error while creating indexedDB log provider. Falling back to in-memory log provider.'); - (logService).error(error); - + if (browser.isEdge) { fileService.registerProvider(logsPath.scheme, new InMemoryLogProvider(logsPath.scheme)); + } else { + try { + const indexedDBLogProvider = new IndexedDBLogProvider(logsPath.scheme); + await indexedDBLogProvider.database; + + fileService.registerProvider(logsPath.scheme, indexedDBLogProvider); + } catch (error) { + logService.info('Error while creating indexedDB log provider. Falling back to in-memory log provider.'); + logService.error(error); + + fileService.registerProvider(logsPath.scheme, new InMemoryLogProvider(logsPath.scheme)); + } } const consoleLogService = new ConsoleLogService(logService.getLevel()); @@ -214,7 +238,7 @@ class CodeRendererMain extends Disposable { // Remote file system const channel = connection.getChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME); - const remoteFileSystemProvider = this._register(new RemoteExtensionsFileSystemProvider(channel, remoteAgentService.getEnvironment())); + const remoteFileSystemProvider = this._register(new RemoteFileSystemProvider(channel, remoteAgentService.getEnvironment())); fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider); if (!this.configuration.userDataProvider) { @@ -263,21 +287,25 @@ class CodeRendererMain extends Disposable { } private resolveWorkspaceInitializationPayload(): IWorkspaceInitializationPayload { + let workspace: IWorkspace | undefined = undefined; + if (this.configuration.workspaceProvider) { + workspace = this.configuration.workspaceProvider.workspace; + } // Multi-root workspace - if (this.configuration.workspaceUri) { - return { id: hash(this.configuration.workspaceUri.toString()).toString(16), configPath: this.configuration.workspaceUri }; + if (workspace && isWorkspaceToOpen(workspace)) { + return getWorkspaceIdentifier(workspace.workspaceUri); } // Single-folder workspace - if (this.configuration.folderUri) { - return { id: hash(this.configuration.folderUri.toString()).toString(16), folder: this.configuration.folderUri }; + if (workspace && isFolderToOpen(workspace)) { + return { id: hash(workspace.folderUri.toString()).toString(16), folder: workspace.folderUri }; } return { id: 'empty-window' }; } - private getRemoteUserDataUri(): URI | null { + private getRemoteUserDataUri(): URI | undefined { const element = document.getElementById('vscode-remote-user-data-uri'); if (element) { const remoteUserDataPath = element.getAttribute('data-settings'); @@ -286,12 +314,12 @@ class CodeRendererMain extends Disposable { } } - return null; + return undefined; } } export function main(domElement: HTMLElement, options: IWorkbenchConstructionOptions): Promise { - const renderer = new CodeRendererMain(domElement, options); + const renderer = new BrowserMain(domElement, options); return renderer.open(); } diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index b6124cc5d16..2b634951bf2 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -60,6 +60,16 @@ import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common ], 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the sizing of editor tabs.") }, + 'workbench.editor.splitSizing': { + 'type': 'string', + 'enum': ['distribute', 'split'], + 'default': 'distribute', + 'enumDescriptions': [ + nls.localize('workbench.editor.splitSizingDistribute', "Splits all the editor groups to equal parts."), + nls.localize('workbench.editor.splitSizingSplit', "Splits the active editor group to equal parts.") + ], + 'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'splitSizing' }, "Controls the sizing of editor groups when splitting them.") + }, 'workbench.editor.focusRecentEditorAfterClose': { 'type': 'boolean', 'description': nls.localize('focusRecentEditorAfterClose', "Controls whether tabs are closed in most recently used order or from left to right."), @@ -77,7 +87,7 @@ import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common }, 'workbench.editor.enablePreviewFromQuickOpen': { 'type': 'boolean', - 'description': nls.localize('enablePreviewFromQuickOpen', "Controls whether opened editors from Quick Open show as preview. Preview editors are reused until they are pinned (e.g. via double click or editing)."), + 'description': nls.localize('enablePreviewFromQuickOpen', "Controls whether editors opened from Quick Open show as preview. Preview editors are reused until they are pinned (e.g. via double click or editing)."), 'default': true }, 'workbench.editor.closeOnFileDelete': { @@ -233,11 +243,6 @@ import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common 'description': nls.localize('workbench.enableExperiments', "Fetches experiments to run from a Microsoft online service."), 'default': true, 'tags': ['usesOnlineServices'] - }, - 'workbench.octiconsUpdate.enabled': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('workbench.octiconsUpdate.enabled', "Controls the visibility of the new Octicons style in the workbench.") } } }); @@ -286,14 +291,15 @@ import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common }, 'window.menuBarVisibility': { 'type': 'string', - 'enum': ['default', 'visible', 'toggle', 'hidden'], + 'enum': ['default', 'visible', 'toggle', 'hidden', 'compact'], '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.") + nls.localize('window.menuBarVisibility.hidden', "Menu is always hidden."), + nls.localize('window.menuBarVisibility.compact', "Menu is displayed as a compact button in the sidebar. This value is ignored when 'window.titleBarStyle' is 'native'.") ], - 'default': 'default', + 'default': isWeb ? 'compact' : '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 || isWeb @@ -368,6 +374,11 @@ import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common 'type': 'boolean', 'default': false, 'description': nls.localize('zenMode.restore', "Controls whether a window should restore to zen mode if it was exited in zen mode.") + }, + 'zenMode.silentNotifications': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('zenMode.silentNotifications', "Controls whether notifications are shown while in zen mode. If true, only error notifications will pop out.") } } }); diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index 917a1ec5d0f..d7e84dc3934 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -19,7 +19,7 @@ import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/ import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions'; import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions'; import { Position, Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; -import { IStorageService, WillSaveStateReason, StorageScope, IWillSaveStateEvent } from 'vs/platform/storage/common/storage'; +import { IStorageService, WillSaveStateReason, StorageScope } from 'vs/platform/storage/common/storage'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; @@ -157,7 +157,7 @@ export class Workbench extends Layout { this.renderWorkbench(instantiationService, accessor.get(INotificationService) as NotificationService, storageService, configurationService); // Workbench Layout - this.createWorkbenchLayout(instantiationService); + this.createWorkbenchLayout(); // Layout this.layout(); @@ -227,6 +227,20 @@ export class Workbench extends Layout { configurationService: IConfigurationService ): void { + // Configuration changes + this._register(configurationService.onDidChangeConfiguration(() => this.setFontAliasing(configurationService))); + + // Font Info + if (isNative) { + this._register(storageService.onWillSaveState(e => { + if (e.reason === WillSaveStateReason.SHUTDOWN) { + this.storeFontInfo(storageService); + } + })); + } else { + this._register(lifecycleService.onWillShutdown(() => this.storeFontInfo(storageService))); + } + // Lifecycle this._register(lifecycleService.onBeforeShutdown(event => this._onBeforeShutdown.fire(event))); this._register(lifecycleService.onWillShutdown(event => this._onWillShutdown.fire(event))); @@ -234,12 +248,6 @@ export class Workbench extends Layout { this._onShutdown.fire(); this.dispose(); })); - - // Configuration changes - this._register(configurationService.onDidChangeConfiguration(() => this.setFontAliasing(configurationService))); - - // Storage - this._register(storageService.onWillSaveState(e => this.storeFontInfo(e, storageService))); } private fontAliasing: 'default' | 'antialiased' | 'none' | 'auto' | undefined; @@ -264,7 +272,7 @@ export class Workbench extends Layout { private restoreFontInfo(storageService: IStorageService, configurationService: IConfigurationService): void { // Restore (native: use storage service, web: use browser specific local storage) - const storedFontInfoRaw = isNative ? storageService.get('editorFontInfo', StorageScope.GLOBAL) : window.localStorage.getItem('editorFontInfo'); + const storedFontInfoRaw = isNative ? storageService.get('editorFontInfo', StorageScope.GLOBAL) : window.localStorage.getItem('vscode.editorFontInfo'); if (storedFontInfoRaw) { try { const storedFontInfo = JSON.parse(storedFontInfoRaw); @@ -279,13 +287,19 @@ export class Workbench extends Layout { readFontInfo(BareFontInfo.createFromRawSettings(configurationService.getValue('editor'), getZoomLevel())); } - private storeFontInfo(e: IWillSaveStateEvent, storageService: IStorageService): void { - if (e.reason === WillSaveStateReason.SHUTDOWN) { - const serializedFontInfo = serializeFontInfo(); - if (serializedFontInfo) { - const serializedFontInfoRaw = JSON.stringify(serializedFontInfo); + private storeFontInfo(storageService: IStorageService): void { + const serializedFontInfo = serializeFontInfo(); + if (serializedFontInfo) { + const serializedFontInfoRaw = JSON.stringify(serializedFontInfo); - isNative ? storageService.store('editorFontInfo', serializedFontInfoRaw, StorageScope.GLOBAL) : window.localStorage.setItem('editorFontInfo', serializedFontInfoRaw); + // Font info is very specific to the machine the workbench runs + // on. As such, in the web, we prefer to store this info in + // local storage and not global storage because it would not make + // much sense to synchronize to other machines. + if (isNative) { + storageService.store('editorFontInfo', serializedFontInfoRaw, StorageScope.GLOBAL); + } else { + window.localStorage.setItem('vscode.editorFontInfo', serializedFontInfoRaw); } } } diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 72c8dcaecc7..46112bcce7c 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -46,10 +46,10 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR weight: weight, when: (descriptor.keybindingContext || when ? ContextKeyExpr.and(descriptor.keybindingContext, when) : null), primary: keybindings ? keybindings.primary : 0, - secondary: keybindings && keybindings.secondary, - win: keybindings && keybindings.win, - mac: keybindings && keybindings.mac, - linux: keybindings && keybindings.linux + secondary: keybindings?.secondary, + win: keybindings?.win, + mac: keybindings?.mac, + linux: keybindings?.linux }); // menu item @@ -112,7 +112,7 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR // otherwise run and dispose try { - const from = args && args.from || 'keybinding'; + const from = args?.from || 'keybinding'; await actionInstance.run(undefined, { from }); } finally { actionInstance.dispose(); diff --git a/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts index 0f5d7b038ca..e2a4ca4d321 100644 --- a/src/vs/workbench/common/contributions.ts +++ b/src/vs/workbench/common/contributions.ts @@ -63,11 +63,11 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry } start(accessor: ServicesAccessor): void { - this.instantiationService = accessor.get(IInstantiationService); - this.lifecycleService = accessor.get(ILifecycleService); + const instantiationService = this.instantiationService = accessor.get(IInstantiationService); + const lifecycleService = this.lifecycleService = accessor.get(ILifecycleService); [LifecyclePhase.Starting, LifecyclePhase.Ready, LifecyclePhase.Restored, LifecyclePhase.Eventually].forEach(phase => { - this.instantiateByPhase(this.instantiationService!, this.lifecycleService!, phase); + this.instantiateByPhase(instantiationService, lifecycleService, phase); }); } @@ -91,7 +91,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry if (phase !== LifecyclePhase.Eventually) { // instantiate everything synchronously and blocking for (const ctor of toBeInstantiated) { - instantiationService.createInstance(ctor); + this.safeCreateInstance(instantiationService, ctor); // catch error so that other contributions are still considered } } else { // for the Eventually-phase we instantiate contributions @@ -102,7 +102,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry let instantiateSome = (idle: IdleDeadline) => { while (i < toBeInstantiated.length) { const ctor = toBeInstantiated[i++]; - instantiationService.createInstance(ctor); + this.safeCreateInstance(instantiationService, ctor); // catch error so that other contributions are still considered if (idle.timeRemaining() < 1) { // time is up -> reschedule runWhenIdle(instantiateSome, forcedTimeout); @@ -114,6 +114,14 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry } } } + + private safeCreateInstance(instantiationService: IInstantiationService, ctor: IConstructorSignature0): void { + try { + instantiationService.createInstance(ctor); + } catch (error) { + console.error(`Unable to instantiate workbench contribution ${(ctor as any).name}.`, error); + } + } } Registry.add(Extensions.Workbench, new WorkbenchContributionsRegistry()); diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index c30bfed1f19..c25eb41dc75 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -5,11 +5,11 @@ import { Event, Emitter } from 'vs/base/common/event'; import { assign } from 'vs/base/common/objects'; -import { isUndefinedOrNull } from 'vs/base/common/types'; +import { isUndefinedOrNull, withNullAsUndefined, assertIsDefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon'; -import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, IResourceInput, EditorActivation } from 'vs/platform/editor/common/editor'; +import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, IResourceInput, EditorActivation, EditorOpenContext } from 'vs/platform/editor/common/editor'; import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -38,6 +38,7 @@ export const SingleEditorGroupsContext = MultipleEditorGroupsContext.toNegated() export const InEditorZenModeContext = new RawContextKey('inZenMode', false); export const IsCenteredLayoutContext = new RawContextKey('isCenteredLayout', false); export const SplitEditorsVertically = new RawContextKey('splitEditorsVertically', false); +export const EditorAreaVisibleContext = new RawContextKey('editorAreaVisible', true); /** * Text diff editor id. @@ -117,7 +118,7 @@ export interface ITextEditor extends IEditor { /** * Returns the underlying text editor widget of this editor. */ - getControl(): ICodeEditor; + getControl(): ICodeEditor | undefined; } export interface ITextDiffEditor extends IEditor { @@ -125,7 +126,7 @@ export interface ITextDiffEditor extends IEditor { /** * Returns the underlying text editor widget of this editor. */ - getControl(): IDiffEditor; + getControl(): IDiffEditor | undefined; } export interface ITextSideBySideEditor extends IEditor { @@ -499,7 +500,7 @@ export interface IEncodingSupport { /** * Gets the encoding of the input if known. */ - getEncoding(): string; + getEncoding(): string | undefined; /** * Sets the encoding for the input for saving. @@ -775,6 +776,18 @@ export class EditorOptions implements IEditorOptions { */ ignoreOverrides: boolean | undefined; + /** + * A optional hint to signal in which context the editor opens. + * + * If configured to be `EditorOpenContext.USER`, this hint can be + * used in various places to control the experience. For example, + * if the editor to open fails with an error, a notification could + * inform about this in a modal dialog. If the editor opened through + * some background task, the notification would show in the background, + * not as a modal dialog. + */ + context: EditorOpenContext | undefined; + /** * Overwrites option values from the provided bag. */ @@ -819,6 +832,10 @@ export class EditorOptions implements IEditorOptions { this.ignoreOverrides = options.ignoreOverrides; } + if (typeof options.context === 'number') { + this.context = options.context; + } + return this; } } @@ -827,13 +844,13 @@ export class EditorOptions implements IEditorOptions { * Base Text Editor Options. */ export class TextEditorOptions extends EditorOptions { - private startLineNumber: number; - private startColumn: number; - private endLineNumber: number; - private endColumn: number; + private startLineNumber: number | undefined; + private startColumn: number | undefined; + private endLineNumber: number | undefined; + private endColumn: number | undefined; - private revealInCenterIfOutsideViewport: boolean; - private editorViewState: IEditorViewState | null; + private revealInCenterIfOutsideViewport: boolean | undefined; + private editorViewState: IEditorViewState | undefined; static from(input?: IBaseResourceInput): TextEditorOptions | undefined { if (!input || !input.options) { @@ -901,7 +918,7 @@ export class TextEditorOptions extends EditorOptions { const options = TextEditorOptions.create(settings); // View state - options.editorViewState = editor.saveViewState(); + options.editorViewState = withNullAsUndefined(editor.saveViewState()); return options; } @@ -1025,6 +1042,7 @@ interface IEditorPartConfiguration { mouseBackForwardToNavigate?: boolean; labelFormat?: 'default' | 'short' | 'medium' | 'long'; restoreViewState?: boolean; + splitSizing?: 'split' | 'distribute'; } export interface IEditorPartOptions extends IEditorPartConfiguration { @@ -1046,7 +1064,7 @@ export function toResource(editor: IEditorInput | undefined, options?: IResource return undefined; } - if (options && options.supportSideBySide && editor instanceof SideBySideEditorInput) { + if (options?.supportSideBySide && editor instanceof SideBySideEditorInput) { editor = options.supportSideBySide === SideBySideEditor.MASTER ? editor.master : editor.details; } @@ -1084,23 +1102,23 @@ export interface IEditorMemento { } class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry { - private instantiationService: IInstantiationService; - private fileInputFactory: IFileInputFactory; + private instantiationService: IInstantiationService | undefined; + private fileInputFactory: IFileInputFactory | undefined; private readonly editorInputFactoryConstructors: Map> = new Map(); private readonly editorInputFactoryInstances: Map = new Map(); start(accessor: ServicesAccessor): void { - this.instantiationService = accessor.get(IInstantiationService); + const instantiationService = this.instantiationService = accessor.get(IInstantiationService); this.editorInputFactoryConstructors.forEach((ctor, key) => { - this.createEditorInputFactory(key, ctor); + this.createEditorInputFactory(key, ctor, instantiationService); }); this.editorInputFactoryConstructors.clear(); } - private createEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { - const instance = this.instantiationService.createInstance(ctor); + private createEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0, instantiationService: IInstantiationService): void { + const instance = instantiationService.createInstance(ctor); this.editorInputFactoryInstances.set(editorInputId, instance); } @@ -1109,14 +1127,14 @@ class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry { } getFileInputFactory(): IFileInputFactory { - return this.fileInputFactory; + return assertIsDefined(this.fileInputFactory); } registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { if (!this.instantiationService) { this.editorInputFactoryConstructors.set(editorInputId, ctor); } else { - this.createEditorInputFactory(editorInputId, ctor); + this.createEditorInputFactory(editorInputId, ctor, this.instantiationService); } } diff --git a/src/vs/workbench/common/editor/binaryEditorModel.ts b/src/vs/workbench/common/editor/binaryEditorModel.ts index 48c1cf5582c..5f94a8c947a 100644 --- a/src/vs/workbench/common/editor/binaryEditorModel.ts +++ b/src/vs/workbench/common/editor/binaryEditorModel.ts @@ -7,25 +7,27 @@ import { EditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { Schemas } from 'vs/base/common/network'; -import { DataUri } from 'vs/base/common/resources'; +import { DataUri, basename } from 'vs/base/common/resources'; +import { MIME_BINARY } from 'vs/base/common/mime'; /** * An editor model that just represents a resource that can be loaded. */ export class BinaryEditorModel extends EditorModel { - private size: number; + private size: number | undefined; private etag: string | undefined; private readonly mime: string; constructor( private readonly resource: URI, - private readonly name: string, + private readonly name: string | undefined, @IFileService private readonly fileService: IFileService ) { super(); this.resource = resource; this.name = name; + this.mime = MIME_BINARY; if (resource.scheme === Schemas.data) { const metadata = DataUri.parseMetaData(resource); @@ -33,7 +35,10 @@ export class BinaryEditorModel extends EditorModel { this.size = Number(metadata.get(DataUri.META_DATA_SIZE)); } - this.mime = metadata.get(DataUri.META_DATA_MIME)!; + const metadataMime = metadata.get(DataUri.META_DATA_MIME); + if (metadataMime) { + this.mime = metadataMime; + } } } @@ -41,7 +46,7 @@ export class BinaryEditorModel extends EditorModel { * The name of the binary resource. */ getName(): string { - return this.name; + return this.name || basename(this.resource); } /** @@ -54,7 +59,7 @@ export class BinaryEditorModel extends EditorModel { /** * The size of the binary resource if known. */ - getSize(): number { + getSize(): number | undefined { return this.size; } diff --git a/src/vs/workbench/common/editor/diffEditorModel.ts b/src/vs/workbench/common/editor/diffEditorModel.ts index 2f3b4818e2b..f5c17787f90 100644 --- a/src/vs/workbench/common/editor/diffEditorModel.ts +++ b/src/vs/workbench/common/editor/diffEditorModel.ts @@ -11,6 +11,7 @@ import { IEditorModel } from 'vs/platform/editor/common/editor'; * and the modified version. */ export class DiffEditorModel extends EditorModel { + protected readonly _originalModel: IEditorModel | null; protected readonly _modifiedModel: IEditorModel | null; @@ -58,4 +59,4 @@ export class DiffEditorModel extends EditorModel { super.dispose(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index a1447c830ca..72f1223b558 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -102,7 +102,7 @@ export class EditorGroup extends Disposable { private focusRecentEditorAfterClose: boolean | undefined; constructor( - labelOrSerializedGroup: ISerializedEditorGroup, + labelOrSerializedGroup: ISerializedEditorGroup | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService ) { @@ -149,7 +149,7 @@ export class EditorGroup extends Disposable { for (const editor of this.editors) { const editorResource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); - if (editorResource && editorResource.toString() === resource.toString()) { + if (editorResource?.toString() === resource.toString()) { return editor; } } @@ -176,8 +176,8 @@ export class EditorGroup extends Disposable { openEditor(editor: EditorInput, options?: IEditorOpenOptions): void { const index = this.indexOf(editor); - const makePinned = options && options.pinned; - const makeActive = (options && options.active) || !this.activeEditor || (!makePinned && this.matches(this.preview, this.activeEditor)); + const makePinned = options?.pinned; + const makeActive = options?.active || !this.activeEditor || (!makePinned && this.matches(this.preview, this.activeEditor)); // New editor if (index === -1) { diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index 1d7712d1c4e..ee9605889c4 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -8,6 +8,7 @@ import { URI } from 'vs/base/common/uri'; import { IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; +import { basename } from 'vs/base/common/resources'; /** * A read-only text editor input whos contents are made of the provided resource that points to an existing @@ -21,7 +22,7 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { private modelReference: Promise> | null = null; constructor( - private name: string, + private name: string | undefined, private description: string | undefined, private readonly resource: URI, private preferredMode: string | undefined, @@ -43,7 +44,7 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { } getName(): string { - return this.name; + return this.name || basename(this.resource); } setName(name: string): void { diff --git a/src/vs/workbench/common/editor/textDiffEditorModel.ts b/src/vs/workbench/common/editor/textDiffEditorModel.ts index f18c71fe3c8..579499c30f6 100644 --- a/src/vs/workbench/common/editor/textDiffEditorModel.ts +++ b/src/vs/workbench/common/editor/textDiffEditorModel.ts @@ -14,14 +14,17 @@ import { DiffEditorModel } from 'vs/workbench/common/editor/diffEditorModel'; */ export class TextDiffEditorModel extends DiffEditorModel { - protected readonly _originalModel!: BaseTextEditorModel | null; - protected readonly _modifiedModel!: BaseTextEditorModel | null; + protected readonly _originalModel: BaseTextEditorModel | null; + protected readonly _modifiedModel: BaseTextEditorModel | null; private _textDiffEditorModel: IDiffEditorModel | null = null; constructor(originalModel: BaseTextEditorModel, modifiedModel: BaseTextEditorModel) { super(originalModel, modifiedModel); + this._originalModel = originalModel; + this._modifiedModel = modifiedModel; + this.updateTextDiffEditorModel(); } @@ -42,7 +45,7 @@ export class TextDiffEditorModel extends DiffEditorModel { } private updateTextDiffEditorModel(): void { - if (this.originalModel && this.originalModel.isResolved() && this.modifiedModel && this.modifiedModel.isResolved()) { + if (this.originalModel?.isResolved() && this.modifiedModel?.isResolved()) { // Create new if (!this._textDiffEditorModel) { diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index da75c1b3e9c..9385d8e31e6 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITextModel, ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model'; +import { ITextModel, ITextBufferFactory, ITextSnapshot, ModelConstants } from 'vs/editor/common/model'; import { EditorModel, IModeSupport } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { ITextEditorModel, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; @@ -106,12 +106,12 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd // text buffer factory const textBufferFactory = value as ITextBufferFactory; if (typeof textBufferFactory.getFirstLineText === 'function') { - return textBufferFactory.getFirstLineText(100); + return textBufferFactory.getFirstLineText(ModelConstants.FIRST_LINE_DETECTION_LENGTH_LIMIT); } // text model const textSnapshot = value as ITextModel; - return textSnapshot.getLineContent(1).substr(0, 100); + return textSnapshot.getLineContent(1).substr(0, ModelConstants.FIRST_LINE_DETECTION_LENGTH_LIMIT); } /** diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 1c021309268..ec1db939455 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -5,7 +5,7 @@ import { URI } from 'vs/base/common/uri'; import { suggestFilename } from 'vs/base/common/mime'; -import { memoize } from 'vs/base/common/decorators'; +import { createMemoizer } from 'vs/base/common/decorators'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { basenameOrAuthority, dirname } from 'vs/base/common/resources'; import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult, Verbosity, IModeSupport } from 'vs/workbench/common/editor'; @@ -22,6 +22,7 @@ import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverServ export class UntitledEditorInput extends EditorInput implements IEncodingSupport, IModeSupport { static readonly ID: string = 'workbench.editors.untitledEditorInput'; + private static readonly MEMOIZER = createMemoizer(); private cachedModel: UntitledEditorModel | null = null; private modelResolve: Promise | null = null; @@ -35,14 +36,15 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport constructor( private readonly resource: URI, private readonly _hasAssociatedFilePath: boolean, - private preferredMode: string, - private readonly initialValue: string, - private preferredEncoding: string, + private preferredMode: string | undefined, + private readonly initialValue: string | undefined, + private preferredEncoding: string | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @ITextFileService private readonly textFileService: ITextFileService, @ILabelService private readonly labelService: ILabelService ) { super(); + this._register(this.labelService.onDidChangeFormatters(() => UntitledEditorInput.MEMOIZER.clear())); } get hasAssociatedFilePath(): boolean { @@ -61,17 +63,17 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path; } - @memoize + @UntitledEditorInput.MEMOIZER private get shortDescription(): string { return this.labelService.getUriBasenameLabel(dirname(this.resource)); } - @memoize + @UntitledEditorInput.MEMOIZER private get mediumDescription(): string { return this.labelService.getUriLabel(dirname(this.resource), { relative: true }); } - @memoize + @UntitledEditorInput.MEMOIZER private get longDescription(): string { return this.labelService.getUriLabel(dirname(this.resource)); } @@ -92,17 +94,17 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport } } - @memoize + @UntitledEditorInput.MEMOIZER private get shortTitle(): string { return this.getName(); } - @memoize + @UntitledEditorInput.MEMOIZER private get mediumTitle(): string { return this.labelService.getUriLabel(this.resource, { relative: true }); } - @memoize + @UntitledEditorInput.MEMOIZER private get longTitle(): string { return this.labelService.getUriLabel(this.resource); } @@ -177,7 +179,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return this.getName(); } - getEncoding(): string { + getEncoding(): string | undefined { if (this.cachedModel) { return this.cachedModel.getEncoding(); } diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index 57a77b7267b..a72aaa52f1a 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -33,14 +33,14 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin private dirty: boolean = false; private versionId: number = 0; private readonly contentChangeEventScheduler: RunOnceScheduler; - private configuredEncoding: string; + private configuredEncoding?: string; constructor( - private readonly preferredMode: string, + private readonly preferredMode: string | undefined, private readonly resource: URI, private _hasAssociatedFilePath: boolean, - private readonly initialValue: string, - private preferredEncoding: string, + private readonly initialValue: string | undefined, + private preferredEncoding: string | undefined, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IBackupFileService private readonly backupFileService: IBackupFileService, @@ -87,7 +87,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin return this.preferredMode; } - getEncoding(): string { + getEncoding(): string | undefined { return this.preferredEncoding || this.configuredEncoding; } @@ -190,7 +190,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin // mark the untitled editor as non-dirty once its content becomes empty and we do // not have an associated path set. we never want dirty indicator in that case. - if (!this._hasAssociatedFilePath && this.textEditorModel && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') { + if (!this._hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') { this.setDirty(false); } diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index 9546898f8c9..a6b19e5df2c 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage, IPromptChoice, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage, IPromptChoice, IStatusMessageOptions, NotificationsFilter } from 'vs/platform/notification/common/notification'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -12,6 +12,7 @@ import { Action } from 'vs/base/common/actions'; import { isErrorWithActions } from 'vs/base/common/errorsWithActions'; import { startsWith } from 'vs/base/common/strings'; import { localize } from 'vs/nls'; +import { find, equals } from 'vs/base/common/arrays'; export interface INotificationsModel { @@ -22,9 +23,12 @@ export interface INotificationsModel { readonly notifications: INotificationViewItem[]; readonly onDidNotificationChange: Event; + readonly onDidFilterChange: Event; addNotification(notification: INotification): INotificationHandle; + setFilter(filter: NotificationsFilter): void; + // // Notifications as Status // @@ -123,20 +127,31 @@ export class NotificationHandle implements INotificationHandle { export class NotificationsModel extends Disposable implements INotificationsModel { - private static NO_OP_NOTIFICATION = new NoOpNotification(); + private static readonly NO_OP_NOTIFICATION = new NoOpNotification(); - private readonly _onDidNotificationChange: Emitter = this._register(new Emitter()); + private readonly _onDidNotificationChange = this._register(new Emitter()); readonly onDidNotificationChange: Event = this._onDidNotificationChange.event; - private readonly _onDidStatusMessageChange: Emitter = this._register(new Emitter()); + private readonly _onDidStatusMessageChange = this._register(new Emitter()); readonly onDidStatusMessageChange: Event = this._onDidStatusMessageChange.event; + private readonly _onDidFilterChange = this._register(new Emitter()); + readonly onDidFilterChange: Event = this._onDidFilterChange.event; + private readonly _notifications: INotificationViewItem[] = []; get notifications(): INotificationViewItem[] { return this._notifications; } private _statusMessage: IStatusMessageViewItem | undefined; get statusMessage(): IStatusMessageViewItem | undefined { return this._statusMessage; } + private filter = NotificationsFilter.OFF; + + setFilter(filter: NotificationsFilter): void { + this.filter = filter; + + this._onDidFilterChange.fire(filter); + } + addNotification(notification: INotification): INotificationHandle { const item = this.createViewItem(notification); if (!item) { @@ -169,19 +184,13 @@ export class NotificationsModel extends Disposable implements INotificationsMode } private findNotification(item: INotificationViewItem): INotificationViewItem | undefined { - for (const notification of this._notifications) { - if (notification.equals(item)) { - return notification; - } - } - - return undefined; + return find(this._notifications, notification => notification.equals(item)); } - private createViewItem(notification: INotification): INotificationViewItem | null { - const item = NotificationViewItem.create(notification); + private createViewItem(notification: INotification): INotificationViewItem | undefined { + const item = NotificationViewItem.create(notification, this.filter); if (!item) { - return null; + return undefined; } // Item Events @@ -385,11 +394,11 @@ export interface INotificationMessage { export class NotificationViewItem extends Disposable implements INotificationViewItem { - private static MAX_MESSAGE_LENGTH = 1000; + private static readonly MAX_MESSAGE_LENGTH = 1000; // Example link: "Some message with [link text](http://link.href)." // RegEx: [, anything not ], ], (, http://|https://|command:, no whitespace) - private static LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: "([^"]+)")?\)/gi; + private static readonly LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: "([^"]+)")?\)/gi; private _expanded: boolean | undefined; @@ -405,9 +414,9 @@ export class NotificationViewItem extends Disposable implements INotificationVie private readonly _onDidLabelChange: Emitter = this._register(new Emitter()); readonly onDidLabelChange: Event = this._onDidLabelChange.event; - static create(notification: INotification): INotificationViewItem | null { + static create(notification: INotification, filter: NotificationsFilter = NotificationsFilter.OFF): INotificationViewItem | undefined { if (!notification || !notification.message || isPromiseCanceledError(notification.message)) { - return null; // we need a message to show + return undefined; // we need a message to show } let severity: Severity; @@ -419,7 +428,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie const message = NotificationViewItem.parseNotificationMessage(notification.message); if (!message) { - return null; // we need a message to show + return undefined; // we need a message to show } let actions: INotificationActions | undefined; @@ -429,7 +438,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie actions = { primary: notification.message.actions }; } - return new NotificationViewItem(severity, notification.sticky, notification.silent, message, notification.source, actions); + return new NotificationViewItem(severity, notification.sticky, notification.silent || filter === NotificationsFilter.SILENT || (filter === NotificationsFilter.ERROR && notification.severity !== Severity.Error), message, notification.source, actions); } private static parseNotificationMessage(input: NotificationMessage): INotificationMessage | undefined { @@ -641,17 +650,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie const primaryActions = (this._actions && this._actions.primary) || []; const otherPrimaryActions = (other.actions && other.actions.primary) || []; - if (primaryActions.length !== otherPrimaryActions.length) { - return false; - } - - for (let i = 0; i < primaryActions.length; i++) { - if ((primaryActions[i].id + primaryActions[i].label) !== (otherPrimaryActions[i].id + otherPrimaryActions[i].label)) { - return false; - } - } - - return true; + return equals(primaryActions, otherPrimaryActions, (a, b) => (a.id + a.label) === (b.id + b.label)); } } @@ -690,9 +689,9 @@ export class ChoiceAction extends Action { class StatusMessageViewItem { - static create(notification: NotificationMessage, options?: IStatusMessageOptions): IStatusMessageViewItem | null { + static create(notification: NotificationMessage, options?: IStatusMessageOptions): IStatusMessageViewItem | undefined { if (!notification || isPromiseCanceledError(notification)) { - return null; // we need a message to show + return undefined; // we need a message to show } let message: string | undefined; @@ -703,7 +702,7 @@ class StatusMessageViewItem { } if (!message) { - return null; // we need a message to show + return undefined; // we need a message to show } return { message, options }; diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index 53de865d8f1..c509716fc49 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -18,13 +18,13 @@ import { withNullAsUndefined } from 'vs/base/common/types'; export class ResourceContextKey extends Disposable implements IContextKey { - static Scheme = new RawContextKey('resourceScheme', undefined); - static Filename = new RawContextKey('resourceFilename', undefined); - static LangId = new RawContextKey('resourceLangId', undefined); - static Resource = new RawContextKey('resource', undefined); - static Extension = new RawContextKey('resourceExtname', undefined); - static HasResource = new RawContextKey('resourceSet', false); - static IsFileSystemResource = new RawContextKey('isFileSystemResource', false); + static readonly Scheme = new RawContextKey('resourceScheme', undefined); + static readonly Filename = new RawContextKey('resourceFilename', undefined); + static readonly LangId = new RawContextKey('resourceLangId', undefined); + static readonly Resource = new RawContextKey('resource', undefined); + static readonly Extension = new RawContextKey('resourceExtname', undefined); + static readonly HasResource = new RawContextKey('resourceSet', false); + static readonly IsFileSystemResource = new RawContextKey('isFileSystemResource', false); private readonly _resourceKey: IContextKey; private readonly _schemeKey: IContextKey; @@ -180,24 +180,24 @@ export class ResourceGlobMatcher extends Disposable { matches(resource: URI): boolean { const folder = this.contextService.getWorkspaceFolder(resource); - let expressionForRoot: ParsedExpression; + let expressionForRoot: ParsedExpression | undefined; if (folder && this.mapRootToParsedExpression.has(folder.uri.toString())) { - expressionForRoot = this.mapRootToParsedExpression.get(folder.uri.toString())!; + expressionForRoot = this.mapRootToParsedExpression.get(folder.uri.toString()); } else { - expressionForRoot = this.mapRootToParsedExpression.get(ResourceGlobMatcher.NO_ROOT)!; + expressionForRoot = this.mapRootToParsedExpression.get(ResourceGlobMatcher.NO_ROOT); } // If the resource if from a workspace, convert its absolute path to a relative // path so that glob patterns have a higher probability to match. For example // a glob pattern of "src/**" will not match on an absolute path "/folder/src/file.txt" // but can match on "src/file.txt" - let resourcePathToMatch: string; + let resourcePathToMatch: string | undefined; if (folder) { - resourcePathToMatch = relativePath(folder.uri, resource)!; // always uses forward slashes + resourcePathToMatch = relativePath(folder.uri, resource); // always uses forward slashes } else { resourcePathToMatch = resource.fsPath; // TODO@isidor: support non-file URIs } - return !!expressionForRoot(resourcePathToMatch); + return !!expressionForRoot && typeof resourcePathToMatch === 'string' && !!expressionForRoot(resourcePathToMatch); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 7d81c6c5e72..188874a1199 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground, editorErrorForeground, editorWarningForeground, editorInfoForeground } from 'vs/platform/theme/common/colorRegistry'; import { Disposable } from 'vs/base/common/lifecycle'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; @@ -235,8 +235,8 @@ export const PANEL_INACTIVE_TITLE_FOREGROUND = registerColor('panelTitle.inactiv }, nls.localize('panelInactiveTitleForeground', "Title color for the inactive panel. Panels are shown below the editor area and contain views like output and integrated terminal.")); export const PANEL_ACTIVE_TITLE_BORDER = registerColor('panelTitle.activeBorder', { - dark: PANEL_BORDER, - light: PANEL_BORDER, + dark: PANEL_ACTIVE_TITLE_FOREGROUND, + light: PANEL_ACTIVE_TITLE_FOREGROUND, hc: contrastBorder }, nls.localize('panelActiveTitleBorder', "Border color for the active panel title. Panels are shown below the editor area and contain views like output and integrated terminal.")); @@ -335,8 +335,8 @@ export const ACTIVITY_BAR_FOREGROUND = registerColor('activityBar.foreground', { }, nls.localize('activityBarForeground', "Activity bar item foreground color when it is active. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); export const ACTIVITY_BAR_INACTIVE_FOREGROUND = registerColor('activityBar.inactiveForeground', { - dark: transparent(ACTIVITY_BAR_FOREGROUND, 0.6), - light: transparent(ACTIVITY_BAR_FOREGROUND, 0.6), + dark: transparent(ACTIVITY_BAR_FOREGROUND, 0.4), + light: transparent(ACTIVITY_BAR_FOREGROUND, 0.4), hc: Color.white }, nls.localize('activityBarInActiveForeground', "Activity bar item foreground color when it is inactive. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); @@ -346,6 +346,18 @@ export const ACTIVITY_BAR_BORDER = registerColor('activityBar.border', { hc: contrastBorder }, nls.localize('activityBarBorder', "Activity bar border color separating to the side bar. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); +export const ACTIVITY_BAR_ACTIVE_BORDER = registerColor('activityBar.activeBorder', { + dark: ACTIVITY_BAR_FOREGROUND, + light: ACTIVITY_BAR_FOREGROUND, + hc: null +}, nls.localize('activityBarActiveBorder', "Activity bar border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); + +export const ACTIVITY_BAR_ACTIVE_BACKGROUND = registerColor('activityBar.activeBackground', { + dark: null, + light: null, + hc: null +}, nls.localize('activityBarActiveBackground', "Activity bar background color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.")); + export const ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND = registerColor('activityBar.dropBackground', { dark: Color.white.transparent(0.12), light: Color.white.transparent(0.12), @@ -560,22 +572,34 @@ export const NOTIFICATIONS_BORDER = registerColor('notifications.border', { }, nls.localize('notificationsBorder', "Notifications border color separating from other notifications in the notifications center. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_ERROR_ICON_FOREGROUND = registerColor('notificationsErrorIcon.foreground', { - dark: '#F48771', - light: '#A1260D', - hc: '#F48771' -}, nls.localize('notificationsErrorIconForeground', "The color used for the notification error icon.")); + dark: editorErrorForeground, + light: editorErrorForeground, + hc: editorErrorForeground +}, nls.localize('notificationsErrorIconForeground', "The color used for the icon of error notifications. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_WARNING_ICON_FOREGROUND = registerColor('notificationsWarningIcon.foreground', { - dark: '#FFCC00', - light: '#DDB100', - hc: '#FFCC00' -}, nls.localize('notificationsWarningIconForeground', "The color used for the notification warning icon.")); + dark: editorWarningForeground, + light: editorWarningForeground, + hc: editorWarningForeground +}, nls.localize('notificationsWarningIconForeground', "The color used for the icon of warning notifications. Notifications slide in from the bottom right of the window.")); export const NOTIFICATIONS_INFO_ICON_FOREGROUND = registerColor('notificationsInfoIcon.foreground', { - dark: '#75BEFF', - light: '#007ACC', - hc: '#75BEFF' -}, nls.localize('notificationsInfoIconForeground', "The color used for the notification info icon.")); + dark: editorInfoForeground, + light: editorInfoForeground, + hc: editorInfoForeground +}, nls.localize('notificationsInfoIconForeground', "The color used for the icon of info notifications. Notifications slide in from the bottom right of the window.")); + +export const WINDOW_ACTIVE_BORDER = registerColor('window.activeBorder', { + dark: null, + light: null, + hc: contrastBorder +}, nls.localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client.")); + +export const WINDOW_INACTIVE_BORDER = registerColor('window.inactiveBorder', { + dark: null, + light: null, + hc: contrastBorder +}, nls.localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client.")); /** * Base class for all themable workbench components. diff --git a/src/vs/workbench/common/viewlet.ts b/src/vs/workbench/common/viewlet.ts index ddb8340130c..01fafea5968 100644 --- a/src/vs/workbench/common/viewlet.ts +++ b/src/vs/workbench/common/viewlet.ts @@ -15,5 +15,5 @@ export interface IViewlet extends IComposite { /** * Returns the minimal width needed to avoid any content horizontal truncation */ - getOptimalWidth(): number | null; + getOptimalWidth(): number | undefined; } diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index a93bb3aca6c..2e733ef117c 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -7,7 +7,6 @@ import { Command } from 'vs/editor/common/modes'; import { UriComponents } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { ITreeViewDataProvider } from 'vs/workbench/common/views'; import { localize } from 'vs/nls'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -148,7 +147,7 @@ export interface IViewDescriptor { // For contributed remote explorer views readonly group?: string; - readonly remoteAuthority?: string; + readonly remoteAuthority?: string | string[]; } export interface IViewDescriptorCollection extends IDisposable { diff --git a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts index 3ac6bb520d5..21960a95a6c 100644 --- a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts +++ b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts @@ -6,11 +6,10 @@ import { URI as Uri } from 'vs/base/common/uri'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ITextFileService, TextFileModelChangeEvent, StateChange } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, TextFileModelChangeEvent, StateChange, IAutoSaveConfiguration } from 'vs/workbench/services/textfile/common/textfiles'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IFilesConfiguration, AutoSaveConfiguration, CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; +import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY + 500; @@ -22,7 +21,6 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu @IBackupFileService private readonly backupFileService: IBackupFileService, @ITextFileService private readonly textFileService: ITextFileService, @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, - @IConfigurationService private readonly configurationService: IConfigurationService ) { super(); @@ -32,26 +30,20 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu private registerListeners() { // Listen for text file model changes - this._register(this.textFileService.models.onModelContentChanged((e) => this.onTextFileModelChanged(e))); - this._register(this.textFileService.models.onModelSaved((e) => this.discardBackup(e.resource))); - this._register(this.textFileService.models.onModelDisposed((e) => this.discardBackup(e))); + this._register(this.textFileService.models.onModelContentChanged(e => this.onTextFileModelChanged(e))); + this._register(this.textFileService.models.onModelSaved(e => this.discardBackup(e.resource))); + this._register(this.textFileService.models.onModelDisposed(e => this.discardBackup(e))); // Listen for untitled model changes - this._register(this.untitledEditorService.onDidChangeContent((e) => this.onUntitledModelChanged(e))); - this._register(this.untitledEditorService.onDidDisposeModel((e) => this.discardBackup(e))); + this._register(this.untitledEditorService.onDidChangeContent(e => this.onUntitledModelChanged(e))); + this._register(this.untitledEditorService.onDidDisposeModel(e => this.discardBackup(e))); // Listen to config changes - this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getValue()))); + this._register(this.textFileService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); } - private onConfigurationChange(configuration: IFilesConfiguration): void { - if (!configuration || !configuration.files) { - this.configuredAutoSaveAfterDelay = false; - - return; - } - - this.configuredAutoSaveAfterDelay = (configuration.files.autoSave === AutoSaveConfiguration.AFTER_DELAY && configuration.files.autoSaveDelay <= AUTO_SAVE_AFTER_DELAY_DISABLED_TIME); + private onAutoSaveConfigurationChange(configuration: IAutoSaveConfiguration): void { + this.configuredAutoSaveAfterDelay = typeof configuration.autoSaveDelay === 'number' && configuration.autoSaveDelay < AUTO_SAVE_AFTER_DELAY_DISABLED_TIME; } private onTextFileModelChanged(event: TextFileModelChangeEvent): void { diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts index 1615bf30b86..71088bf77c3 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { CallHierarchyProviderRegistry, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; +import { CallHierarchyProviderRegistry, CallHierarchyDirection, CallHierarchyModel } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { CallHierarchyTreePeekWidget } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek'; @@ -18,31 +18,36 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { PeekContext } from 'vs/editor/contrib/referenceSearch/peekViewWidget'; -import { CallHierarchyRoot } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { Range } from 'vs/editor/common/core/range'; +import { IPosition } from 'vs/editor/common/core/position'; const _ctxHasCompletionItemProvider = new RawContextKey('editorHasCallHierarchyProvider', false); const _ctxCallHierarchyVisible = new RawContextKey('callHierarchyVisible', false); class CallHierarchyController implements IEditorContribution { - static Id = 'callHierarchy'; + static readonly Id = 'callHierarchy'; static get(editor: ICodeEditor): CallHierarchyController { return editor.getContribution(CallHierarchyController.Id); } - private static _StorageDirection = 'callHierarchy/defaultDirection'; + private static readonly _StorageDirection = 'callHierarchy/defaultDirection'; private readonly _ctxHasProvider: IContextKey; private readonly _ctxIsVisible: IContextKey; private readonly _dispoables = new DisposableStore(); private readonly _sessionDisposables = new DisposableStore(); + private _widget?: CallHierarchyTreePeekWidget; + constructor( private readonly _editor: ICodeEditor, @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IStorageService private readonly _storageService: IStorageService, + @ICodeEditorService private readonly _editorService: ICodeEditorService, @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { this._ctxIsVisible = _ctxCallHierarchyVisible.bindTo(this._contextKeyService); @@ -59,52 +64,83 @@ class CallHierarchyController implements IEditorContribution { this._dispoables.dispose(); } - getId(): string { - return CallHierarchyController.Id; - } - - async startCallHierarchy(): Promise { + async startCallHierarchyFromEditor(): Promise { this._sessionDisposables.clear(); if (!this._editor.hasModel()) { return; } - const model = this._editor.getModel(); + const document = this._editor.getModel(); const position = this._editor.getPosition(); - const [provider] = CallHierarchyProviderRegistry.ordered(model); - if (!provider) { + if (!CallHierarchyProviderRegistry.has(document)) { return; } + const cts = new CancellationTokenSource(); + const model = CallHierarchyModel.create(document, position, cts.token); const direction = this._storageService.getNumber(CallHierarchyController._StorageDirection, StorageScope.GLOBAL, CallHierarchyDirection.CallsFrom); - Event.any(this._editor.onDidChangeModel, this._editor.onDidChangeModelLanguage)(this.endCallHierarchy, this, this._sessionDisposables); - const widget = this._instantiationService.createInstance( - CallHierarchyTreePeekWidget, - this._editor, - position, - provider, - direction + this._showCallHierarchyWidget(position, direction, model, cts); + } + + async startCallHierarchyFromCallHierarchy(): Promise { + if (!this._widget) { + return; + } + const model = this._widget.getModel(); + const call = this._widget.getFocused(); + if (!call || !model) { + return; + } + const newEditor = await this._editorService.openCodeEditor({ resource: call.item.uri }, this._editor); + if (!newEditor) { + return; + } + const newModel = model.fork(call.item); + this._sessionDisposables.clear(); + + CallHierarchyController.get(newEditor)._showCallHierarchyWidget( + Range.lift(newModel.root.selectionRange).getStartPosition(), + this._widget.direction, + Promise.resolve(newModel), + new CancellationTokenSource() ); + } - widget.showLoading(); + private _showCallHierarchyWidget(position: IPosition, direction: number, model: Promise, cts: CancellationTokenSource) { + + Event.any(this._editor.onDidChangeModel, this._editor.onDidChangeModelLanguage)(this.endCallHierarchy, this, this._sessionDisposables); + this._widget = this._instantiationService.createInstance(CallHierarchyTreePeekWidget, this._editor, position, direction); + this._widget.showLoading(); this._ctxIsVisible.set(true); - - const cancel = new CancellationTokenSource(); - - this._sessionDisposables.add(widget.onDidClose(() => { + this._sessionDisposables.add(this._widget.onDidClose(() => { this.endCallHierarchy(); - this._storageService.store(CallHierarchyController._StorageDirection, widget.direction, StorageScope.GLOBAL); + this._storageService.store(CallHierarchyController._StorageDirection, this._widget!.direction, StorageScope.GLOBAL); })); - this._sessionDisposables.add({ dispose() { cancel.cancel(); } }); - this._sessionDisposables.add(widget); + this._sessionDisposables.add({ dispose() { cts.dispose(true); } }); + this._sessionDisposables.add(this._widget); - const root = CallHierarchyRoot.fromEditor(this._editor); - if (root) { - widget.showItem(root); - } else { - widget.showMessage(localize('no.item', "No results")); + model.then(model => { + if (cts.token.isCancellationRequested) { + return; // nothing + } + if (model) { + this._sessionDisposables.add(model); + this._widget!.showModel(model); + } + else { + this._widget!.showMessage(localize('no.item', "No results")); + } + }).catch(e => { + this._widget!.showMessage(localize('error', "Failed to show call hierarchy")); + console.error(e); + }); + } + + toggleCallHierarchyDirection(): void { + if (this._widget) { + this._widget.toggleDirection(); } } @@ -115,7 +151,7 @@ class CallHierarchyController implements IEditorContribution { } } -registerEditorContribution(CallHierarchyController); +registerEditorContribution(CallHierarchyController.Id, CallHierarchyController); registerEditorAction(class extends EditorAction { @@ -134,14 +170,55 @@ registerEditorAction(class extends EditorAction { primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H }, precondition: ContextKeyExpr.and( + _ctxCallHierarchyVisible.negate(), _ctxHasCompletionItemProvider, PeekContext.notInPeekEditor ) }); } - async run(_accessor: ServicesAccessor, editor: ICodeEditor, args: any): Promise { - return CallHierarchyController.get(editor).startCallHierarchy(); + async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise { + return CallHierarchyController.get(editor).startCallHierarchyFromEditor(); + } +}); + +registerEditorAction(class extends EditorAction { + + constructor() { + super({ + id: 'editor.toggleCallHierarchy', + label: localize('title.toggle', "Toggle Call Hierarchy"), + alias: 'Toggle Call Hierarchy', + kbOpts: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H + }, + precondition: _ctxCallHierarchyVisible + }); + } + + async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise { + return CallHierarchyController.get(editor).toggleCallHierarchyDirection(); + } +}); + +registerEditorAction(class extends EditorAction { + + constructor() { + super({ + id: 'editor.refocusCallHierarchy', + label: localize('title.refocus', "Refocus Call Hierarchy"), + alias: 'Refocus Call Hierarchy', + kbOpts: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.Shift + KeyCode.Enter + }, + precondition: _ctxCallHierarchyVisible + }); + } + + async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise { + return CallHierarchyController.get(editor).startCallHierarchyFromCallHierarchy(); } }); diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.ts index 160662e8ac2..745780da5ac 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.ts @@ -10,9 +10,9 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry'; import { URI } from 'vs/base/common/uri'; import { IPosition } from 'vs/editor/common/core/position'; -import { registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { onUnexpectedExternalError } from 'vs/base/common/errors'; +import { IDisposable } from 'vs/base/common/lifecycle'; export const enum CallHierarchyDirection { CallsTo = 1, @@ -20,6 +20,7 @@ export const enum CallHierarchyDirection { } export interface CallHierarchyItem { + id: string; kind: SymbolKind; name: string; detail?: string; @@ -29,56 +30,107 @@ export interface CallHierarchyItem { } export interface IncomingCall { - source: CallHierarchyItem; - sourceRanges: IRange[]; + from: CallHierarchyItem; + fromRanges: IRange[]; } export interface OutgoingCall { - sourceRanges: IRange[]; - target: CallHierarchyItem; + fromRanges: IRange[]; + to: CallHierarchyItem; +} + +export interface CallHierarchySession { + root: CallHierarchyItem; + dispose(): void; } export interface CallHierarchyProvider { - provideIncomingCalls(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult; + prepareCallHierarchy(document: ITextModel, position: IPosition, token: CancellationToken): ProviderResult; - provideOutgoingCalls(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult; + provideIncomingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult; + + provideOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult; } export const CallHierarchyProviderRegistry = new LanguageFeatureRegistry(); -export async function provideIncomingCalls(model: ITextModel, position: IPosition, token: CancellationToken): Promise { - const [provider] = CallHierarchyProviderRegistry.ordered(model); - if (!provider) { - return []; +class RefCountedDisposabled { + + constructor( + private readonly _disposable: IDisposable, + private _counter = 1 + ) { } + + acquire() { + this._counter++; + return this; } - try { - const result = await provider.provideIncomingCalls(model, position, token); - if (isNonEmptyArray(result)) { - return result; + + release() { + if (--this._counter === 0) { + this._disposable.dispose(); } - } catch (e) { - onUnexpectedExternalError(e); + return this; } - return []; } -export async function provideOutgoingCalls(model: ITextModel, position: IPosition, token: CancellationToken): Promise { - const [provider] = CallHierarchyProviderRegistry.ordered(model); - if (!provider) { +export class CallHierarchyModel { + + static async create(model: ITextModel, position: IPosition, token: CancellationToken): Promise { + const [provider] = CallHierarchyProviderRegistry.ordered(model); + if (!provider) { + return undefined; + } + const session = await provider.prepareCallHierarchy(model, position, token); + if (!session) { + return undefined; + } + return new CallHierarchyModel(provider, session.root, new RefCountedDisposabled(session)); + } + + private constructor( + readonly provider: CallHierarchyProvider, + readonly root: CallHierarchyItem, + readonly ref: RefCountedDisposabled, + ) { } + + dispose(): void { + this.ref.release(); + } + + fork(item: CallHierarchyItem): CallHierarchyModel { + const that = this; + return new class extends CallHierarchyModel { + constructor() { + super(that.provider, item, that.ref.acquire()); + } + }; + } + + async resolveIncomingCalls(item: CallHierarchyItem, token: CancellationToken): Promise { + try { + const result = await this.provider.provideIncomingCalls(item, token); + if (isNonEmptyArray(result)) { + return result; + } + } catch (e) { + onUnexpectedExternalError(e); + } return []; } - try { - const result = await provider.provideOutgoingCalls(model, position, token); - if (isNonEmptyArray(result)) { - return result; + + async resolveOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): Promise { + try { + const result = await this.provider.provideOutgoingCalls(item, token); + if (isNonEmptyArray(result)) { + return result; + } + } catch (e) { + onUnexpectedExternalError(e); } - } catch (e) { - onUnexpectedExternalError(e); + return []; } - return []; } -registerDefaultLanguageCommand('_executeCallHierarchyIncomingCalls', async (model, position) => provideIncomingCalls(model, position, CancellationToken.None)); -registerDefaultLanguageCommand('_executeCallHierarchyOutgoingCalls', async (model, position) => provideOutgoingCalls(model, position, CancellationToken.None)); diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts index 7e4d4ac6dac..b38b999e532 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/callHierarchy'; import { PeekViewWidget, IPeekViewService } from 'vs/editor/contrib/referenceSearch/peekViewWidget'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { CallHierarchyProvider, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; +import { CallHierarchyDirection, CallHierarchyModel } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; import { FuzzyScore } from 'vs/base/common/filters'; import * as callHTree from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree'; @@ -31,7 +31,7 @@ import { Action } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { Color } from 'vs/base/common/color'; -import { TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree'; +import { TreeMouseEventTarget, ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { URI } from 'vs/base/common/uri'; const enum State { @@ -42,19 +42,14 @@ const enum State { class ChangeHierarchyDirectionAction extends Action { - constructor(direction: CallHierarchyDirection, updateDirection: (direction: CallHierarchyDirection) => void) { + constructor(getDirection: () => CallHierarchyDirection, toggleDirection: () => void) { super('', undefined, '', true, () => { - if (direction === CallHierarchyDirection.CallsTo) { - direction = CallHierarchyDirection.CallsFrom; - } else { - direction = CallHierarchyDirection.CallsTo; - } - updateDirection(direction); + toggleDirection(); update(); return Promise.resolve(); }); const update = () => { - if (direction === CallHierarchyDirection.CallsFrom) { + if (getDirection() === CallHierarchyDirection.CallsFrom) { this.label = localize('toggle.from', "Showing Calls"); this.class = 'calls-from'; } else { @@ -94,16 +89,17 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { private _parent!: HTMLElement; private _message!: HTMLElement; private _splitView!: SplitView; - private _tree!: WorkbenchAsyncDataTree; + private _tree!: WorkbenchAsyncDataTree; private _treeViewStates = new Map(); private _editor!: EmbeddedCodeEditorWidget; private _dim!: Dimension; private _layoutInfo!: LayoutInfo; + private readonly _previewDisposable = new DisposableStore(); + constructor( editor: ICodeEditor, private readonly _where: IPosition, - private readonly _provider: CallHierarchyProvider, private _direction: CallHierarchyDirection, @IThemeService themeService: IThemeService, @IPeekViewService private readonly _peekViewService: IPeekViewService, @@ -117,6 +113,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { this._peekViewService.addExclusiveWidget(editor, this); this._applyTheme(themeService.getTheme()); this._disposables.add(themeService.onThemeChange(this._applyTheme, this)); + this._disposables.add(this._previewDisposable); } dispose(): void { @@ -199,17 +196,18 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { addClass(treeContainer, 'tree'); container.appendChild(treeContainer); const options: IAsyncDataTreeOptions = { + sorter: new callHTree.Sorter(), identityProvider: new callHTree.IdentityProvider(() => this._direction), ariaLabel: localize('tree.aria', "Call Hierarchy"), expandOnlyOnTwistieClick: true, }; - this._tree = this._instantiationService.createInstance( + this._tree = this._instantiationService.createInstance>( WorkbenchAsyncDataTree, 'CallHierarchyPeek', treeContainer, new callHTree.VirtualDelegate(), [this._instantiationService.createInstance(callHTree.CallRenderer)], - this._instantiationService.createInstance(callHTree.DataSource, this._provider, () => this._direction), + this._instantiationService.createInstance(callHTree.DataSource, () => this._direction), options ); @@ -244,81 +242,8 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { } })); - // session state - const localDispose = new DisposableStore(); - this._disposables.add(localDispose); - // update editor - this._disposables.add(this._tree.onDidChangeFocus(async e => { - const [element] = e.elements; - if (!element) { - return; - } - - localDispose.clear(); - - // update: editor and editor highlights - const options: IModelDecorationOptions = { - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - className: 'call-decoration', - overviewRuler: { - color: themeColorFromId(referencesWidget.peekViewEditorMatchHighlight), - position: OverviewRulerLane.Center - }, - }; - - let previewUri: URI; - if (this._direction === CallHierarchyDirection.CallsFrom) { - // outgoing calls: show caller and highlight focused calls - previewUri = element.parent ? element.parent.item.uri : this._tree.getInput()!.model.uri; - } else { - // incoming calls: show caller and highlight focused calls - previewUri = element.item.uri; - } - - const value = await this._textModelService.createModelReference(previewUri); - this._editor.setModel(value.object.textEditorModel); - - // set decorations for caller ranges (if in the same file) - let decorations: IModelDeltaDecoration[] = []; - let fullRange: IRange | undefined; - for (const loc of element.locations) { - if (loc.uri.toString() === previewUri.toString()) { - decorations.push({ range: loc.range, options }); - fullRange = !fullRange ? loc.range : Range.plusRange(loc.range, fullRange); - } - } - if (fullRange) { - this._editor.revealRangeInCenter(fullRange, ScrollType.Immediate); - const ids = this._editor.deltaDecorations([], decorations); - localDispose.add(toDisposable(() => this._editor.deltaDecorations(ids, []))); - } - localDispose.add(value); - - // update: title and subtitle - let node: callHTree.Call | undefined = element; - let names = [element.item.name]; - while (node) { - let parent = this._tree.getParentElement(node); - let name: string; - if (parent instanceof callHTree.Call) { - name = parent.item.name; - node = parent; - } else { - name = this._tree.getInput()!.word; - node = undefined; - } - if (this._direction === CallHierarchyDirection.CallsTo) { - names.push(name); - } else { - names.unshift(name); - } - } - const title = this._direction === CallHierarchyDirection.CallsFrom - ? localize('callFrom', "Calls from '{0}'", this._tree.getInput()!.word) - : localize('callsTo', "Callers of '{0}'", this._tree.getInput()!.word); - this.setTitle(title, names.join(' → ')); - })); + this._disposables.add(this._tree.onDidChangeFocus(this._updatePreview, this)); this._disposables.add(this._editor.onMouseDown(e => { const { event, target } = e; @@ -364,6 +289,60 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { })); } + private async _updatePreview() { + const [element] = this._tree.getFocus(); + if (!element) { + return; + } + + this._previewDisposable.clear(); + + // update: editor and editor highlights + const options: IModelDecorationOptions = { + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'call-decoration', + overviewRuler: { + color: themeColorFromId(referencesWidget.peekViewEditorMatchHighlight), + position: OverviewRulerLane.Center + }, + }; + + let previewUri: URI; + if (this._direction === CallHierarchyDirection.CallsFrom) { + // outgoing calls: show caller and highlight focused calls + previewUri = element.parent ? element.parent.item.uri : element.model.root.uri; + + } else { + // incoming calls: show caller and highlight focused calls + previewUri = element.item.uri; + } + + const value = await this._textModelService.createModelReference(previewUri); + this._editor.setModel(value.object.textEditorModel); + + // set decorations for caller ranges (if in the same file) + let decorations: IModelDeltaDecoration[] = []; + let fullRange: IRange | undefined; + for (const loc of element.locations) { + if (loc.uri.toString() === previewUri.toString()) { + decorations.push({ range: loc.range, options }); + fullRange = !fullRange ? loc.range : Range.plusRange(loc.range, fullRange); + } + } + if (fullRange) { + this._editor.revealRangeInCenter(fullRange, ScrollType.Immediate); + const ids = this._editor.deltaDecorations([], decorations); + this._previewDisposable.add(toDisposable(() => this._editor.deltaDecorations(ids, []))); + } + this._previewDisposable.add(value); + + // update: title + const title = this._direction === CallHierarchyDirection.CallsFrom + ? localize('callFrom', "Calls from '{0}'", element.model.root.name) + : localize('callsTo', "Callers of '{0}'", element.model.root.name); + this.setTitle(title); + } + showLoading(): void { this._parent.dataset['state'] = State.Loading; this.setTitle(localize('title.loading', "Loading...")); @@ -379,41 +358,56 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { this._message.focus(); } - async showItem(item: callHTree.CallHierarchyRoot): Promise { + async showModel(model: CallHierarchyModel): Promise { this._show(); const viewState = this._treeViewStates.get(this._direction); - await this._tree.setInput(item, viewState); - if (this._tree.getNode(item).children.length === 0) { + await this._tree.setInput(model, viewState); + + const root = >this._tree.getNode(model).children[0]; + await this._tree.expand(root.element); + + if (root.children.length === 0) { // this.showMessage(this._direction === CallHierarchyDirection.CallsFrom - ? localize('empt.callsFrom', "No calls from '{0}'", item.word) - : localize('empt.callsTo', "No callers of '{0}'", item.word)); + ? localize('empt.callsFrom', "No calls from '{0}'", model.root.name) + : localize('empt.callsTo', "No callers of '{0}'", model.root.name)); } else { this._parent.dataset['state'] = State.Data; - this._tree.domFocus(); if (!viewState) { - this._tree.focusFirst(); + this._tree.setFocus([root.children[0].element]); } + this._tree.domFocus(); + this._updatePreview(); } if (!this._changeDirectionAction) { - const changeDirection = (newDirection: CallHierarchyDirection) => { - if (this._direction !== newDirection) { - this._treeViewStates.set(this._direction, this._tree.getViewState()); - this._direction = newDirection; - this._tree.setFocus([]); - this.showItem(this._tree.getInput()!); - } - }; - this._changeDirectionAction = new ChangeHierarchyDirectionAction(this._direction, changeDirection); + this._changeDirectionAction = new ChangeHierarchyDirectionAction(() => this._direction, () => this.toggleDirection()); this._disposables.add(this._changeDirectionAction); this._actionbarWidget!.push(this._changeDirectionAction, { icon: true, label: false }); } } + getModel(): CallHierarchyModel | undefined { + return this._tree.getInput(); + } + + getFocused(): callHTree.Call | undefined { + return this._tree.getFocus()[0]; + } + + async toggleDirection(): Promise { + const model = this._tree.getInput(); + if (model) { + const newDirection = this._direction === CallHierarchyDirection.CallsTo ? CallHierarchyDirection.CallsFrom : CallHierarchyDirection.CallsTo; + this._treeViewStates.set(this._direction, this._tree.getViewState()); + this._direction = newDirection; + await this.showModel(model); + } + } + private _show() { if (!this._isShowing) { this.editor.revealLineInCenterIfOutsideViewport(this._where.lineNumber, ScrollType.Smooth); diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts index dbe1dee06ad..a00b49e0d01 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts @@ -3,104 +3,79 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IAsyncDataSource, ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree'; -import { CallHierarchyItem, CallHierarchyProvider, CallHierarchyDirection, provideOutgoingCalls, provideIncomingCalls } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; +import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeSorter } from 'vs/base/browser/ui/tree/tree'; +import { CallHierarchyItem, CallHierarchyDirection, CallHierarchyModel, } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; -import { symbolKindToCssClass, Location } from 'vs/editor/common/modes'; -import { hash } from 'vs/base/common/hash'; -import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { SymbolKinds, Location } from 'vs/editor/common/modes'; +import * as dom from 'vs/base/browser/dom'; +import { compare } from 'vs/base/common/strings'; import { Range } from 'vs/editor/common/core/range'; -import { ITextModel } from 'vs/editor/common/model'; -import { IPosition } from 'vs/editor/common/core/position'; -import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; export class Call { constructor( readonly item: CallHierarchyItem, readonly locations: Location[], + readonly model: CallHierarchyModel, readonly parent: Call | undefined ) { } -} -export class CallHierarchyRoot { - - static fromEditor(editor: IActiveCodeEditor): CallHierarchyRoot | undefined { - const model = editor.getModel(); - const position = editor.getPosition(); - const wordInfo = model.getWordAtPosition(position); - return wordInfo - ? new CallHierarchyRoot(model, position, wordInfo.word) - : undefined; + static compare(a: Call, b: Call): number { + let res = compare(a.item.uri.toString(), b.item.uri.toString()); + if (res === 0) { + res = Range.compareRangesUsingStarts(a.item.range, b.item.range); + } + return res; } - - constructor( - readonly model: ITextModel, - readonly position: IPosition, - readonly word: string - ) { } } -export class DataSource implements IAsyncDataSource { +export class DataSource implements IAsyncDataSource { constructor( - public provider: CallHierarchyProvider, public getDirection: () => CallHierarchyDirection, - @ITextModelService private readonly _modelService: ITextModelService, ) { } hasChildren(): boolean { return true; } - async getChildren(element: CallHierarchyRoot | Call): Promise { + async getChildren(element: CallHierarchyModel | Call): Promise { + if (element instanceof CallHierarchyModel) { + return [new Call(element.root, [], element, undefined)]; + } - const results: Call[] = []; + const { model, item } = element; + + if (this.getDirection() === CallHierarchyDirection.CallsFrom) { + return (await model.resolveOutgoingCalls(item, CancellationToken.None)).map(call => { + return new Call( + call.to, + call.fromRanges.map(range => ({ range, uri: item.uri })), + model, + element + ); + }); - if (element instanceof CallHierarchyRoot) { - if (this.getDirection() === CallHierarchyDirection.CallsFrom) { - await this._getOutgoingCalls(element.model, element.position, results); - } else { - await this._getIncomingCalls(element.model, element.position, results); - } } else { - const reference = await this._modelService.createModelReference(element.item.uri); - const position = Range.lift(element.item.selectionRange).getStartPosition(); - if (this.getDirection() === CallHierarchyDirection.CallsFrom) { - await this._getOutgoingCalls(reference.object.textEditorModel, position, results, element); - } else { - await this._getIncomingCalls(reference.object.textEditorModel, position, results, element); - } - reference.dispose(); - } - - return results; - } - - private async _getOutgoingCalls(model: ITextModel, position: IPosition, bucket: Call[], parent?: Call): Promise { - const outgoingCalls = await provideOutgoingCalls(model, position, CancellationToken.None); - for (const call of outgoingCalls) { - bucket.push(new Call( - call.target, - call.sourceRanges.map(range => ({ range, uri: model.uri })), - parent - )); + return (await model.resolveIncomingCalls(item, CancellationToken.None)).map(call => { + return new Call( + call.from, + call.fromRanges.map(range => ({ range, uri: call.from.uri })), + model, + element + ); + }); } } +} - private async _getIncomingCalls(model: ITextModel, position: IPosition, bucket: Call[], parent?: Call): Promise { - const incomingCalls = await provideIncomingCalls(model, position, CancellationToken.None); - for (const call of incomingCalls) { - bucket.push(new Call( - call.source, - call.sourceRanges.map(range => ({ range, uri: call.source.uri })), - parent - )); - } +export class Sorter implements ITreeSorter { + + compare(element: Call, otherElement: Call): number { + return Call.compare(element, otherElement); } - } export class IdentityProvider implements IIdentityProvider { @@ -110,42 +85,46 @@ export class IdentityProvider implements IIdentityProvider { ) { } getId(element: Call): { toString(): string; } { - return this.getDirection() + hash(element.item.uri.toString(), hash(JSON.stringify(element.item.range))).toString() + (element.parent ? this.getId(element.parent) : ''); + let res = this.getDirection() + JSON.stringify(element.item.uri) + JSON.stringify(element.item.range); + if (element.parent) { + res += this.getId(element.parent); + } + return res; } } class CallRenderingTemplate { constructor( - readonly iconLabel: IconLabel + readonly icon: HTMLDivElement, + readonly label: IconLabel ) { } } export class CallRenderer implements ITreeRenderer { - static id = 'CallRenderer'; + static readonly id = 'CallRenderer'; templateId: string = CallRenderer.id; renderTemplate(container: HTMLElement): CallRenderingTemplate { - const iconLabel = new IconLabel(container, { supportHighlights: true }); - return new CallRenderingTemplate(iconLabel); + dom.addClass(container, 'callhierarchy-element'); + let icon = document.createElement('div'); + container.appendChild(icon); + const label = new IconLabel(container, { supportHighlights: true }); + return new CallRenderingTemplate(icon, label); } renderElement(node: ITreeNode, _index: number, template: CallRenderingTemplate): void { const { element, filterData } = node; - - template.iconLabel.setLabel( + template.icon.className = SymbolKinds.toCssClassName(element.item.kind, true); + template.label.setLabel( element.item.name, element.item.detail, - { - labelEscapeNewLines: true, - matches: createMatches(filterData), - extraClasses: [symbolKindToCssClass(element.item.kind, true)] - } + { labelEscapeNewLines: true, matches: createMatches(filterData) } ); } disposeTemplate(template: CallRenderingTemplate): void { - template.iconLabel.dispose(); + template.label.dispose(); } } diff --git a/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css b/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css index ede412d0c4a..19c2e871295 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css +++ b/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css @@ -38,3 +38,14 @@ .monaco-workbench .call-hierarchy .tree { height: 100%; } + +.monaco-workbench .call-hierarchy .tree .callhierarchy-element { + display: flex; + flex: 1; + flex-flow: row nowrap; + align-items: center; +} + +.monaco-workbench .call-hierarchy .tree .callhierarchy-element .monaco-icon-label { + padding-left: 4px; +} diff --git a/src/vs/workbench/contrib/cli/node/cli.contribution.ts b/src/vs/workbench/contrib/cli/node/cli.contribution.ts index 7da113bc27f..b0dc1655169 100644 --- a/src/vs/workbench/contrib/cli/node/cli.contribution.ts +++ b/src/vs/workbench/contrib/cli/node/cli.contribution.ts @@ -41,7 +41,7 @@ function isAvailable(): Promise { class InstallAction extends Action { static readonly ID = 'workbench.action.installCommandLine'; - static LABEL = nls.localize('install', "Install '{0}' command in PATH", product.applicationName); + static readonly LABEL = nls.localize('install', "Install '{0}' command in PATH", product.applicationName); constructor( id: string, @@ -108,7 +108,7 @@ class InstallAction extends Action { promisify(cp.exec)(command, {}) .then(undefined, _ => Promise.reject(new Error(nls.localize('cantCreateBinFolder', "Unable to create '/usr/local/bin'.")))) - .then(resolve, reject); + .then(() => resolve(), reject); break; case 1 /* Cancel */: reject(new Error(nls.localize('aborted', "Aborted"))); @@ -122,7 +122,7 @@ class InstallAction extends Action { class UninstallAction extends Action { static readonly ID = 'workbench.action.uninstallCommandLine'; - static LABEL = nls.localize('uninstall', "Uninstall '{0}' command from PATH", product.applicationName); + static readonly LABEL = nls.localize('uninstall', "Uninstall '{0}' command from PATH", product.applicationName); constructor( id: string, @@ -175,7 +175,7 @@ class UninstallAction extends Action { promisify(cp.exec)(command, {}) .then(undefined, _ => Promise.reject(new Error(nls.localize('cantUninstall', "Unable to uninstall the shell command '{0}'.", this.target)))) - .then(resolve, reject); + .then(() => resolve(), reject); break; case 1 /* Cancel */: reject(new Error(nls.localize('aborted', "Aborted"))); diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css index 458b5b13ad0..8e6ddaf4512 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css @@ -6,4 +6,5 @@ .monaco-editor .accessibilityHelpWidget { padding: 10px; vertical-align: middle; -} \ No newline at end of file + overflow: auto; +} diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts index 4e2253b8731..85225bed6c1 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts @@ -35,7 +35,7 @@ const CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE = new RawContextKey('accessi class AccessibilityHelpController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.accessibilityHelpController'; + public static readonly ID = 'editor.contrib.accessibilityHelpController'; public static get(editor: ICodeEditor): AccessibilityHelpController { return editor.getContribution(AccessibilityHelpController.ID); @@ -54,10 +54,6 @@ class AccessibilityHelpController extends Disposable implements IEditorContribut this._widget = this._register(instantiationService.createInstance(AccessibilityHelpWidget, this._editor)); } - public getId(): string { - return AccessibilityHelpController.ID; - } - public show(): void { this._widget.show(); } @@ -267,11 +263,13 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { private _layout(): void { let editorLayout = this._editor.getLayoutInfo(); - let top = Math.round((editorLayout.height - AccessibilityHelpWidget.HEIGHT) / 2); - this._domNode.setTop(top); + const width = Math.min(editorLayout.width - 40, AccessibilityHelpWidget.WIDTH); + const height = Math.min(editorLayout.height - 40, AccessibilityHelpWidget.HEIGHT); - let left = Math.round((editorLayout.width - AccessibilityHelpWidget.WIDTH) / 2); - this._domNode.setLeft(left); + this._domNode.setTop(Math.round((editorLayout.height - height) / 2)); + this._domNode.setLeft(Math.round((editorLayout.width - width) / 2)); + this._domNode.setWidth(width); + this._domNode.setHeight(height); } } @@ -299,7 +297,7 @@ class ShowAccessibilityHelpAction extends EditorAction { } } -registerEditorContribution(AccessibilityHelpController); +registerEditorContribution(AccessibilityHelpController.ID, AccessibilityHelpController); registerEditorAction(ShowAccessibilityHelpAction); const AccessibilityHelpCommand = EditorCommand.bindToContribution(AccessibilityHelpController.get); diff --git a/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts b/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts index 39a4d1afe66..740449c991f 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts @@ -5,9 +5,9 @@ import './menuPreventer'; import './accessibility/accessibility'; +import './diffEditorHelper'; import './inspectKeybindings'; import './largeFileOptimizations'; -import './selectionClipboard'; import './inspectTMScopes/inspectTMScopes'; import './toggleMinimap'; import './toggleMultiCursorModifier'; diff --git a/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts b/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts new file mode 100644 index 00000000000..d01c06d5e59 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts @@ -0,0 +1,106 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; +import { registerDiffEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { IDiffEditorContribution } from 'vs/editor/common/editorCommon'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets'; +import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; + +const enum WidgetState { + Hidden, + HintWhitespace +} + +class DiffEditorHelperContribution extends Disposable implements IDiffEditorContribution { + + public static ID = 'editor.contrib.diffEditorHelper'; + + private _helperWidget: FloatingClickWidget | null; + private _helperWidgetListener: IDisposable | null; + private _state: WidgetState; + + constructor( + private readonly _diffEditor: IDiffEditor, + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @INotificationService private readonly _notificationService: INotificationService, + ) { + super(); + this._helperWidget = null; + this._helperWidgetListener = null; + this._state = WidgetState.Hidden; + + + this._register(this._diffEditor.onDidUpdateDiff(() => { + const diffComputationResult = this._diffEditor.getDiffComputationResult(); + this._setState(this._deduceState(diffComputationResult)); + + if (diffComputationResult && diffComputationResult.quitEarly) { + this._notificationService.prompt( + Severity.Warning, + nls.localize('hintTimeout', "The diff algorithm was stopped early (after {0} ms.)", this._diffEditor.maxComputationTime), + [{ + label: nls.localize('removeTimeout', "Remove limit"), + run: () => { + this._configurationService.updateValue('diffEditor.maxComputationTime', 0, ConfigurationTarget.USER); + } + }], + {} + ); + } + })); + } + + private _deduceState(diffComputationResult: IDiffComputationResult | null): WidgetState { + if (!diffComputationResult) { + return WidgetState.Hidden; + } + if (this._diffEditor.ignoreTrimWhitespace && diffComputationResult.changes.length === 0 && !diffComputationResult.identical) { + return WidgetState.HintWhitespace; + } + return WidgetState.Hidden; + } + + private _setState(newState: WidgetState) { + if (this._state === newState) { + return; + } + + this._state = newState; + + if (this._helperWidgetListener) { + this._helperWidgetListener.dispose(); + this._helperWidgetListener = null; + } + if (this._helperWidget) { + this._helperWidget.dispose(); + this._helperWidget = null; + } + + if (this._state === WidgetState.HintWhitespace) { + this._helperWidget = this._instantiationService.createInstance(FloatingClickWidget, this._diffEditor.getModifiedEditor(), nls.localize('hintWhitespace', "Show Whitespace Differences"), null); + this._helperWidgetListener = this._helperWidget.onClick(() => this._onDidClickHelperWidget()); + this._helperWidget.render(); + } + } + + private _onDidClickHelperWidget(): void { + if (this._state === WidgetState.HintWhitespace) { + this._configurationService.updateValue('diffEditor.ignoreTrimWhitespace', false, ConfigurationTarget.USER); + } + } + + dispose(): void { + super.dispose(); + } +} + +registerDiffEditorContribution(DiffEditorHelperContribution.ID, DiffEditorHelperContribution); diff --git a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts index 615a53aaad3..fbbf29cc24e 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/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, inputActiveOptionBackground, 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, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ContextScopedFindInput } from 'vs/platform/browser/contextScopedHistoryWidget'; @@ -280,6 +280,11 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-workbench .simple-find-part { background-color: ${findWidgetBGColor} !important; }`); } + const widgetForeground = theme.getColor(editorWidgetForeground); + if (widgetForeground) { + collector.addRule(`.monaco-workbench .simple-find-part { color: ${widgetForeground}; }`); + } + const widgetShadowColor = theme.getColor(widgetShadow); if (widgetShadowColor) { collector.addRule(`.monaco-workbench .simple-find-part { box-shadow: 0 2px 8px ${widgetShadowColor}; }`); diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.css b/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.css index 234ad747b75..a28c0560783 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.css +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.css @@ -6,6 +6,7 @@ .tm-inspect-widget { z-index: 50; user-select: text; + -webkit-user-select: text; padding: 10px; } diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts index c01b75c3cbb..aecdba4bd23 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts @@ -27,7 +27,7 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work class InspectTMScopesController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.inspectTMScopes'; + public static readonly ID = 'editor.contrib.inspectTMScopes'; public static get(editor: ICodeEditor): InspectTMScopesController { return editor.getContribution(InspectTMScopesController.ID); @@ -60,10 +60,6 @@ class InspectTMScopesController extends Disposable implements IEditorContributio this._register(this._editor.onKeyUp((e) => e.keyCode === KeyCode.Escape && this.stop())); } - public getId(): string { - return InspectTMScopesController.ID; - } - public dispose(): void { this.stop(); super.dispose(); @@ -374,7 +370,7 @@ class InspectTMScopesWidget extends Disposable implements IContentWidget { } } -registerEditorContribution(InspectTMScopesController); +registerEditorContribution(InspectTMScopesController.ID, InspectTMScopesController); registerEditorAction(InspectTMScopes); registerThemingParticipant((theme, collector) => { diff --git a/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts b/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts index 558d193d12a..69ee095045d 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { ParseError, parse } from 'vs/base/common/json'; +import { ParseError, parse, getNodeType } from 'vs/base/common/json'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; @@ -12,12 +12,12 @@ import { LanguageIdentifier } from 'vs/editor/common/modes'; import { CharacterPair, CommentRule, FoldingRules, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { IFileService } from 'vs/platform/files/common/files'; import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; interface IRegExp { pattern: string; @@ -69,7 +69,7 @@ export class LanguageConfigurationFileHandler { constructor( @ITextMateService textMateService: ITextMateService, @IModeService private readonly _modeService: IModeService, - @IFileService private readonly _fileService: IFileService, + @IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService, @IExtensionService private readonly _extensionService: IExtensionService ) { this._done = []; @@ -98,12 +98,16 @@ export class LanguageConfigurationFileHandler { } private _handleConfigFile(languageIdentifier: LanguageIdentifier, configFileLocation: URI): void { - this._fileService.readFile(configFileLocation).then((contents) => { + this._extensionResourceLoaderService.readExtensionResource(configFileLocation).then((contents) => { const errors: ParseError[] = []; - const configuration = parse(contents.value.toString(), errors); + let configuration = parse(contents, errors); if (errors.length) { console.error(nls.localize('parseErrors', "Errors parsing {0}: {1}", configFileLocation.toString(), errors.map(e => (`[${e.offset}, ${e.length}] ${getParseErrorMessage(e.error)}`)).join('\n'))); } + if (getNodeType(configuration) !== 'object') { + console.error(nls.localize('formatError', "{0}: Invalid format, JSON object expected.", configFileLocation.toString())); + configuration = {}; + } this._handleConfig(languageIdentifier, configuration); }, (err) => { console.error(err); diff --git a/src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts b/src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts index 551c3e4b86a..2febc613bf7 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts @@ -17,7 +17,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/ */ export class LargeFileOptimizationsWarner extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.largeFileOptimizationsWarner'; + public static readonly ID = 'editor.contrib.largeFileOptimizationsWarner'; constructor( private readonly _editor: ICodeEditor, @@ -60,10 +60,6 @@ export class LargeFileOptimizationsWarner extends Disposable implements IEditorC } })); } - - public getId(): string { - return LargeFileOptimizationsWarner.ID; - } } -registerEditorContribution(LargeFileOptimizationsWarner); +registerEditorContribution(LargeFileOptimizationsWarner.ID, LargeFileOptimizationsWarner); diff --git a/src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts b/src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts index 7d5845d3519..4e62cd2f4c0 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts @@ -14,7 +14,7 @@ import { IEditorContribution } from 'vs/editor/common/editorCommon'; */ export class MenuPreventer extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.menuPreventer'; + public static readonly ID = 'editor.contrib.menuPreventer'; private _editor: ICodeEditor; private _altListeningMouse: boolean; @@ -55,10 +55,6 @@ export class MenuPreventer extends Disposable implements IEditorContribution { } })); } - - public getId(): string { - return MenuPreventer.ID; - } } -registerEditorContribution(MenuPreventer); +registerEditorContribution(MenuPreventer.ID, MenuPreventer); diff --git a/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts index ebf9955db2a..38091423c74 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts @@ -3,114 +3,4 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { RunOnceScheduler } from 'vs/base/common/async'; -import { Disposable } from 'vs/base/common/lifecycle'; -import * as process from 'vs/base/common/process'; -import * as platform from 'vs/base/common/platform'; -import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; -import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; -import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; -import { Range } from 'vs/editor/common/core/range'; -import { IEditorContribution } from 'vs/editor/common/editorCommon'; -import { EndOfLinePreference } from 'vs/editor/common/model'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; - -export class SelectionClipboard extends Disposable implements IEditorContribution { - private static SELECTION_LENGTH_LIMIT = 65536; - private static readonly ID = 'editor.contrib.selectionClipboard'; - - constructor(editor: ICodeEditor, @IClipboardService clipboardService: IClipboardService) { - super(); - - if (platform.isLinux) { - let isEnabled = editor.getOption(EditorOption.selectionClipboard); - - this._register(editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { - if (e.hasChanged(EditorOption.selectionClipboard)) { - isEnabled = editor.getOption(EditorOption.selectionClipboard); - } - })); - - this._register(editor.onMouseDown((e: IEditorMouseEvent) => { - if (!isEnabled) { - return; - } - if (!editor.hasModel()) { - return; - } - if (e.event.middleButton) { - e.event.preventDefault(); - editor.focus(); - - if (e.target.position) { - editor.setPosition(e.target.position); - } - - if (e.target.type === MouseTargetType.SCROLLBAR) { - return; - } - - process.nextTick(() => { - // TODO@Alex: electron weirdness: calling clipboard.readText('selection') generates a paste event, so no need to execute paste ourselves - clipboardService.readText('selection'); - // keybindingService.executeCommand(Handler.Paste, { - // text: clipboard.readText('selection'), - // pasteOnNewLine: false - // }); - }); - } - })); - - let setSelectionToClipboard = this._register(new RunOnceScheduler(() => { - if (!editor.hasModel()) { - return; - } - let model = editor.getModel(); - let selections = editor.getSelections(); - selections = selections.slice(0); - selections.sort(Range.compareRangesUsingStarts); - - let resultLength = 0; - for (const sel of selections) { - if (sel.isEmpty()) { - // Only write if all cursors have selection - return; - } - resultLength += model.getValueLengthInRange(sel); - } - - if (resultLength > SelectionClipboard.SELECTION_LENGTH_LIMIT) { - // This is a large selection! - // => do not write it to the selection clipboard - return; - } - - let result: string[] = []; - for (const sel of selections) { - result.push(model.getValueInRange(sel, EndOfLinePreference.TextDefined)); - } - - let textToCopy = result.join(model.getEOL()); - clipboardService.writeText(textToCopy, 'selection'); - }, 100)); - - this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { - if (!isEnabled) { - return; - } - setSelectionToClipboard.schedule(); - })); - } - } - - public getId(): string { - return SelectionClipboard.ID; - } - - public dispose(): void { - super.dispose(); - } -} - -registerEditorContribution(SelectionClipboard); +export const SelectionClipboardContributionID = 'editor.contrib.selectionClipboard'; diff --git a/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts b/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts index 6b256e04a8c..ac40c376e27 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts @@ -9,8 +9,9 @@ import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; -import { SelectionClipboard } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; +import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; import { TabCompletionController } from 'vs/workbench/contrib/snippets/browser/tabCompletion'; +import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; export function getSimpleEditorOptions(): IEditorOptions { return { @@ -40,13 +41,13 @@ export function getSimpleEditorOptions(): IEditorOptions { export function getSimpleCodeEditorWidgetOptions(): ICodeEditorWidgetOptions { return { isSimpleWidget: true, - contributions: [ - MenuPreventer, - SelectionClipboard, - ContextMenuController, - SuggestController, - SnippetController2, - TabCompletionController, - ] + contributions: EditorExtensionsRegistry.getSomeEditorContributions([ + MenuPreventer.ID, + SelectionClipboardContributionID, + ContextMenuController.ID, + SuggestController.ID, + SnippetController2.ID, + TabCompletionController.ID, + ]) }; } diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css index 64e3705f051..c9512232cd3 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ .suggest-input-container { - padding: 3px 4px 5px; + padding: 4px; } .suggest-input-container .monaco-editor-background, diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index 2ce7aef85f7..bb6029252bf 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -31,7 +31,8 @@ import { IStyleOverrides, IThemable, attachStyler } from 'vs/platform/theme/comm import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; -import { SelectionClipboard } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; +import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; +import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; interface SuggestResultsProvider { /** @@ -130,7 +131,13 @@ export class SuggestEnabledInput extends Widget implements IThemable { this.inputWidget = instantiationService.createInstance(CodeEditorWidget, this.stylingContainer, editorOptions, { - contributions: [SuggestController, SnippetController2, ContextMenuController, MenuPreventer, SelectionClipboard], + contributions: EditorExtensionsRegistry.getSomeEditorContributions([ + SuggestController.ID, + SnippetController2.ID, + ContextMenuController.ID, + MenuPreventer.ID, + SelectionClipboardContributionID, + ]), isSimpleWidget: true, }); this._register(this.inputWidget); @@ -216,7 +223,7 @@ export class SuggestEnabledInput extends Widget implements IThemable { public style(colors: ISuggestEnabledInputStyles): void { - this.stylingContainer.style.backgroundColor = colors.inputBackground ? colors.inputBackground.toString() : null; + this.stylingContainer.style.backgroundColor = colors.inputBackground ? colors.inputBackground.toString() : ''; this.stylingContainer.style.color = colors.inputForeground ? colors.inputForeground.toString() : null; this.placeholderText.style.color = colors.inputPlaceholderForeground ? colors.inputPlaceholderForeground.toString() : null; @@ -228,7 +235,7 @@ export class SuggestEnabledInput extends Widget implements IThemable { const cursor = this.stylingContainer.getElementsByClassName('cursor')[0] as HTMLDivElement; if (cursor) { - cursor.style.backgroundColor = colors.inputForeground ? colors.inputForeground.toString() : null; + cursor.style.backgroundColor = colors.inputForeground ? colors.inputForeground.toString() : ''; } } @@ -290,6 +297,7 @@ function getSuggestEnabledInputOptions(ariaLabel?: string): IEditorOptions { ariaLabel: ariaLabel || '', snippetSuggestions: 'none', - suggest: { filterGraceful: false, showIcons: false } + suggest: { filterGraceful: false, showIcons: false }, + autoClosingBrackets: 'never' }; } diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index f5abc1078ce..29f6839f84b 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -166,7 +166,7 @@ class ToggleWordWrapAction extends EditorAction { class ToggleWordWrapController extends Disposable implements IEditorContribution { - private static readonly _ID = 'editor.contrib.toggleWordWrapController'; + public static readonly ID = 'editor.contrib.toggleWordWrapController'; constructor( private readonly editor: ICodeEditor, @@ -254,10 +254,6 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution wordWrapMinified: state.configuredWordWrapMinified }); } - - public getId(): string { - return ToggleWordWrapController._ID; - } } function canToggleWordWrap(uri: URI): boolean { @@ -268,7 +264,7 @@ function canToggleWordWrap(uri: URI): boolean { } -registerEditorContribution(ToggleWordWrapController); +registerEditorContribution(ToggleWordWrapController.ID, ToggleWordWrapController); registerEditorAction(ToggleWordWrapAction); diff --git a/src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts b/src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts index 6e3236ffa27..a38a3245b03 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts @@ -37,4 +37,4 @@ export class WorkbenchReferencesController extends ReferencesController { } } -registerEditorContribution(WorkbenchReferencesController); +registerEditorContribution(ReferencesController.ID, WorkbenchReferencesController); diff --git a/src/vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution.ts index 4c11f23fc72..a2f03ae3e24 100644 --- a/src/vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution.ts +++ b/src/vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution.ts @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import './inputClipboardActions'; import './sleepResumeRepaintMinimap'; +import './selectionClipboard'; diff --git a/src/vs/workbench/contrib/codeEditor/electron-browser/inputClipboardActions.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/inputClipboardActions.ts new file mode 100644 index 00000000000..b4755e97300 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/electron-browser/inputClipboardActions.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import * as platform from 'vs/base/common/platform'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; + +if (platform.isMacintosh) { + + // On the mac, cmd+x, cmd+c and cmd+v do not result in cut / copy / paste + // We therefore add a basic keybinding rule that invokes document.execCommand + // This is to cover s... + + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'execCut', + primary: KeyMod.CtrlCmd | KeyCode.KEY_X, + handler: bindExecuteCommand('cut'), + weight: 0, + when: undefined, + }); + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'execCopy', + primary: KeyMod.CtrlCmd | KeyCode.KEY_C, + handler: bindExecuteCommand('copy'), + weight: 0, + when: undefined, + }); + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'execPaste', + primary: KeyMod.CtrlCmd | KeyCode.KEY_V, + handler: bindExecuteCommand('paste'), + weight: 0, + when: undefined, + }); + + function bindExecuteCommand(command: 'cut' | 'copy' | 'paste') { + return () => { + document.execCommand(command); + }; + } +} diff --git a/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts new file mode 100644 index 00000000000..65b603080a4 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts @@ -0,0 +1,111 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { RunOnceScheduler } from 'vs/base/common/async'; +import { Disposable } from 'vs/base/common/lifecycle'; +import * as platform from 'vs/base/common/platform'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; +import { Range } from 'vs/editor/common/core/range'; +import { IEditorContribution } from 'vs/editor/common/editorCommon'; +import { EndOfLinePreference } from 'vs/editor/common/model'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +export class SelectionClipboard extends Disposable implements IEditorContribution { + private static readonly SELECTION_LENGTH_LIMIT = 65536; + + constructor(editor: ICodeEditor, @IClipboardService clipboardService: IClipboardService) { + super(); + + if (platform.isLinux) { + let isEnabled = editor.getOption(EditorOption.selectionClipboard); + + this._register(editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.selectionClipboard)) { + isEnabled = editor.getOption(EditorOption.selectionClipboard); + } + })); + + let setSelectionToClipboard = this._register(new RunOnceScheduler(() => { + if (!editor.hasModel()) { + return; + } + let model = editor.getModel(); + let selections = editor.getSelections(); + selections = selections.slice(0); + selections.sort(Range.compareRangesUsingStarts); + + let resultLength = 0; + for (const sel of selections) { + if (sel.isEmpty()) { + // Only write if all cursors have selection + return; + } + resultLength += model.getValueLengthInRange(sel); + } + + if (resultLength > SelectionClipboard.SELECTION_LENGTH_LIMIT) { + // This is a large selection! + // => do not write it to the selection clipboard + return; + } + + let result: string[] = []; + for (const sel of selections) { + result.push(model.getValueInRange(sel, EndOfLinePreference.TextDefined)); + } + + let textToCopy = result.join(model.getEOL()); + clipboardService.writeText(textToCopy, 'selection'); + }, 100)); + + this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => { + if (!isEnabled) { + return; + } + if (e.source === 'restoreState') { + // do not set selection to clipboard if this selection change + // was caused by restoring editors... + return; + } + setSelectionToClipboard.schedule(); + })); + } + } + + public dispose(): void { + super.dispose(); + } +} + +class SelectionClipboardPastePreventer implements IWorkbenchContribution { + constructor( + @IConfigurationService configurationService: IConfigurationService + ) { + if (platform.isLinux) { + document.addEventListener('mouseup', (e) => { + if (e.button === 1) { + // middle button + const config = configurationService.getValue<{ selectionClipboard: boolean; }>('editor'); + if (!config.selectionClipboard) { + // selection clipboard is disabled + // try to stop the upcoming paste + e.preventDefault(); + } + } + }); + } + } +} + +registerEditorContribution(SelectionClipboardContributionID, SelectionClipboard); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(SelectionClipboardPastePreventer, LifecyclePhase.Ready); diff --git a/src/vs/workbench/contrib/comments/browser/commentMenus.ts b/src/vs/workbench/contrib/comments/browser/commentMenus.ts index 7494c2e6277..9ac56e09797 100644 --- a/src/vs/workbench/contrib/comments/browser/commentMenus.ts +++ b/src/vs/workbench/contrib/comments/browser/commentMenus.ts @@ -7,22 +7,15 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; import { IAction } from 'vs/base/common/actions'; -import { MainThreadCommentController } from 'vs/workbench/api/browser/mainThreadComments'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { Comment, CommentThread } from 'vs/editor/common/modes'; import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; export class CommentMenus implements IDisposable { constructor( - controller: MainThreadCommentController, - @IContextKeyService private contextKeyService: IContextKeyService, @IMenuService private readonly menuService: IMenuService, @IContextMenuService private readonly contextMenuService: IContextMenuService - ) { - const commentControllerKey = this.contextKeyService.createKey('commentController', undefined); - - commentControllerKey.set(controller.contextValue); - } + ) { } getCommentThreadTitleActions(commentThread: CommentThread, contextKeyService: IContextKeyService): IMenu { return this.getMenu(MenuId.CommentThreadTitle, contextKeyService); diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index e6d891f2e4f..fbdfdab2e22 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -57,7 +57,7 @@ export class CommentNode extends Disposable { protected toolbar: ToolBar | undefined; private _commentFormActions: CommentFormActions | null = null; - private readonly _onDidDelete = new Emitter(); + private readonly _onDidClick = new Emitter(); public get domNode(): HTMLElement { return this._domNode; @@ -89,7 +89,7 @@ export class CommentNode extends Disposable { this._contextKeyService = contextKeyService.createScoped(this._domNode); this._commentContextValue = this._contextKeyService.createKey('comment', comment.contextValue); - this._domNode.tabIndex = 0; + this._domNode.tabIndex = -1; const avatar = dom.append(this._domNode, dom.$('div.avatar-container')); if (comment.userIconPath) { const img = dom.append(avatar, dom.$('img.avatar')); @@ -111,10 +111,12 @@ export class CommentNode extends Disposable { this._domNode.setAttribute('aria-label', `${comment.userName}, ${comment.body.value}`); this._domNode.setAttribute('role', 'treeitem'); this._clearTimeout = null; + + this._register(dom.addDisposableListener(this._domNode, dom.EventType.CLICK, () => this.isEditing || this._onDidClick.fire(this))); } - public get onDidDelete(): Event { - return this._onDidDelete.event; + public get onDidClick(): Event { + return this._onDidClick.event; } private createHeader(commentDetailsContainer: HTMLElement): void { @@ -430,19 +432,31 @@ export class CommentNode extends Disposable { this._commentFormActions.setActions(menu); } + setFocus(focused: boolean, visible: boolean = false) { + if (focused) { + this._domNode.focus(); + this._actionsToolbarContainer.classList.remove('hidden'); + this._actionsToolbarContainer.classList.add('tabfocused'); + this._domNode.tabIndex = 0; + } else { + if (this._actionsToolbarContainer.classList.contains('tabfocused') && !this._actionsToolbarContainer.classList.contains('mouseover')) { + this._actionsToolbarContainer.classList.add('hidden'); + this._domNode.tabIndex = -1; + } + this._actionsToolbarContainer.classList.remove('tabfocused'); + } + } + private registerActionBarListeners(actionsContainer: HTMLElement): void { this._register(dom.addDisposableListener(this._domNode, 'mouseenter', () => { actionsContainer.classList.remove('hidden'); + actionsContainer.classList.add('mouseover'); })); - - this._register(dom.addDisposableListener(this._domNode, 'focus', () => { - actionsContainer.classList.remove('hidden'); - })); - this._register(dom.addDisposableListener(this._domNode, 'mouseleave', () => { - if (!this._domNode.contains(document.activeElement)) { + if (actionsContainer.classList.contains('mouseover') && !actionsContainer.classList.contains('tabfocused')) { actionsContainer.classList.add('hidden'); } + actionsContainer.classList.remove('mouseover'); })); } diff --git a/src/vs/workbench/contrib/comments/browser/commentService.ts b/src/vs/workbench/contrib/comments/browser/commentService.ts index 29587a0e7d0..56bae5b2001 100644 --- a/src/vs/workbench/contrib/comments/browser/commentService.ts +++ b/src/vs/workbench/contrib/comments/browser/commentService.ts @@ -160,9 +160,7 @@ export class CommentService extends Disposable implements ICommentService { return this._commentMenus.get(owner)!; } - let controller = this._commentControls.get(owner); - - let menu = this.instantiationService.createInstance(CommentMenus, controller!); + let menu = this.instantiationService.createInstance(CommentMenus); this._commentMenus.set(owner, menu); return menu; } diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index 09438e54175..8a2d723991a 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -45,6 +45,9 @@ import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/comment import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget'; import { SimpleCommentEditor } from './simpleCommentEditor'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration'; const COLLAPSE_ACTION_CLASS = 'expand-review-action'; @@ -54,21 +57,21 @@ const COMMENT_SCHEME = 'comment'; let INMEM_MODEL_ID = 0; export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget { - private _headElement: HTMLElement; - protected _headingLabel: HTMLElement; - protected _actionbarWidget: ActionBar; - private _bodyElement: HTMLElement; + private _headElement!: HTMLElement; + protected _headingLabel!: HTMLElement; + protected _actionbarWidget!: ActionBar; + private _bodyElement!: HTMLElement; private _parentEditor: ICodeEditor; - private _commentEditor: ICodeEditor; - private _commentsElement: HTMLElement; - private _commentElements: CommentNode[]; - private _commentForm: HTMLElement; - private _reviewThreadReplyButton: HTMLElement; + private _commentEditor!: ICodeEditor; + private _commentsElement!: HTMLElement; + private _commentElements: CommentNode[] = []; + private _commentForm!: HTMLElement; + private _reviewThreadReplyButton!: HTMLElement; private _resizeObserver: any; private readonly _onDidClose = new Emitter(); private readonly _onDidCreateThread = new Emitter(); private _isExpanded?: boolean; - private _collapseAction: Action; + private _collapseAction!: Action; private _commentGlyph?: CommentGlyphWidget; private _submitActionsDisposables: IDisposable[]; private readonly _globalToDispose = new DisposableStore(); @@ -76,12 +79,14 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget private _markdownRenderer: MarkdownRenderer; private _styleElement: HTMLStyleElement; private _formActions: HTMLElement | null; - private _error: HTMLElement; + private _error!: HTMLElement; private _contextKeyService: IContextKeyService; private _threadIsEmpty: IContextKey; private _commentThreadContextValue: IContextKey; - private _commentEditorIsEmpty: IContextKey; - private _commentFormActions: CommentFormActions; + private _commentEditorIsEmpty!: IContextKey; + private _commentFormActions!: CommentFormActions; + private _scopedInstatiationService: IInstantiationService; + private _focusedComment: number | undefined = undefined; public get owner(): string { return this._owner; @@ -100,8 +105,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget editor: ICodeEditor, private _owner: string, private _commentThread: modes.CommentThread, - private _pendingComment: string, - @IInstantiationService private instantiationService: IInstantiationService, + private _pendingComment: string | null, + @IInstantiationService instantiationService: IInstantiationService, @IModeService private modeService: IModeService, @IModelService private modelService: IModelService, @IThemeService private themeService: IThemeService, @@ -114,10 +119,22 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget ) { super(editor, { keepEditorSelection: true }); this._contextKeyService = contextKeyService.createScoped(this.domNode); + + this._scopedInstatiationService = instantiationService.createChild(new ServiceCollection( + [IContextKeyService, this._contextKeyService] + )); + this._threadIsEmpty = CommentContextKeys.commentThreadIsEmpty.bindTo(this._contextKeyService); this._threadIsEmpty.set(!_commentThread.comments || !_commentThread.comments.length); this._commentThreadContextValue = this._contextKeyService.createKey('commentThread', _commentThread.contextValue); + const commentControllerKey = this._contextKeyService.createKey('commentController', undefined); + const controller = this.commentService.getCommentController(this._owner); + + if (controller) { + commentControllerKey.set(controller.contextValue); + } + this._resizeObserver = null; this._isExpanded = _commentThread.collapsibleState === modes.CommentThreadCollapsibleState.Expanded; this._commentThreadDisposables = []; @@ -254,6 +271,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } public collapse(): Promise { + this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Collapsed; if (this._commentThread.comments && this._commentThread.comments.length === 0) { this.deleteCommentThread(); return Promise.resolve(); @@ -272,11 +290,13 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget toggleExpand(lineNumber: number) { if (this._isExpanded) { + this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Collapsed; this.hide(); if (!this._commentThread.comments || !this._commentThread.comments.length) { this.deleteCommentThread(); } } else { + this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded; this.show({ lineNumber: lineNumber, column: 1 }, 2); } } @@ -332,12 +352,6 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._commentElements = newCommentNodeList; this.createThreadLabel(); - if (this._formActions && this._commentEditor.hasModel()) { - dom.clearNode(this._formActions); - const model = this._commentEditor.getModel(); - this.createCommentWidgetActions(this._formActions, model); - } - // Move comment glyph widget and show position if the line has changed. const lineNumber = this._commentThread.range.startLineNumber; let shouldMoveWidget = false; @@ -371,6 +385,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } else { this._commentThreadContextValue.reset(); } + + this.setFocusedComment(this._focusedComment); } protected _onWidth(widthInPixel: number): void { @@ -393,6 +409,21 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._commentsElement = dom.append(this._bodyElement, dom.$('div.comments-container')); this._commentsElement.setAttribute('role', 'presentation'); + this._commentsElement.tabIndex = 0; + + this._disposables.add(dom.addDisposableListener(this._commentsElement, dom.EventType.KEY_DOWN, (e) => { + let event = new StandardKeyboardEvent(e as KeyboardEvent); + if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.DownArrow)) { + const moveFocusWithinBounds = (change: number): number => { + if (this._focusedComment === undefined && change >= 0) { return 0; } + if (this._focusedComment === undefined && change < 0) { return this._commentElements.length - 1; } + let newIndex = this._focusedComment! + change; + return Math.min(Math.max(0, newIndex), this._commentElements.length - 1); + }; + + this.setFocusedComment(event.equals(KeyCode.UpArrow) ? moveFocusWithinBounds(-1) : moveFocusWithinBounds(1)); + } + })); this._commentElements = []; if (this._commentThread.comments) { @@ -406,7 +437,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const hasExistingComments = this._commentThread.comments && this._commentThread.comments.length > 0; this._commentForm = dom.append(this._bodyElement, dom.$('.comment-form')); - this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, this._commentForm, SimpleCommentEditor.getEditorOptions(), this._parentEditor, this); + this._commentEditor = this._scopedInstatiationService.createInstance(SimpleCommentEditor, this._commentForm, SimpleCommentEditor.getEditorOptions(), this._parentEditor, this); this._commentEditorIsEmpty = CommentContextKeys.commentIsEmpty.bindTo(this._contextKeyService); this._commentEditorIsEmpty.set(!this._pendingComment); @@ -557,6 +588,19 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget })); } + private setFocusedComment(value: number | undefined) { + if (this._focusedComment !== undefined) { + this._commentElements[this._focusedComment]?.setFocus(false); + } + + if (this._commentElements.length === 0 || value === undefined) { + this._focusedComment = undefined; + } else { + this._focusedComment = Math.min(value, this._commentElements.length - 1); + this._commentElements[this._focusedComment].setFocus(true); + } + } + private getActiveComment(): CommentNode | ReviewZoneWidget { return this._commentElements.filter(node => node.isEditing)[0] || this; } @@ -595,7 +639,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } private createNewCommentNode(comment: modes.Comment): CommentNode { - let newCommentNode = this.instantiationService.createInstance(CommentNode, + let newCommentNode = this._scopedInstatiationService.createInstance(CommentNode, this._commentThread, comment, this.owner, @@ -605,25 +649,9 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._markdownRenderer); this._disposables.add(newCommentNode); - this._disposables.add(newCommentNode.onDidDelete(deletedNode => { - const deletedNodeId = deletedNode.comment.uniqueIdInThread; - const deletedElementIndex = arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.uniqueIdInThread === deletedNodeId); - if (deletedElementIndex > -1) { - this._commentElements.splice(deletedElementIndex, 1); - } - - const deletedCommentIndex = arrays.firstIndex(this._commentThread.comments!, comment => comment.uniqueIdInThread === deletedNodeId); - if (deletedCommentIndex > -1) { - this._commentThread.comments!.splice(deletedCommentIndex, 1); - } - - this._commentsElement.removeChild(deletedNode.domNode); - deletedNode.dispose(); - - if (this._commentThread.comments!.length === 0) { - this.dispose(); - } - })); + this._disposables.add(newCommentNode.onDidClick(clickedNode => + this.setFocusedComment(arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.uniqueIdInThread === clickedNode.comment.uniqueIdInThread)) + )); return newCommentNode; } @@ -739,7 +767,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } } - private mouseDownInfo: { lineNumber: number } | null; + private mouseDownInfo: { lineNumber: number } | null = null; private onEditorMouseDown(e: IEditorMouseEvent): void { this.mouseDownInfo = null; diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index bd3ea6d7f9d..6bd03c670c1 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -76,10 +76,7 @@ class CommentingRangeDecoration { options: commentingOptions }]; - let model = this._editor.getModel(); - if (model) { - this._decorationId = model.deltaDecorations([this._decorationId], commentingRangeDecorations)[0]; - } + this._decorationId = this._editor.deltaDecorations([], commentingRangeDecorations)[0]; } public getCommentAction(): { ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges } { @@ -149,20 +146,20 @@ class CommentingRangeDecorator { } } -export class ReviewController implements IEditorContribution { +export class CommentController implements IEditorContribution { private readonly globalToDispose = new DisposableStore(); private readonly localToDispose = new DisposableStore(); - private editor: ICodeEditor; + private editor!: ICodeEditor; private _commentWidgets: ReviewZoneWidget[]; private _commentInfos: ICommentInfo[]; - private _commentingRangeDecorator: CommentingRangeDecorator; + private _commentingRangeDecorator!: CommentingRangeDecorator; private mouseDownInfo: { lineNumber: number } | null = null; private _commentingRangeSpaceReserved = false; private _computePromise: CancelablePromise> | null; - private _addInProgress: boolean; + private _addInProgress!: boolean; private _emptyThreadsToAddQueue: [number, IEditorMouseEvent | undefined][] = []; - private _computeCommentingRangePromise: CancelablePromise | null; - private _computeCommentingRangeScheduler: Delayer> | null; + private _computeCommentingRangePromise!: CancelablePromise | null; + private _computeCommentingRangeScheduler!: Delayer> | null; private _pendingCommentCache: { [key: string]: { [key: string]: string } }; constructor( @@ -246,8 +243,8 @@ export class ReviewController implements IEditorContribution { } } - public static get(editor: ICodeEditor): ReviewController { - return editor.getContribution(ID); + public static get(editor: ICodeEditor): CommentController { + return editor.getContribution(ID); } public revealCommentThread(threadId: string, commentUniqueId: number, fetchOnceIfNotExist: boolean): void { @@ -317,10 +314,6 @@ export class ReviewController implements IEditorContribution { } } - public getId(): string { - return ID; - } - public dispose(): void { this.globalToDispose.dispose(); this.localToDispose.dispose(); @@ -689,7 +682,7 @@ export class NextCommentThreadAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - let controller = ReviewController.get(editor); + let controller = CommentController.get(editor); if (controller) { controller.nextCommentThread(); } @@ -697,7 +690,7 @@ export class NextCommentThreadAction extends EditorAction { } -registerEditorContribution(ReviewController); +registerEditorContribution(ID, CommentController); registerEditorAction(NextCommentThreadAction); CommandsRegistry.registerCommand({ @@ -708,7 +701,7 @@ CommandsRegistry.registerCommand({ return Promise.resolve(); } - const controller = ReviewController.get(activeEditor); + const controller = CommentController.get(activeEditor); if (!controller) { return Promise.resolve(); } diff --git a/src/vs/workbench/contrib/comments/browser/commentsPanel.ts b/src/vs/workbench/contrib/comments/browser/commentsPanel.ts index 5f0e33758a4..032ea879260 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsPanel.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsPanel.ts @@ -15,7 +15,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Panel } from 'vs/workbench/browser/panel'; import { CommentNode, CommentsModel, ResourceWithCommentThreads, ICommentThreadChangedEvent } from 'vs/workbench/contrib/comments/common/commentModel'; -import { ReviewController } from 'vs/workbench/contrib/comments/browser/commentsEditorContribution'; +import { CommentController } from 'vs/workbench/contrib/comments/browser/commentsEditorContribution'; import { ICommentService, IWorkspaceCommentThreadsEvent } from 'vs/workbench/contrib/comments/browser/commentService'; import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -27,13 +27,13 @@ import { CommentsList, COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbe export class CommentsPanel extends Panel { - private treeLabels: ResourceLabels; - private tree: CommentsList; - private treeContainer: HTMLElement; - private messageBoxContainer: HTMLElement; - private messageBox: HTMLElement; - private commentsModel: CommentsModel; - private collapseAllAction: IAction; + private treeLabels!: ResourceLabels; + private tree!: CommentsList; + private treeContainer!: HTMLElement; + private messageBoxContainer!: HTMLElement; + private messageBox!: HTMLElement; + private commentsModel!: CommentsModel; + private collapseAllAction?: IAction; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -163,7 +163,7 @@ export class CommentsPanel extends Panel { const commentToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].comment.uniqueIdInThread : element.comment.uniqueIdInThread; const control = this.editorService.activeTextEditorWidget; if (threadToReveal && isCodeEditor(control)) { - const controller = ReviewController.get(control); + const controller = CommentController.get(control); controller.revealCommentThread(threadToReveal, commentToReveal, false); } @@ -184,7 +184,7 @@ export class CommentsPanel extends Panel { if (editor) { const control = editor.getControl(); if (threadToReveal && isCodeEditor(control)) { - const controller = ReviewController.get(control); + const controller = CommentController.get(control); controller.revealCommentThread(threadToReveal, commentToReveal.uniqueIdInThread, true); } } @@ -195,7 +195,9 @@ export class CommentsPanel extends Panel { private refresh(): void { if (this.isVisible()) { - this.collapseAllAction.enabled = this.commentsModel.hasCommentThreads(); + if (this.collapseAllAction) { + this.collapseAllAction.enabled = this.commentsModel.hasCommentThreads(); + } dom.toggleClass(this.treeContainer, 'hidden', !this.commentsModel.hasCommentThreads()); this.tree.updateChildren().then(() => { diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts index 4cdcb6a6895..299a7271b2b 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -56,8 +56,8 @@ interface ICommentThreadTemplateData { } export class CommentsModelVirualDelegate implements IListVirtualDelegate { - private static RESOURCE_ID = 'resource-with-comments'; - private static COMMENT_ID = 'comment-node'; + private static readonly RESOURCE_ID = 'resource-with-comments'; + private static readonly COMMENT_ID = 'comment-node'; getHeight(element: any): number { diff --git a/src/vs/workbench/contrib/comments/browser/media/review.css b/src/vs/workbench/contrib/comments/browser/media/review.css index 12c14a8ce2f..444a8035088 100644 --- a/src/vs/workbench/contrib/comments/browser/media/review.css +++ b/src/vs/workbench/contrib/comments/browser/media/review.css @@ -34,7 +34,7 @@ width: 100%; } -.monaco-editor .review-widget .body .review-comment .comment-title .action-label.octicon { +.monaco-editor .review-widget .body .review-comment .comment-title .action-label.codicon { line-height: 18px; } @@ -78,6 +78,7 @@ .monaco-editor .review-widget .body .review-comment .review-comment-contents { padding-left: 20px; user-select: text; + -webkit-user-select: text; width: 100%; overflow: hidden; } @@ -134,6 +135,7 @@ width: 16px; height: 12px; -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; display: inline-block; margin-top: 3px; margin-right: 4px; @@ -274,10 +276,6 @@ text-align: left; width: 100%; box-sizing: border-box; - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; padding: 0.4em; font-size: 12px; line-height: 17px; @@ -362,10 +360,6 @@ } .monaco-editor .review-widget .head { - -webkit-box-sizing: border-box; - -o-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; box-sizing: border-box; display: flex; height: 100%; @@ -413,7 +407,7 @@ background-position: center center; } -.monaco-editor .review-widget .head .review-actions > .monaco-action-bar .action-label.octicon { +.monaco-editor .review-widget .head .review-actions > .monaco-action-bar .action-label.codicon { margin: 0; } diff --git a/src/vs/workbench/contrib/comments/browser/reactionsAction.ts b/src/vs/workbench/contrib/comments/browser/reactionsAction.ts index a06e6ce4017..a5ae07ec17f 100644 --- a/src/vs/workbench/contrib/comments/browser/reactionsAction.ts +++ b/src/vs/workbench/contrib/comments/browser/reactionsAction.ts @@ -33,6 +33,10 @@ export class ReactionActionViewItem extends ActionViewItem { super(null, action, {}); } updateLabel(): void { + if (!this.label) { + return; + } + let action = this.getAction() as ReactionAction; if (action.class) { this.label.classList.add(action.class); diff --git a/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts b/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts index 12a7897fec6..7cd39297216 100644 --- a/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts +++ b/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts @@ -47,12 +47,13 @@ export class SimpleCommentEditor extends CodeEditorWidget { @IAccessibilityService accessibilityService: IAccessibilityService ) { const codeEditorWidgetOptions = { + isSimpleWidget: true, contributions: [ - MenuPreventer, - ContextMenuController, - SuggestController, - SnippetController2, - TabCompletionController, + { id: MenuPreventer.ID, ctor: MenuPreventer }, + { id: ContextMenuController.ID, ctor: ContextMenuController }, + { id: SuggestController.ID, ctor: SuggestController }, + { id: SnippetController2.ID, ctor: SnippetController2 }, + { id: TabCompletionController.ID, ctor: TabCompletionController }, ] }; diff --git a/src/vs/workbench/contrib/configExporter/node/configurationExportHelper.contribution.ts b/src/vs/workbench/contrib/configExporter/node/configurationExportHelper.contribution.ts new file mode 100644 index 00000000000..503f8a83d5a --- /dev/null +++ b/src/vs/workbench/contrib/configExporter/node/configurationExportHelper.contribution.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 { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { DefaultConfigurationExportHelper } from 'vs/workbench/contrib/configExporter/node/configurationExportHelper'; + +export class ExtensionPoints implements IWorkbenchContribution { + + constructor( + @IInstantiationService instantiationService: IInstantiationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService + ) { + // Config Exporter + if (environmentService.configuration['export-default-configuration']) { + instantiationService.createInstance(DefaultConfigurationExportHelper); + } + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExtensionPoints, LifecyclePhase.Restored); diff --git a/src/vs/workbench/services/configuration/node/configurationExportHelper.ts b/src/vs/workbench/contrib/configExporter/node/configurationExportHelper.ts similarity index 100% rename from src/vs/workbench/services/configuration/node/configurationExportHelper.ts rename to src/vs/workbench/contrib/configExporter/node/configurationExportHelper.ts diff --git a/src/vs/workbench/contrib/customEditor/browser/commands.ts b/src/vs/workbench/contrib/customEditor/browser/commands.ts index 9137385cc80..996aa3ceb7e 100644 --- a/src/vs/workbench/contrib/customEditor/browser/commands.ts +++ b/src/vs/workbench/contrib/customEditor/browser/commands.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Schemas } from 'vs/base/common/network'; +import { firstOrDefault } from 'vs/base/common/arrays'; import { URI } from 'vs/base/common/uri'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import * as nls from 'vs/nls'; @@ -12,19 +12,17 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IListService } from 'vs/platform/list/browser/listService'; import { IEditorCommandsContext } from 'vs/workbench/common/editor'; -import { ResourceContextKey } from 'vs/workbench/common/resources'; -import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { ICustomEditorService, CONTEXT_HAS_CUSTOM_EDITORS } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { firstOrDefault } from 'vs/base/common/arrays'; const viewCategory = nls.localize('viewCategory', "View"); // #region Open With const OPEN_WITH_COMMAND_ID = 'openWith'; -const OPEN_WITH_TITLE = { value: nls.localize('openWith.title', 'Open With'), original: 'Open With' }; +// const OPEN_WITH_TITLE = { value: nls.localize('openWith.title', 'Open With'), original: 'Open With' }; KeybindingsRegistry.registerCommandAndKeybindingRule({ id: OPEN_WITH_COMMAND_ID, @@ -41,15 +39,15 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { - group: 'navigation', - order: 20, - command: { - id: OPEN_WITH_COMMAND_ID, - title: OPEN_WITH_TITLE, - }, - when: ResourceContextKey.Scheme.isEqualTo(Schemas.file) -}); +// MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { +// group: 'navigation', +// order: 20, +// command: { +// id: OPEN_WITH_COMMAND_ID, +// title: OPEN_WITH_TITLE, +// }, +// when: ResourceContextKey.Scheme.isEqualTo(Schemas.file) +// }); // #endregion @@ -95,7 +93,8 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { id: REOPEN_WITH_COMMAND_ID, title: REOPEN_WITH_TITLE, category: viewCategory, - } + }, + when: CONTEXT_HAS_CUSTOM_EDITORS, }); // #endregion diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index 2a5c59429a3..24a42571e89 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -4,41 +4,34 @@ *--------------------------------------------------------------------------------------------*/ import { memoize } from 'vs/base/common/decorators'; -import { Emitter } from 'vs/base/common/event'; +import { Lazy } from 'vs/base/common/lazy'; import { UnownedDisposable } from 'vs/base/common/lifecycle'; +import { Schemas } from 'vs/base/common/network'; import { basename } from 'vs/base/common/path'; +import { DataUri, isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import { WebviewEditorState } from 'vs/editor/common/modes'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IEditorModel } from 'vs/platform/editor/common/editor'; import { ILabelService } from 'vs/platform/label/common/label'; -import { ConfirmResult, IEditorInput, Verbosity } from 'vs/workbench/common/editor'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview'; -import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; -import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { promptSave } from 'vs/workbench/services/textfile/browser/textFileService'; +import { IWebviewWorkbenchService, LazilyResolvedWebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService'; -export class CustomFileEditorInput extends WebviewInput { +export class CustomFileEditorInput extends LazilyResolvedWebviewEditorInput { public static typeId = 'workbench.editors.webviewEditor'; - private name?: string; - private _hasResolved = false; private readonly _editorResource: URI; - private _state = WebviewEditorState.Readonly; constructor( resource: URI, viewType: string, id: string, - webview: UnownedDisposable, + webview: Lazy>, + @ILifecycleService lifecycleService: ILifecycleService, + @IWebviewWorkbenchService webviewWorkbenchService: IWebviewWorkbenchService, @ILabelService private readonly labelService: ILabelService, - @IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService, - @IExtensionService private readonly _extensionService: IExtensionService, - @IDialogService private readonly dialogService: IDialogService, ) { - super(id, viewType, '', undefined, webview); + super(id, viewType, '', webview, webviewWorkbenchService, lifecycleService); this._editorResource = resource; } @@ -50,17 +43,34 @@ export class CustomFileEditorInput extends WebviewInput { return this._editorResource; } + @memoize getName(): string { - if (!this.name) { - this.name = basename(this.labelService.getUriLabel(this.getResource())); + if (this.getResource().scheme === Schemas.data) { + const metadata = DataUri.parseMetaData(this.getResource()); + const label = metadata.get(DataUri.META_DATA_LABEL); + if (typeof label === 'string') { + return label; + } } - return this.name; + return basename(this.labelService.getUriLabel(this.getResource())); + } + + @memoize + getDescription(): string | undefined { + if (this.getResource().scheme === Schemas.data) { + const metadata = DataUri.parseMetaData(this.getResource()); + const description = metadata.get(DataUri.META_DATA_DESCRIPTION); + if (typeof description === 'string') { + return description; + } + } + return super.getDescription(); } matches(other: IEditorInput): boolean { return this === other || (other instanceof CustomFileEditorInput && this.viewType === other.viewType - && this.getResource().toString() === other.getResource().toString()); + && isEqual(this.getResource(), other.getResource())); } @memoize @@ -70,11 +80,17 @@ export class CustomFileEditorInput extends WebviewInput { @memoize private get mediumTitle(): string { + if (this.getResource().scheme === Schemas.data) { + return this.getName(); + } return this.labelService.getUriLabel(this.getResource(), { relative: true }); } @memoize private get longTitle(): string { + if (this.getResource().scheme === Schemas.data) { + return this.getName(); + } return this.labelService.getUriLabel(this.getResource()); } @@ -89,44 +105,4 @@ export class CustomFileEditorInput extends WebviewInput { return this.longTitle; } } - - public async resolve(): Promise { - if (!this._hasResolved) { - this._hasResolved = true; - this._extensionService.activateByEvent(`onWebviewEditor:${this.viewType}`); - await this._webviewEditorService.resolveWebview(this); - } - return super.resolve(); - } - - public setState(newState: WebviewEditorState): void { - this._state = newState; - this._onDidChangeDirty.fire(); - } - - public isDirty() { - return this._state === WebviewEditorState.Dirty; - } - - public async confirmSave(): Promise { - if (!this.isDirty()) { - return ConfirmResult.DONT_SAVE; - } - return promptSave(this.dialogService, [this.getResource()]); - } - - public async save(): Promise { - if (!this.isDirty) { - return true; - } - const waitingOn: Promise[] = []; - this._onWillSave.fire({ - waitUntil: (thenable: Promise): void => { waitingOn.push(thenable); }, - }); - const result = await Promise.all(waitingOn); - return result.every(x => x); - } - - private readonly _onWillSave = this._register(new Emitter<{ waitUntil: (thenable: Thenable) => void }>()); - public readonly onWillSave = this._onWillSave.event; } diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts index bcb570dbacb..e4509a59b02 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts @@ -9,7 +9,8 @@ import { generateUuid } from 'vs/base/common/uuid'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CustomFileEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory'; -import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; +import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService'; +import { Lazy } from 'vs/base/common/lazy'; export class CustomEditoInputFactory extends WebviewEditorInputFactory { @@ -17,9 +18,9 @@ export class CustomEditoInputFactory extends WebviewEditorInputFactory { public constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, - @IWebviewEditorService private readonly webviewService: IWebviewEditorService, + @IWebviewWorkbenchService private readonly webviewWorkbenchService: IWebviewWorkbenchService, ) { - super(webviewService); + super(webviewWorkbenchService); } public serialize(input: CustomFileEditorInput): string | undefined { @@ -40,12 +41,17 @@ export class CustomEditoInputFactory extends WebviewEditorInputFactory { serializedEditorInput: string ): CustomFileEditorInput { const data = this.fromJson(serializedEditorInput); - const webviewInput = this.webviewService.reviveWebview(generateUuid(), data.viewType, data.title, data.iconPath, data.state, data.options, data.extensionLocation ? { - location: data.extensionLocation, - id: data.extensionId - } : undefined, data.group); + const id = data.id || generateUuid(); - const customInput = this._instantiationService.createInstance(CustomFileEditorInput, URI.from((data as any).editorResource), data.viewType, generateUuid(), new UnownedDisposable(webviewInput.webview)); + const webview = new Lazy(() => { + const webviewInput = this.webviewWorkbenchService.reviveWebview(id, data.viewType, data.title, data.iconPath, data.state, data.options, data.extensionLocation && data.extensionId ? { + location: data.extensionLocation, + id: data.extensionId + } : undefined, data.group); + return new UnownedDisposable(webviewInput.webview); + }); + + const customInput = this._instantiationService.createInstance(CustomFileEditorInput, URI.from((data as any).editorResource), data.viewType, id, webview); if (typeof data.group === 'number') { customInput.updateGroup(data.group); } diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 1ed4e3647e5..e9d1440016c 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -3,12 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { coalesce, distinct } from 'vs/base/common/arrays'; +import { coalesce, distinct, mergeSort, find } from 'vs/base/common/arrays'; import * as glob from 'vs/base/common/glob'; -import { UnownedDisposable } from 'vs/base/common/lifecycle'; +import { UnownedDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; -import { basename, DataUri } from 'vs/base/common/resources'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { basename, DataUri, isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import * as nls from 'vs/nls'; @@ -16,26 +15,30 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; +import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; +import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { EditorInput, EditorOptions, IEditor, IEditorInput } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint'; -import { CustomEditorDiscretion, CustomEditorInfo, CustomEditorSelector, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { CustomEditorPriority, CustomEditorInfo, CustomEditorSelector, ICustomEditorService, CONTEXT_HAS_CUSTOM_EDITORS } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService'; import { CustomFileEditorInput } from './customEditorInput'; +import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { Lazy } from 'vs/base/common/lazy'; const defaultEditorId = 'default'; const defaultEditorInfo: CustomEditorInfo = { id: defaultEditorId, - displayName: nls.localize('promptOpenWith.defaultEditor', "Default built-in editor"), + displayName: nls.localize('promptOpenWith.defaultEditor', "VS Code's standard text editor"), selector: [ { filenamePattern: '*' } ], - discretion: CustomEditorDiscretion.default, + priority: CustomEditorPriority.default, }; export class CustomEditorStore { @@ -65,18 +68,22 @@ export class CustomEditorStore { } } -export class CustomEditorService implements ICustomEditorService { +export class CustomEditorService extends Disposable implements ICustomEditorService { _serviceBrand: any; private readonly editors = new CustomEditorStore(); + private readonly _hasCustomEditor: IContextKey; constructor( + @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService private readonly configurationService: IConfigurationService, @IEditorService private readonly editorService: IEditorService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IQuickInputService private readonly quickInputService: IQuickInputService, @IWebviewService private readonly webviewService: IWebviewService, ) { + super(); + webviewEditorsExtensionPoint.setHandler(extensions => { this.editors.clear(); @@ -86,11 +93,17 @@ export class CustomEditorService implements ICustomEditorService { id: webviewEditorContribution.viewType, displayName: webviewEditorContribution.displayName, selector: webviewEditorContribution.selector || [], - discretion: webviewEditorContribution.discretion || CustomEditorDiscretion.default, + priority: webviewEditorContribution.priority || CustomEditorPriority.default, }); } } + this.updateContext(); }); + + this._hasCustomEditor = CONTEXT_HAS_CUSTOM_EDITORS.bindTo(contextKeyService); + + this._register(this.editorService.onDidActiveEditorChange(() => this.updateContext())); + this.updateContext(); } public getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[] { @@ -115,11 +128,22 @@ export class CustomEditorService implements ICustomEditorService { ...this.getContributedCustomEditors(resource), ], editor => editor.id); - const pick = await this.quickInputService.pick( - customEditors.map((editorDescriptor): IQuickPickItem => ({ - label: editorDescriptor.displayName, - id: editorDescriptor.id, - })), { + let currentlyOpenedEditorType: undefined | string; + for (const editor of group ? group.editors : []) { + if (editor.getResource() && isEqual(editor.getResource()!, resource)) { + currentlyOpenedEditorType = editor instanceof CustomFileEditorInput ? editor.viewType : defaultEditorId; + break; + } + } + + const items = customEditors.map((editorDescriptor): IQuickPickItem => ({ + label: editorDescriptor.displayName, + id: editorDescriptor.id, + description: editorDescriptor.id === currentlyOpenedEditorType + ? nls.localize('openWithCurrentlyActive', "Currently Active") + : undefined + })); + const pick = await this.quickInputService.pick(items, { placeHolder: nls.localize('promptOpenWith.placeHolder', "Select editor to use for '{0}'...", basename(resource)), }); @@ -151,13 +175,16 @@ export class CustomEditorService implements ICustomEditorService { public createInput( resource: URI, viewType: string, - group: IEditorGroup | undefined + group: IEditorGroup | undefined, + options?: { readonly customClasses: string; }, ): CustomFileEditorInput { const id = generateUuid(); - const webview = this.webviewService.createWebviewEditorOverlay(id, {}, {}); - const input = this.instantiationService.createInstance(CustomFileEditorInput, resource, viewType, id, new UnownedDisposable(webview)); + const webview = new Lazy(() => { + return new UnownedDisposable(this.webviewService.createWebviewEditorOverlay(id, { customClasses: options?.customClasses }, {})); + }); + const input = this.instantiationService.createInstance(CustomFileEditorInput, resource, viewType, id, webview); if (group) { - input.updateGroup(group!.id); + input.updateGroup(group.id); } return input; } @@ -169,22 +196,47 @@ export class CustomEditorService implements ICustomEditorService { group?: IEditorGroup ): Promise { if (group) { - const existingEditors = group.editors.filter(editor => editor.getResource() && editor.getResource()!.toString() === resource.toString()); + const existingEditors = group.editors.filter(editor => editor.getResource() && isEqual(editor.getResource()!, resource)); if (existingEditors.length) { - await this.editorService.replaceEditors([{ - editor: existingEditors[0], - replacement: input, - options: options ? EditorOptions.create(options) : undefined, - }], group); + const existing = existingEditors[0]; + if (!input.matches(existing)) { + await this.editorService.replaceEditors([{ + editor: existing, + replacement: input, + options: options ? EditorOptions.create(options) : undefined, + }], group); + + if (existing instanceof CustomFileEditorInput) { + existing.dispose(); + } + } } } return this.editorService.openEditor(input, options, group); } + + private updateContext() { + const activeControl = this.editorService.activeControl; + if (!activeControl) { + this._hasCustomEditor.reset(); + return; + } + const resource = activeControl.input.getResource(); + if (!resource) { + this._hasCustomEditor.reset(); + return; + } + const possibleEditors = [ + ...this.getContributedCustomEditors(resource), + ...this.getUserConfiguredCustomEditors(resource), + ]; + this._hasCustomEditor.set(possibleEditors.length > 0); + } } export const customEditorsAssociationsKey = 'workbench.experimental.editorAssociations'; -export type CustomEditorsAssociations = readonly (CustomEditorSelector & { readonly viewType: string })[]; +export type CustomEditorsAssociations = readonly (CustomEditorSelector & { readonly viewType: string; })[]; export class CustomEditorContribution implements IWorkbenchContribution { constructor( @@ -200,81 +252,56 @@ export class CustomEditorContribution implements IWorkbenchContribution { group: IEditorGroup ): IOpenEditorOverride | undefined { if (editor instanceof CustomFileEditorInput) { - return; + if (editor.group === group.id) { + return undefined; + } } if (editor instanceof DiffEditorInput) { - const getCustomEditorOverrideForSubInput = (subInput: IEditorInput): EditorInput | undefined => { - if (subInput instanceof CustomFileEditorInput) { - return undefined; - } - const resource = subInput.getResource(); - if (!resource) { - return undefined; - } - - const editors = distinct([ - ...this.customEditorService.getUserConfiguredCustomEditors(resource), - ...this.customEditorService.getContributedCustomEditors(resource), - ], editor => editor.id); - - // Always prefer the first editor in the diff editor case - return editors.length - ? this.customEditorService.createInput(resource, editors[0].id, group) - : undefined; - }; - - const modifiedOverride = getCustomEditorOverrideForSubInput(editor.modifiedInput); - const originalOverride = getCustomEditorOverrideForSubInput(editor.originalInput); - - if (modifiedOverride || originalOverride) { - return { - override: (async () => { - const input = new DiffEditorInput(editor.getName(), editor.getDescription(), originalOverride || editor.originalInput, modifiedOverride || editor.modifiedInput); - return this.editorService.openEditor(input, { ...options, ignoreOverrides: true }, group); - })(), - }; - } - - return undefined; + return this.onDiffEditorOpening(editor, options, group); } const resource = editor.getResource(); - if (!resource) { - return; + if (resource) { + return this.onResourceEditorOpening(resource, editor, options, group); } + return undefined; + } + private onResourceEditorOpening( + resource: URI, + editor: IEditorInput, + options: ITextEditorOptions | undefined, + group: IEditorGroup + ): IOpenEditorOverride | undefined { const userConfiguredEditors = this.customEditorService.getUserConfiguredCustomEditors(resource); - const contributedEditors = this.customEditorService.getContributedCustomEditors(resource); - - if (!userConfiguredEditors.length) { - if (!contributedEditors.length) { - return; - } - - const defaultEditors = contributedEditors.filter(editor => editor.discretion === CustomEditorDiscretion.default); - if (defaultEditors.length === 1) { - return { - override: this.customEditorService.openWith(resource, defaultEditors[0].id, options, group), - }; - } - } - - for (const input of group.editors) { - if (input instanceof CustomFileEditorInput && input.getResource().toString() === resource.toString()) { - return { - override: group.openEditor(input, options).then(withNullAsUndefined) - }; - } - } - if (userConfiguredEditors.length) { return { override: this.customEditorService.openWith(resource, userConfiguredEditors[0].id, options, group), }; } - // Open default editor but prompt user to see if they wish to use a custom one instead + const contributedEditors = this.customEditorService.getContributedCustomEditors(resource); + if (!contributedEditors.length) { + return; + } + + // Find the single default editor to use (if any) by looking at the editor's priority and the + // other contributed editors. + const defaultEditor = find(contributedEditors, editor => { + if (editor.priority !== CustomEditorPriority.default && editor.priority !== CustomEditorPriority.builtin) { + return false; + } + return contributedEditors.every(otherEditor => + otherEditor === editor || isLowerPriority(otherEditor, editor)); + }); + if (defaultEditor) { + return { + override: this.customEditorService.openWith(resource, defaultEditor.id, options, group), + }; + } + + // Open VS Code's standard editor but prompt user to see if they wish to use a custom one instead return { override: (async () => { const standardEditor = await this.editorService.openEditor(editor, { ...options, ignoreOverrides: true }, group); @@ -291,30 +318,91 @@ export class CustomEditorContribution implements IWorkbenchContribution { })() }; } + + private onDiffEditorOpening( + editor: DiffEditorInput, + options: ITextEditorOptions | undefined, + group: IEditorGroup + ): IOpenEditorOverride | undefined { + const getCustomEditorOverrideForSubInput = (subInput: IEditorInput, customClasses: string): EditorInput | undefined => { + if (subInput instanceof CustomFileEditorInput) { + return undefined; + } + const resource = subInput.getResource(); + if (!resource) { + return undefined; + } + + // Prefer default editors in the diff editor case but ultimatly always take the first editor + const editors = mergeSort( + distinct([ + ...this.customEditorService.getUserConfiguredCustomEditors(resource), + ...this.customEditorService.getContributedCustomEditors(resource), + ], editor => editor.id), + (a, b) => { + return priorityToRank(a.priority) - priorityToRank(b.priority); + }); + + if (!editors.length) { + return undefined; + } + + return this.customEditorService.createInput(resource, editors[0].id, group, { customClasses }); + }; + + const modifiedOverride = getCustomEditorOverrideForSubInput(editor.modifiedInput, 'modified'); + const originalOverride = getCustomEditorOverrideForSubInput(editor.originalInput, 'original'); + + if (modifiedOverride || originalOverride) { + return { + override: (async () => { + const input = new DiffEditorInput(editor.getName(), editor.getDescription(), originalOverride || editor.originalInput, modifiedOverride || editor.modifiedInput); + return this.editorService.openEditor(input, { ...options, ignoreOverrides: true }, group); + })(), + }; + } + + return undefined; + } +} + +function isLowerPriority(otherEditor: CustomEditorInfo, editor: CustomEditorInfo): unknown { + return priorityToRank(otherEditor.priority) < priorityToRank(editor.priority); +} + +function priorityToRank(priority: CustomEditorPriority): number { + switch (priority) { + case CustomEditorPriority.default: return 3; + case CustomEditorPriority.builtin: return 2; + case CustomEditorPriority.option: return 1; + } } function matches(selector: CustomEditorSelector, resource: URI): boolean { if (resource.scheme === Schemas.data) { + if (!selector.mime) { + return false; + } const metadata = DataUri.parseMetaData(resource); const mime = metadata.get(DataUri.META_DATA_MIME); - if (!selector.mime || !mime) { + if (!mime) { return false; } return glob.match(selector.mime, mime.toLowerCase()); } - if (!selector.filenamePattern && !selector.scheme) { - return false; - } if (selector.filenamePattern) { - if (!glob.match(selector.filenamePattern.toLowerCase(), basename(resource).toLowerCase())) { - return false; + if (glob.match(selector.filenamePattern.toLowerCase(), basename(resource).toLowerCase())) { + return true; } } - if (selector.scheme) { - if (resource.scheme !== selector.scheme) { - return false; - } - } - return true; + + return false; } + +registerThemingParticipant((theme, collector) => { + const shadow = theme.getColor(colorRegistry.scrollbarShadow); + if (shadow) { + collector.addRule(`.webview.modified { box-shadow: -6px 0 5px -5px ${shadow}; }`); + } +}); diff --git a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts index a17205467bb..5e169d1b2c4 100644 --- a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts +++ b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts @@ -5,7 +5,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as nls from 'vs/nls'; -import { CustomEditorDiscretion, CustomEditorSelector } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { CustomEditorPriority, CustomEditorSelector } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService'; @@ -13,14 +13,14 @@ namespace WebviewEditorContribution { export const viewType = 'viewType'; export const displayName = 'displayName'; export const selector = 'selector'; - export const discretion = 'discretion'; + export const priority = 'priority'; } interface IWebviewEditorsExtensionPoint { readonly [WebviewEditorContribution.viewType]: string; readonly [WebviewEditorContribution.displayName]: string; readonly [WebviewEditorContribution.selector]?: readonly CustomEditorSelector[]; - readonly [WebviewEditorContribution.discretion]?: CustomEditorDiscretion; + readonly [WebviewEditorContribution.priority]?: CustomEditorPriority; } const webviewEditorsContribution: IJSONSchema = { @@ -41,7 +41,7 @@ const webviewEditorsContribution: IJSONSchema = { }, [WebviewEditorContribution.displayName]: { type: 'string', - description: nls.localize('contributes.displayName', 'Name of the custom editor displayed to users.'), + description: nls.localize('contributes.displayName', 'Human readable name of the custom editor. This is displayed to users when selecting which editor to use.'), }, [WebviewEditorContribution.selector]: { type: 'array', @@ -53,23 +53,25 @@ const webviewEditorsContribution: IJSONSchema = { type: 'string', description: nls.localize('contributes.selector.filenamePattern', 'Glob that the custom editor is enabled for.'), }, - scheme: { + mime: { type: 'string', - description: nls.localize('contributes.selector.scheme', 'File scheme that the custom editor is enabled for.'), + description: nls.localize('contributes.selector.mime', 'Glob that matches the mime type of a data uri resource.'), } } } }, - [WebviewEditorContribution.discretion]: { + [WebviewEditorContribution.priority]: { type: 'string', - description: nls.localize('contributes.discretion', 'Controls when the custom editor is used. May be overridden by users.'), + description: nls.localize('contributes.priority', 'Controls when the custom editor is used. May be overridden by users.'), enum: [ - CustomEditorDiscretion.default, - CustomEditorDiscretion.option + CustomEditorPriority.default, + CustomEditorPriority.option, + CustomEditorPriority.builtin, ], enumDescriptions: [ - nls.localize('contributes.discretion.default', 'Editor is automatically used for a resource if no other default custom editors are registered for it.'), - nls.localize('contributes.discretion.option', 'Editor is not automatically used but can be selected by a user.'), + nls.localize('contributes.priority.default', 'Editor is automatically used for a resource if no other default custom editors are registered for it.'), + nls.localize('contributes.priority.option', 'Editor is not automatically used but can be selected by a user.'), + nls.localize('contributes.priority.builtin', 'Editor automatically used if no other `default` or `builtin` editors are registered for the resource.'), ], default: 'default' } diff --git a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts index 8fff4953c78..b8eaf3ae0d0 100644 --- a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts +++ b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts @@ -54,9 +54,9 @@ Registry.as(ConfigurationExtensions.Configuration) type: 'string', description: nls.localize('editor.editorAssociations.viewType', "Editor view type."), }, - 'scheme': { + 'mime': { type: 'string', - description: nls.localize('editor.editorAssociations.scheme', "Uri scheme the editor should be used for."), + description: nls.localize('editor.editorAssociations.mime', "Mime type the editor should be used for. This is used for binary files."), }, 'filenamePattern': { type: 'string', diff --git a/src/vs/workbench/contrib/customEditor/common/customEditor.ts b/src/vs/workbench/contrib/customEditor/common/customEditor.ts index 5a82502e225..a0bda2e0764 100644 --- a/src/vs/workbench/contrib/customEditor/common/customEditor.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditor.ts @@ -8,28 +8,31 @@ import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { EditorInput, IEditor } from 'vs/workbench/common/editor'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const ICustomEditorService = createDecorator('customEditorService'); +export const CONTEXT_HAS_CUSTOM_EDITORS = new RawContextKey('hasCustomEditors', false); + export interface ICustomEditorService { _serviceBrand: any; getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[]; getUserConfiguredCustomEditors(resource: URI): readonly CustomEditorInfo[]; - createInput(resource: URI, viewType: string, group: IEditorGroup | undefined): EditorInput; + createInput(resource: URI, viewType: string, group: IEditorGroup | undefined, options?: { readonly customClasses: string }): EditorInput; openWith(resource: URI, customEditorViewType: string, options?: ITextEditorOptions, group?: IEditorGroup): Promise; promptOpenWith(resource: URI, options?: ITextEditorOptions, group?: IEditorGroup): Promise; } -export const enum CustomEditorDiscretion { +export const enum CustomEditorPriority { default = 'default', + builtin = 'builtin', option = 'option', } export interface CustomEditorSelector { - readonly scheme?: string; readonly filenamePattern?: string; readonly mime?: string; } @@ -37,6 +40,6 @@ export interface CustomEditorSelector { export interface CustomEditorInfo { readonly id: string; readonly displayName: string; - readonly discretion: CustomEditorDiscretion; + readonly priority: CustomEditorPriority; readonly selector: readonly CustomEditorSelector[]; } diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 80306bf6af8..f5e1e7b7a1b 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -12,12 +12,12 @@ import { IAction, Action } from 'vs/base/common/actions'; import { Range } from 'vs/editor/common/core/range'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model'; +import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel, OverviewRulerLane, IModelDecorationOverviewRulerOptions } from 'vs/editor/common/model'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { RemoveBreakpointAction } from 'vs/workbench/contrib/debug/browser/debugActions'; -import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, BreakpointWidgetContext, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, BreakpointWidgetContext, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IBreakpointUpdateData, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug'; import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; import { ContextSubMenu } from 'vs/base/browser/contextmenu'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -30,6 +30,8 @@ import { memoize } from 'vs/base/common/decorators'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { distinct } from 'vs/base/common/arrays'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const $ = dom.$; @@ -45,7 +47,7 @@ const breakpointHelperDecoration: IModelDecorationOptions = { stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }; -function createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArray, debugService: IDebugService): { range: Range; options: IModelDecorationOptions; }[] { +function createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArray, debugService: IDebugService, debugSettings: IDebugConfiguration): { range: Range; options: IModelDecorationOptions; }[] { const result: { range: Range; options: IModelDecorationOptions; }[] = []; breakpoints.forEach((breakpoint) => { if (breakpoint.lineNumber <= model.getLineCount()) { @@ -56,7 +58,7 @@ function createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArr ); result.push({ - options: getBreakpointDecorationOptions(model, breakpoint, debugService), + options: getBreakpointDecorationOptions(model, breakpoint, debugService, debugSettings), range }); } @@ -65,7 +67,7 @@ function createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArr return result; } -function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoint, debugService: IDebugService): IModelDecorationOptions { +function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoint, debugService: IDebugService, debugSettings: IDebugConfiguration): IModelDecorationOptions { const { className, message } = getBreakpointMessageAndClassName(debugService, breakpoint); let glyphMarginHoverMessage: MarkdownString | undefined; @@ -78,11 +80,22 @@ function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoi } } + let overviewRulerDecoration: IModelDecorationOverviewRulerOptions | null; + if (debugSettings.showBreakpointsInOverviewRuler) { + overviewRulerDecoration = { + color: 'rgb(124, 40, 49)', + position: OverviewRulerLane.Left + }; + } else { + overviewRulerDecoration = null; + } + return { glyphMarginClassName: className, glyphMarginHoverMessage, stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - beforeContentClassName: breakpoint.column ? `debug-breakpoint-placeholder` : undefined + beforeContentClassName: breakpoint.column ? `debug-breakpoint-placeholder` : undefined, + overviewRuler: overviewRulerDecoration }; } @@ -138,16 +151,13 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, @IDialogService private readonly dialogService: IDialogService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService); this.registerListeners(); this.setDecorationsScheduler = new RunOnceScheduler(() => this.setDecorations(), 30); } - getId(): string { - return BREAKPOINT_EDITOR_CONTRIBUTION_ID; - } - private registerListeners(): void { this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => { const data = e.target.detail as IMarginData; @@ -220,7 +230,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => { let showBreakpointHintAtLineNumber = -1; const model = this.editor.getModel(); - if (model && e.target.position && e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN && this.debugService.getConfigurationManager().canSetBreakpointsIn(model) && + if (model && e.target.position && (e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN || e.target.type === MouseTargetType.GUTTER_LINE_NUMBERS) && this.debugService.getConfigurationManager().canSetBreakpointsIn(model) && this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) { const data = e.target.detail as IMarginData; if (!data.isAfterLines) { @@ -237,12 +247,23 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { this.closeBreakpointWidget(); await this.setDecorations(); })); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(async () => { + this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => { if (!this.ignoreBreakpointsChangeEvent && !this.setDecorationsScheduler.isScheduled()) { this.setDecorationsScheduler.schedule(); } })); + this.toDispose.push(this.debugService.onDidChangeState(() => { + // We need to update breakpoint decorations when state changes since the top stack frame and breakpoint decoration might change + if (!this.setDecorationsScheduler.isScheduled()) { + this.setDecorationsScheduler.schedule(); + } + })); this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged())); + this.toDispose.push(this.configurationService.onDidChangeConfiguration(async (e) => { + if (e.affectsConfiguration('debug.showBreakpointsInOverviewRuler')) { + await this.setDecorations(); + } + })); } private getContextMenuActions(breakpoints: ReadonlyArray, uri: URI, lineNumber: number, column?: number): Array { @@ -305,7 +326,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { nls.localize('addConditionalBreakpoint', "Add Conditional Breakpoint..."), undefined, true, - () => Promise.resolve(this.showBreakpointWidget(lineNumber, column)) + () => Promise.resolve(this.showBreakpointWidget(lineNumber, column, BreakpointWidgetContext.CONDITION)) )); actions.push(new Action( 'addLogPoint', @@ -357,7 +378,8 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { const activeCodeEditor = this.editor; const model = activeCodeEditor.getModel(); const breakpoints = this.debugService.getModel().getBreakpoints({ uri: model.uri }); - const desiredBreakpointDecorations = createBreakpointDecorations(model, breakpoints, this.debugService); + const debugSettings = this.configurationService.getValue('debug'); + const desiredBreakpointDecorations = createBreakpointDecorations(model, breakpoints, this.debugService, debugSettings); try { this.ignoreDecorationsChangedEvent = true; @@ -542,6 +564,20 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable { onHide: () => dispose(actions) }); })); + + const updateSize = () => { + const lineHeight = this.editor.getOption(EditorOption.lineHeight); + this.domNode.style.height = `${lineHeight}px`; + this.domNode.style.width = `${Math.ceil(0.8 * lineHeight)}px`; + this.domNode.style.marginLeft = `${Math.ceil(0.35 * lineHeight)}px`; + }; + updateSize(); + + this.toDispose.push(this.editor.onDidChangeConfiguration(c => { + if (c.hasChanged(EditorOption.fontSize) || c.hasChanged(EditorOption.lineHeight)) { + updateSize(); + } + })); } @memoize @@ -572,4 +608,4 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable { } } -registerEditorContribution(BreakpointEditorContribution); +registerEditorContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID, BreakpointEditorContribution); diff --git a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts index 3ba18b6a7f0..cdab0721ac3 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts @@ -35,6 +35,8 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { getSimpleEditorOptions, getSimpleCodeEditorWidgetOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; import { IRange, Range } from 'vs/editor/common/core/range'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; const $ = dom.$; const IPrivateBreakpointWidgetService = createDecorator('privateBreakpointWidgetService'); @@ -48,14 +50,17 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi _serviceBrand: undefined; private selectContainer!: HTMLElement; + private inputContainer!: HTMLElement; private input!: IActiveCodeEditor; private toDispose: lifecycle.IDisposable[]; private conditionInput = ''; private hitCountInput = ''; private logMessageInput = ''; private breakpoint: IBreakpoint | undefined; + private context: Context; + private heightInPx: number; - constructor(editor: ICodeEditor, private lineNumber: number, private column: number | undefined, private context: Context, + constructor(editor: ICodeEditor, private lineNumber: number, private column: number | undefined, context: Context | undefined, @IContextViewService private readonly contextViewService: IContextViewService, @IDebugService private readonly debugService: IDebugService, @IThemeService private readonly themeService: IThemeService, @@ -63,6 +68,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi @IInstantiationService private readonly instantiationService: IInstantiationService, @IModelService private readonly modelService: IModelService, @ICodeEditorService private readonly codeEditorService: ICodeEditorService, + @IConfigurationService private readonly _configurationService: IConfigurationService ) { super(editor, { showFrame: true, showArrow: false, frameWidth: 1 }); @@ -74,7 +80,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi this.breakpoint = breakpoints.length ? breakpoints[0] : undefined; } - if (this.context === undefined) { + if (context === undefined) { if (this.breakpoint && !this.breakpoint.condition && !this.breakpoint.hitCondition && this.breakpoint.logMessage) { this.context = Context.LOG_MESSAGE; } else if (this.breakpoint && !this.breakpoint.condition && this.breakpoint.hitCondition) { @@ -82,6 +88,8 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi } else { this.context = Context.CONDITION; } + } else { + this.context = context; } this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(e => { @@ -155,7 +163,8 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi this.input.focus(); }); - this.createBreakpointInput(dom.append(container, $('.inputContainer'))); + this.inputContainer = $('.inputContainer'); + this.createBreakpointInput(dom.append(container, this.inputContainer)); this.input.getModel().setValue(this.getInputValue(this.breakpoint)); this.toDispose.push(this.input.getModel().onDidChangeContent(() => { @@ -167,7 +176,9 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi } protected _doLayout(heightInPixel: number, widthInPixel: number): void { + this.heightInPx = heightInPixel; this.input.layout({ height: heightInPixel, width: widthInPixel - 113 }); + this.centerInputVertically(); } private createBreakpointInput(container: HTMLElement): void { @@ -177,7 +188,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi const scopedInstatiationService = this.instantiationService.createChild(new ServiceCollection( [IContextKeyService, scopedContextKeyService], [IPrivateBreakpointWidgetService, this])); - const options = getSimpleEditorOptions(); + const options = this.createEditorOptions(); const codeEditorWidgetOptions = getSimpleCodeEditorWidgetOptions(); this.input = scopedInstatiationService.createInstance(CodeEditorWidget, container, options, codeEditorWidgetOptions); CONTEXT_IN_BREAKPOINT_WIDGET.bindTo(scopedContextKeyService).set(true); @@ -224,6 +235,29 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi return suggestionsPromise; } })); + + this.toDispose.push(this._configurationService.onDidChangeConfiguration((e) => { + if (e.affectsConfiguration('editor.fontSize') || e.affectsConfiguration('editor.lineHeight')) { + this.input.updateOptions(this.createEditorOptions()); + this.centerInputVertically(); + } + })); + } + + private createEditorOptions(): IEditorOptions { + const editorConfig = this._configurationService.getValue('editor'); + const options = getSimpleEditorOptions(); + options.fontSize = editorConfig.fontSize; + return options; + } + + private centerInputVertically() { + if (this.container) { + const lineHeight = this.input.getOption(EditorOption.lineHeight); + const lineNum = this.input.getModel().getLineCount(); + const newTopMargin = (this.heightInPx - lineNum * lineHeight) / 2; + this.inputContainer.style.marginTop = newTopMargin + 'px'; + } } private createDecorations(): IDecorationOptions[] { diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index 7f8ffb936c3..aad8c7e6944 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -14,7 +14,7 @@ import { IContextMenuService, IContextViewService } from 'vs/platform/contextvie import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IListVirtualDelegate, IListContextMenuEvent, IListRenderer } from 'vs/base/browser/ui/list/list'; @@ -161,21 +161,19 @@ export class BreakpointsView extends ViewletPanel { const breakpointType = element instanceof Breakpoint && element.logMessage ? nls.localize('Logpoint', "Logpoint") : nls.localize('Breakpoint', "Breakpoint"); if (element instanceof Breakpoint || element instanceof FunctionBreakpoint) { - actions.push(new Action('workbench.action.debug.openEditorAndEditBreakpoint', nls.localize('editBreakpoint', "Edit {0}...", breakpointType), '', true, () => { + actions.push(new Action('workbench.action.debug.openEditorAndEditBreakpoint', nls.localize('editBreakpoint', "Edit {0}...", breakpointType), '', true, async () => { if (element instanceof Breakpoint) { - return openBreakpointSource(element, false, false, this.debugService, this.editorService).then(editor => { - if (editor) { - const codeEditor = editor.getControl(); - if (isCodeEditor(codeEditor)) { - codeEditor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber, element.column); - } + const editor = await openBreakpointSource(element, false, false, this.debugService, this.editorService); + if (editor) { + const codeEditor = editor.getControl(); + if (isCodeEditor(codeEditor)) { + codeEditor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber, element.column); } - }); + } + } else { + this.debugService.getViewModel().setSelectedFunctionBreakpoint(element); + this.onBreakpointsChange(); } - - this.debugService.getViewModel().setSelectedFunctionBreakpoint(element); - this.onBreakpointsChange(); - return Promise.resolve(undefined); })); actions.push(new Separator()); } @@ -709,6 +707,25 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br }; } + const focusedThread = debugService.getViewModel().focusedThread; + if (focusedThread) { + const callStack = focusedThread ? focusedThread.getCallStack() : undefined; + const topStackFrame = callStack ? callStack[0] : undefined; + if (topStackFrame && topStackFrame.source.uri.toString() === breakpoint.uri.toString() && topStackFrame.range.startLineNumber === breakpoint.lineNumber) { + if (topStackFrame.range.startColumn === breakpoint.column) { + return { + className: 'debug-breakpoint-and-top-stack-frame-at-column', + message: breakpoint.message || nls.localize('breakpoint', "Breakpoint") + }; + } else if (breakpoint.column === undefined) { + return { + className: 'debug-breakpoint-and-top-stack-frame', + message: breakpoint.message || nls.localize('breakpoint', "Breakpoint") + }; + } + } + } + return { className: 'debug-breakpoint', message: breakpoint.message || nls.localize('breakpoint', "Breakpoint") diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 4749eff2fc0..1706204f2eb 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -34,6 +34,7 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils'; import { STOP_ID, STOP_LABEL, DISCONNECT_ID, DISCONNECT_LABEL, RESTART_SESSION_ID, RESTART_LABEL, STEP_OVER_ID, STEP_OVER_LABEL, STEP_INTO_LABEL, STEP_INTO_ID, STEP_OUT_LABEL, STEP_OUT_ID, PAUSE_ID, PAUSE_LABEL, CONTINUE_ID, CONTINUE_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands'; import { ICommandService } from 'vs/platform/commands/common/commands'; +import { CollapseAction } from 'vs/workbench/browser/viewlet'; const $ = dom.$; @@ -82,8 +83,16 @@ export class CallStackView extends ViewletPanel { this.pauseMessageLabel.title = thread.stoppedDetails.text || ''; dom.toggleClass(this.pauseMessageLabel, 'exception', thread.stoppedDetails.reason === 'exception'); this.pauseMessage.hidden = false; + if (this.toolbar) { + this.toolbar.setActions([])(); + } + } else { this.pauseMessage.hidden = true; + if (this.toolbar) { + const collapseAction = new CollapseAction(this.tree, true, 'explorer-action codicon-collapse-all'); + this.toolbar.setActions([collapseAction])(); + } } this.needsRefresh = false; @@ -113,7 +122,7 @@ export class CallStackView extends ViewletPanel { const treeContainer = renderViewTree(container); this.dataSource = new CallStackDataSource(this.debugService); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CallStackView', treeContainer, new CallStackDelegate(), [ + this.tree = this.instantiationService.createInstance>(WorkbenchAsyncDataTree, 'CallStackView', treeContainer, new CallStackDelegate(), [ new SessionsRenderer(this.instantiationService), new ThreadsRenderer(this.instantiationService), this.instantiationService.createInstance(StackFramesRenderer), @@ -312,20 +321,20 @@ export class CallStackView extends ViewletPanel { } const actions: IAction[] = []; - const actionsDisposable = createAndFillInContextMenuActions(this.contributedContextMenu, { arg: this.getContextForContributedActions(element), shouldForwardArgs: false }, actions, this.contextMenuService); + const actionsDisposable = createAndFillInContextMenuActions(this.contributedContextMenu, { arg: this.getContextForContributedActions(element), shouldForwardArgs: true }, actions, this.contextMenuService); this.contextMenuService.showContextMenu({ getAnchor: () => e.anchor, getActions: () => actions, - getActionsContext: () => element, + getActionsContext: () => element && element instanceof StackFrame ? element.getId() : undefined, onHide: () => dispose(actionsDisposable) }); } - private getContextForContributedActions(element: CallStackItem | null): string | number | undefined { + private getContextForContributedActions(element: CallStackItem | null): string | number { if (element instanceof StackFrame) { if (element.source.inMemory) { - return element.source.raw.path || element.source.reference; + return element.source.raw.path || element.source.reference || ''; } return element.source.uri.toString(); @@ -337,7 +346,7 @@ export class CallStackView extends ViewletPanel { return element.getId(); } - return undefined; + return ''; } } @@ -777,7 +786,7 @@ class StopAction extends Action { private readonly session: IDebugSession, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${STOP_ID}`, STOP_LABEL, 'debug-action stop'); + super(`action.${STOP_ID}`, STOP_LABEL, 'debug-action codicon-debug-stop'); } public run(): Promise { @@ -805,7 +814,7 @@ class RestartAction extends Action { private readonly session: IDebugSession, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${RESTART_SESSION_ID}`, RESTART_LABEL, 'debug-action restart'); + super(`action.${RESTART_SESSION_ID}`, RESTART_LABEL, 'debug-action codicon-debug-restart'); } public run(): Promise { @@ -819,7 +828,7 @@ class StepOverAction extends Action { private readonly thread: IThread, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${STEP_OVER_ID}`, STEP_OVER_LABEL, 'debug-action step-over', thread.stopped); + super(`action.${STEP_OVER_ID}`, STEP_OVER_LABEL, 'debug-action codicon-debug-step-over', thread.stopped); } public run(): Promise { @@ -833,7 +842,7 @@ class StepIntoAction extends Action { private readonly thread: IThread, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${STEP_INTO_ID}`, STEP_INTO_LABEL, 'debug-action step-into', thread.stopped); + super(`action.${STEP_INTO_ID}`, STEP_INTO_LABEL, 'debug-action codicon-debug-step-into', thread.stopped); } public run(): Promise { @@ -847,7 +856,7 @@ class StepOutAction extends Action { private readonly thread: IThread, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${STEP_OUT_ID}`, STEP_OUT_LABEL, 'debug-action step-out', thread.stopped); + super(`action.${STEP_OUT_ID}`, STEP_OUT_LABEL, 'debug-action codicon-debug-step-out', thread.stopped); } public run(): Promise { @@ -861,7 +870,7 @@ class PauseAction extends Action { private readonly thread: IThread, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${PAUSE_ID}`, PAUSE_LABEL, 'debug-action pause', !thread.stopped); + super(`action.${PAUSE_ID}`, PAUSE_LABEL, 'debug-action codicon-debug-pause', !thread.stopped); } public run(): Promise { @@ -875,7 +884,7 @@ class ContinueAction extends Action { private readonly thread: IThread, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${CONTINUE_ID}`, CONTINUE_LABEL, 'debug-action continue', thread.stopped); + super(`action.${CONTINUE_ID}`, CONTINUE_LABEL, 'debug-action codicon-debug-continue', thread.stopped); } public run(): Promise { diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 445d50b98a0..3c68e97f711 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -84,7 +84,7 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie DebugViewlet, VIEWLET_ID, nls.localize('debug', "Debug"), - 'debug', + 'codicon-debug', 3 )); @@ -127,7 +127,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi const debugCategory = nls.localize('debugCategory', "Debug"); -registry.registerWorkbenchAction(new SyncActionDescriptor(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }), 'Debug: Start Debugging', debugCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE.toNegated()), 'Debug: Start Debugging', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL), 'Debug: Open launch.json', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(AddFunctionBreakpointAction, AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL), 'Debug: Add Function Breakpoint', debugCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ReapplyBreakpointsAction, ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL), 'Debug: Reapply All Breakpoints', debugCategory); @@ -261,8 +261,14 @@ configurationRegistry.registerConfiguration({ }, 'debug.onTaskErrors': { enum: ['debugAnyway', 'showErrors', 'prompt'], + enumDescriptions: [nls.localize('debugAnyway', "Ignore task errors and start debugging."), nls.localize('showErrors', "Show the Problems view and do not start debugging."), nls.localize('prompt', "Prompt user.")], description: nls.localize('debug.onTaskErrors', "Controls what to do when errors are encountered after running a preLaunchTask."), default: 'prompt' + }, + 'debug.showBreakpointsInOverviewRuler': { + type: 'boolean', + description: nls.localize({ comment: ['This is the description for a setting'], key: 'showBreakpointsInOverviewRuler' }, "Controls whether breakpoints should be shown in the overview ruler."), + default: false } } }); diff --git a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts index 7653bcd4d64..bca1d167e25 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts @@ -36,7 +36,7 @@ export class StartDebugActionViewItem implements IActionViewItem { private selected = 0; constructor( - private context: any, + private context: unknown, private action: IAction, @IDebugService private readonly debugService: IDebugService, @IThemeService private readonly themeService: IThemeService, @@ -69,7 +69,7 @@ export class StartDebugActionViewItem implements IActionViewItem { render(container: HTMLElement): void { this.container = container; dom.addClass(container, 'start-debug-action-item'); - this.start = dom.append(container, $('.icon')); + this.start = dom.append(container, $('.codicon.codicon-debug-start')); this.start.title = this.action.label; this.start.setAttribute('role', 'button'); this.start.tabIndex = 0; @@ -122,8 +122,8 @@ export class StartDebugActionViewItem implements IActionViewItem { } })); this.toDispose.push(attachStylerCallback(this.themeService, { selectBorder }, colors => { - this.container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : null; - selectBoxContainer.style.borderLeft = colors.selectBorder ? `1px solid ${colors.selectBorder}` : null; + this.container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : ''; + selectBoxContainer.style.borderLeft = colors.selectBorder ? `1px solid ${colors.selectBorder}` : ''; })); this.updateOptions(); diff --git a/src/vs/workbench/contrib/debug/browser/debugActions.ts b/src/vs/workbench/contrib/debug/browser/debugActions.ts index 3a2c52b0193..4f22268bf2a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActions.ts @@ -12,23 +12,17 @@ import { Variable, Breakpoint, FunctionBreakpoint } from 'vs/workbench/contrib/d import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { startDebugging } from 'vs/workbench/contrib/debug/common/debugUtils'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; export abstract class AbstractDebugAction extends Action { - protected toDispose: IDisposable[]; - constructor( id: string, label: string, cssClass: string, @IDebugService protected debugService: IDebugService, @IKeybindingService protected keybindingService: IKeybindingService, ) { super(id, label, cssClass, false); - this.toDispose = []; - this.toDispose.push(this.debugService.onDidChangeState(state => this.updateEnablement(state))); + this._register(this.debugService.onDidChangeState(state => this.updateEnablement(state))); this.updateLabel(label); this.updateEnablement(); @@ -56,16 +50,11 @@ export abstract class AbstractDebugAction extends Action { protected isEnabled(_: State): boolean { return true; } - - dispose(): void { - super.dispose(); - this.toDispose = dispose(this.toDispose); - } } export class ConfigureAction extends AbstractDebugAction { static readonly ID = 'workbench.action.debug.configure'; - static LABEL = nls.localize('openLaunchJson', "Open {0}", 'launch.json'); + static readonly LABEL = nls.localize('openLaunchJson', "Open {0}", 'launch.json'); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @@ -73,8 +62,8 @@ export class ConfigureAction extends AbstractDebugAction { @INotificationService private readonly notificationService: INotificationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService ) { - super(id, label, 'debug-action configure', debugService, keybindingService); - this.toDispose.push(debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateClass())); + super(id, label, 'debug-action codicon codicon-gear', debugService, keybindingService); + this._register(debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateClass())); this.updateClass(); } @@ -89,22 +78,20 @@ export class ConfigureAction extends AbstractDebugAction { private updateClass(): void { const configurationManager = this.debugService.getConfigurationManager(); const configurationCount = configurationManager.getLaunches().map(l => l.getConfigurationNames().length).reduce((sum, current) => sum + current); - this.class = configurationCount > 0 ? 'debug-action configure' : 'debug-action configure notification'; + this.class = configurationCount > 0 ? 'debug-action codicon codicon-gear' : 'debug-action codicon codicon-gear notification'; } - run(event?: any): Promise { + async run(event?: any): Promise { if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.notificationService.info(nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration.")); - return Promise.resolve(); + return; } const sideBySide = !!(event && (event.ctrlKey || event.metaKey)); const configurationManager = this.debugService.getConfigurationManager(); - if (!configurationManager.selectedConfiguration.launch) { - configurationManager.selectConfiguration(configurationManager.getLaunches()[0]); + if (configurationManager.selectedConfiguration.launch) { + return configurationManager.selectedConfiguration.launch.openConfigFile(sideBySide, false); } - - return configurationManager.selectedConfiguration.launch!.openConfigFile(sideBySide, false); } } @@ -116,18 +103,18 @@ export class StartAction extends AbstractDebugAction { @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IHistoryService private readonly historyService: IHistoryService ) { super(id, label, 'debug-action start', debugService, keybindingService); - this.toDispose.push(this.debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateEnablement())); - this.toDispose.push(this.debugService.onDidNewSession(() => this.updateEnablement())); - this.toDispose.push(this.debugService.onDidEndSession(() => this.updateEnablement())); - this.toDispose.push(this.contextService.onDidChangeWorkbenchState(() => this.updateEnablement())); + this._register(this.debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateEnablement())); + this._register(this.debugService.onDidNewSession(() => this.updateEnablement())); + this._register(this.debugService.onDidEndSession(() => this.updateEnablement())); + this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateEnablement())); } run(): Promise { - return startDebugging(this.debugService, this.historyService, this.isNoDebug()); + const { launch, name } = this.debugService.getConfigurationManager().selectedConfiguration; + return this.debugService.startDebugging(launch, name, { noDebug: this.isNoDebug() }); } protected isNoDebug(): boolean { @@ -165,7 +152,7 @@ export class RunAction extends StartAction { export class SelectAndStartAction extends AbstractDebugAction { static readonly ID = 'workbench.action.debug.selectandstart'; - static LABEL = nls.localize('selectAndStartDebugging', "Select and Start Debugging"); + static readonly LABEL = nls.localize('selectAndStartDebugging', "Select and Start Debugging"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @@ -182,7 +169,7 @@ export class SelectAndStartAction extends AbstractDebugAction { export class RemoveBreakpointAction extends Action { static readonly ID = 'workbench.debug.viewlet.action.removeBreakpoint'; - static LABEL = nls.localize('removeBreakpoint', "Remove Breakpoint"); + static readonly LABEL = nls.localize('removeBreakpoint', "Remove Breakpoint"); constructor(id: string, label: string, @IDebugService private readonly debugService: IDebugService) { super(id, label, 'debug-action remove'); @@ -196,11 +183,11 @@ export class RemoveBreakpointAction extends Action { export class RemoveAllBreakpointsAction extends AbstractDebugAction { static readonly ID = 'workbench.debug.viewlet.action.removeAllBreakpoints'; - static LABEL = nls.localize('removeAllBreakpoints', "Remove All Breakpoints"); + static readonly LABEL = nls.localize('removeAllBreakpoints', "Remove All Breakpoints"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action remove-all', debugService, keybindingService); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); + super(id, label, 'debug-action codicon-close-all', debugService, keybindingService); + this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); } run(): Promise { @@ -215,11 +202,11 @@ export class RemoveAllBreakpointsAction extends AbstractDebugAction { export class EnableAllBreakpointsAction extends AbstractDebugAction { static readonly ID = 'workbench.debug.viewlet.action.enableAllBreakpoints'; - static LABEL = nls.localize('enableAllBreakpoints', "Enable All Breakpoints"); + static readonly LABEL = nls.localize('enableAllBreakpoints', "Enable All Breakpoints"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { super(id, label, 'debug-action enable-all-breakpoints', debugService, keybindingService); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); + this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); } run(): Promise { @@ -234,11 +221,11 @@ export class EnableAllBreakpointsAction extends AbstractDebugAction { export class DisableAllBreakpointsAction extends AbstractDebugAction { static readonly ID = 'workbench.debug.viewlet.action.disableAllBreakpoints'; - static LABEL = nls.localize('disableAllBreakpoints', "Disable All Breakpoints"); + static readonly LABEL = nls.localize('disableAllBreakpoints', "Disable All Breakpoints"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { super(id, label, 'debug-action disable-all-breakpoints', debugService, keybindingService); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); + this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); } run(): Promise { @@ -253,14 +240,14 @@ export class DisableAllBreakpointsAction extends AbstractDebugAction { export class ToggleBreakpointsActivatedAction extends AbstractDebugAction { static readonly ID = 'workbench.debug.viewlet.action.toggleBreakpointsActivatedAction'; - static ACTIVATE_LABEL = nls.localize('activateBreakpoints', "Activate Breakpoints"); - static DEACTIVATE_LABEL = nls.localize('deactivateBreakpoints', "Deactivate Breakpoints"); + static readonly ACTIVATE_LABEL = nls.localize('activateBreakpoints', "Activate Breakpoints"); + static readonly DEACTIVATE_LABEL = nls.localize('deactivateBreakpoints', "Deactivate Breakpoints"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action breakpoints-activate', debugService, keybindingService); + super(id, label, 'debug-action codicon-activate-breakpoints', debugService, keybindingService); this.updateLabel(this.debugService.getModel().areBreakpointsActivated() ? ToggleBreakpointsActivatedAction.DEACTIVATE_LABEL : ToggleBreakpointsActivatedAction.ACTIVATE_LABEL); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => { + this._register(this.debugService.getModel().onDidChangeBreakpoints(() => { this.updateLabel(this.debugService.getModel().areBreakpointsActivated() ? ToggleBreakpointsActivatedAction.DEACTIVATE_LABEL : ToggleBreakpointsActivatedAction.ACTIVATE_LABEL); this.updateEnablement(); })); @@ -277,11 +264,11 @@ export class ToggleBreakpointsActivatedAction extends AbstractDebugAction { export class ReapplyBreakpointsAction extends AbstractDebugAction { static readonly ID = 'workbench.debug.viewlet.action.reapplyBreakpointsAction'; - static LABEL = nls.localize('reapplyAllBreakpoints', "Reapply All Breakpoints"); + static readonly LABEL = nls.localize('reapplyAllBreakpoints', "Reapply All Breakpoints"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { super(id, label, '', debugService, keybindingService); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); + this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); } run(): Promise { @@ -297,16 +284,15 @@ export class ReapplyBreakpointsAction extends AbstractDebugAction { export class AddFunctionBreakpointAction extends AbstractDebugAction { static readonly ID = 'workbench.debug.viewlet.action.addFunctionBreakpointAction'; - static LABEL = nls.localize('addFunctionBreakpoint', "Add Function Breakpoint"); + static readonly LABEL = nls.localize('addFunctionBreakpoint', "Add Function Breakpoint"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action add-function-breakpoint', debugService, keybindingService); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); + super(id, label, 'debug-action codicon-add', debugService, keybindingService); + this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement())); } - run(): Promise { + async run(): Promise { this.debugService.addFunctionBreakpoint(); - return Promise.resolve(); } protected isEnabled(_: State): boolean { @@ -317,17 +303,16 @@ export class AddFunctionBreakpointAction extends AbstractDebugAction { export class AddWatchExpressionAction extends AbstractDebugAction { static readonly ID = 'workbench.debug.viewlet.action.addWatchExpression'; - static LABEL = nls.localize('addWatchExpression', "Add Expression"); + static readonly LABEL = nls.localize('addWatchExpression', "Add Expression"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action add-watch-expression', debugService, keybindingService); - this.toDispose.push(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement())); - this.toDispose.push(this.debugService.getViewModel().onDidSelectExpression(() => this.updateEnablement())); + super(id, label, 'debug-action codicon-add', debugService, keybindingService); + this._register(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement())); + this._register(this.debugService.getViewModel().onDidSelectExpression(() => this.updateEnablement())); } - run(): Promise { + async run(): Promise { this.debugService.addWatchExpression(); - return Promise.resolve(undefined); } protected isEnabled(_: State): boolean { @@ -338,16 +323,15 @@ export class AddWatchExpressionAction extends AbstractDebugAction { export class RemoveAllWatchExpressionsAction extends AbstractDebugAction { static readonly ID = 'workbench.debug.viewlet.action.removeAllWatchExpressions'; - static LABEL = nls.localize('removeAllWatchExpressions', "Remove All Expressions"); + static readonly LABEL = nls.localize('removeAllWatchExpressions', "Remove All Expressions"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action remove-all', debugService, keybindingService); - this.toDispose.push(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement())); + super(id, label, 'debug-action codicon-close-all', debugService, keybindingService); + this._register(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement())); } - run(): Promise { + async run(): Promise { this.debugService.removeWatchExpressions(); - return Promise.resolve(); } protected isEnabled(_: State): boolean { @@ -357,7 +341,7 @@ export class RemoveAllWatchExpressionsAction extends AbstractDebugAction { export class FocusSessionAction extends AbstractDebugAction { static readonly ID = 'workbench.action.debug.focusProcess'; - static LABEL = nls.localize('focusSession', "Focus Session"); + static readonly LABEL = nls.localize('focusSession', "Focus Session"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @@ -367,23 +351,21 @@ export class FocusSessionAction extends AbstractDebugAction { super(id, label, '', debugService, keybindingService); } - run(session: IDebugSession): Promise { - this.debugService.focusStackFrame(undefined, undefined, session, true); + async run(session: IDebugSession): Promise { + await this.debugService.focusStackFrame(undefined, undefined, session, true); const stackFrame = this.debugService.getViewModel().focusedStackFrame; if (stackFrame) { - return stackFrame.openInEditor(this.editorService, true); + await stackFrame.openInEditor(this.editorService, true); } - - return Promise.resolve(undefined); } } export class CopyValueAction extends Action { static readonly ID = 'workbench.debug.viewlet.action.copyValue'; - static LABEL = nls.localize('copyValue', "Copy Value"); + static readonly LABEL = nls.localize('copyValue', "Copy Value"); constructor( - id: string, label: string, private value: any, private context: string, + id: string, label: string, private value: Variable | string, private context: string, @IDebugService private readonly debugService: IDebugService, @IClipboardService private readonly clipboardService: IClipboardService ) { @@ -395,15 +377,19 @@ export class CopyValueAction extends Action { const stackFrame = this.debugService.getViewModel().focusedStackFrame; const session = this.debugService.getViewModel().focusedSession; - if (this.value instanceof Variable && stackFrame && session && this.value.evaluateName) { + if (typeof this.value === 'string') { + return this.clipboardService.writeText(this.value); + } + + if (stackFrame && session && this.value.evaluateName) { try { const evaluation = await session.evaluate(this.value.evaluateName, stackFrame.frameId, this.context); this.clipboardService.writeText(evaluation.body.result); } catch (e) { this.clipboardService.writeText(this.value.value); } + } else { + this.clipboardService.writeText(this.value.value); } - - return this.clipboardService.writeText(this.value); } } diff --git a/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts b/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts index 68cf65a7931..d102042652b 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCallStackContribution.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { Range } from 'vs/editor/common/core/range'; import { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions } from 'vs/editor/common/model'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index d24aa5d5c1e..826f634a3d4 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -10,7 +10,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { IListService } from 'vs/platform/list/browser/listService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution, CONTEXT_IN_DEBUG_MODE, CONTEXT_EXPRESSION_SELECTED, CONTEXT_BREAKPOINT_SELECTED, IConfig, IStackFrame, IThread, IDebugSession, CONTEXT_DEBUG_STATE, REPL_ID, IDebugConfiguration, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug'; -import { Expression, Variable, Breakpoint, FunctionBreakpoint, Thread, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel'; +import { Expression, Variable, Breakpoint, FunctionBreakpoint, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel'; import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -27,8 +27,6 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { onUnexpectedError } from 'vs/base/common/errors'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { startDebugging } from 'vs/workbench/contrib/debug/common/debugUtils'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; @@ -60,9 +58,16 @@ export const DISCONNECT_LABEL = nls.localize('disconnect', "Disconnect"); export const STOP_LABEL = nls.localize('stop', "Stop"); export const CONTINUE_LABEL = nls.localize('continueDebug', "Continue"); -function getThreadAndRun(accessor: ServicesAccessor, thread: IThread | undefined, run: (thread: IThread) => Promise, ): void { +async function getThreadAndRun(accessor: ServicesAccessor, threadId: number | any, run: (thread: IThread) => Promise): Promise { const debugService = accessor.get(IDebugService); - if (!(thread instanceof Thread)) { + let thread: IThread | undefined; + if (typeof threadId === 'number') { + debugService.getModel().getSessions().forEach(s => { + if (!thread) { + thread = s.getThread(threadId); + } + }); + } else { thread = debugService.getViewModel().focusedThread; if (!thread) { const focusedSession = debugService.getViewModel().focusedSession; @@ -72,40 +77,66 @@ function getThreadAndRun(accessor: ServicesAccessor, thread: IThread | undefined } if (thread) { - run(thread).then(undefined, onUnexpectedError); + await run(thread); } } +function getFrame(debugService: IDebugService, frameId: string | undefined): IStackFrame | undefined { + if (!frameId) { + return undefined; + } + + const sessions = debugService.getModel().getSessions(); + for (let s of sessions) { + for (let t of s.getAllThreads()) { + for (let sf of t.getCallStack()) { + if (sf.getId() === frameId) { + return sf; + } + } + } + } + + return undefined; +} + export function registerCommands(): void { + // These commands are used in call stack context menu, call stack inline actions, command pallete, debug toolbar, mac native touch bar + // When the command is exectued in the context of a thread(context menu on a thread, inline call stack action) we pass the thread id + // Otherwise when it is executed "globaly"(using the touch bar, debug toolbar, command pallete) we do not pass any id and just take whatever is the focussed thread + // Same for stackFrame commands and session commands. CommandsRegistry.registerCommand({ id: COPY_STACK_TRACE_ID, - handler: async (accessor: ServicesAccessor, _: string, frame: IStackFrame) => { + handler: async (accessor: ServicesAccessor, _: string, frameId: string | undefined) => { const textResourcePropertiesService = accessor.get(ITextResourcePropertiesService); const clipboardService = accessor.get(IClipboardService); - const eol = textResourcePropertiesService.getEOL(frame.source.uri); - await clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol)); + let frame = getFrame(accessor.get(IDebugService), frameId); + if (frame) { + const eol = textResourcePropertiesService.getEOL(frame.source.uri); + await clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol)); + } } }); CommandsRegistry.registerCommand({ id: REVERSE_CONTINUE_ID, - handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => { - getThreadAndRun(accessor, thread, thread => thread.reverseContinue()); + handler: (accessor: ServicesAccessor, threadId: number | any) => { + getThreadAndRun(accessor, threadId, thread => thread.reverseContinue()); } }); CommandsRegistry.registerCommand({ id: STEP_BACK_ID, - handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => { - getThreadAndRun(accessor, thread, thread => thread.stepBack()); + handler: (accessor: ServicesAccessor, threadId: number | any) => { + getThreadAndRun(accessor, threadId, thread => thread.stepBack()); } }); CommandsRegistry.registerCommand({ id: TERMINATE_THREAD_ID, - handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => { - getThreadAndRun(accessor, thread, thread => thread.terminate()); + handler: (accessor: ServicesAccessor, threadId: number | any) => { + getThreadAndRun(accessor, threadId, thread => thread.terminate()); } }); @@ -170,8 +201,8 @@ export function registerCommands(): void { } if (!session) { - const historyService = accessor.get(IHistoryService); - startDebugging(debugService, historyService, false); + const { launch, name } = debugService.getConfigurationManager().selectedConfiguration; + debugService.startDebugging(launch, name, { noDebug: false }); } else { session.removeReplExpressions(); debugService.restartSession(session).then(undefined, onUnexpectedError); @@ -184,8 +215,8 @@ export function registerCommands(): void { weight: KeybindingWeight.WorkbenchContrib, primary: KeyCode.F10, when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'), - handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => { - getThreadAndRun(accessor, thread, thread => thread.next()); + handler: (accessor: ServicesAccessor, threadId: number | any) => { + getThreadAndRun(accessor, threadId, (thread: IThread) => thread.next()); } }); @@ -194,8 +225,8 @@ export function registerCommands(): void { weight: KeybindingWeight.WorkbenchContrib + 10, // Have a stronger weight to have priority over full screen when debugging primary: KeyCode.F11, when: CONTEXT_IN_DEBUG_MODE, - handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => { - getThreadAndRun(accessor, thread, thread => thread.stepIn()); + handler: (accessor: ServicesAccessor, threadId: number | any) => { + getThreadAndRun(accessor, threadId, (thread: IThread) => thread.stepIn()); } }); @@ -204,8 +235,8 @@ export function registerCommands(): void { weight: KeybindingWeight.WorkbenchContrib, primary: KeyMod.Shift | KeyCode.F11, when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'), - handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => { - getThreadAndRun(accessor, thread, thread => thread.stepOut()); + handler: (accessor: ServicesAccessor, threadId: number | any) => { + getThreadAndRun(accessor, threadId, (thread: IThread) => thread.stepOut()); } }); @@ -214,28 +245,16 @@ export function registerCommands(): void { weight: KeybindingWeight.WorkbenchContrib, primary: KeyCode.F6, when: CONTEXT_DEBUG_STATE.isEqualTo('running'), - handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => { - const debugService = accessor.get(IDebugService); - if (!(thread instanceof Thread)) { - thread = debugService.getViewModel().focusedThread; - if (!thread) { - const session = debugService.getViewModel().focusedSession; - const threads = session && session.getAllThreads(); - thread = threads && threads.length ? threads[0] : undefined; - } - } - - if (thread) { - thread.pause().then(undefined, onUnexpectedError); - } + handler: (accessor: ServicesAccessor, threadId: number | any) => { + getThreadAndRun(accessor, threadId, thread => thread.pause()); } }); CommandsRegistry.registerCommand({ id: DISCONNECT_ID, - handler: (accessor: ServicesAccessor, _: string, session: IDebugSession | undefined) => { + handler: (accessor: ServicesAccessor, sessionId: string | undefined) => { const debugService = accessor.get(IDebugService); - session = session || debugService.getViewModel().focusedSession; + const session = debugService.getModel().getSession(sessionId) || debugService.getViewModel().focusedSession; debugService.stopSession(session).then(undefined, onUnexpectedError); } }); @@ -245,16 +264,14 @@ export function registerCommands(): void { weight: KeybindingWeight.WorkbenchContrib, primary: KeyMod.Shift | KeyCode.F5, when: CONTEXT_IN_DEBUG_MODE, - handler: (accessor: ServicesAccessor, _: string, session: IDebugSession | undefined) => { + handler: (accessor: ServicesAccessor, sessionId: string | undefined) => { const debugService = accessor.get(IDebugService); - if (!session || !session.getId) { - session = debugService.getViewModel().focusedSession; - const configurationService = accessor.get(IConfigurationService); - const showSubSessions = configurationService.getValue('debug').showSubSessionsInToolBar; - // Stop should be sent to the root parent session - while (!showSubSessions && session && session.parentSession) { - session = session.parentSession; - } + let session = debugService.getModel().getSession(sessionId) || debugService.getViewModel().focusedSession; + const configurationService = accessor.get(IConfigurationService); + const showSubSessions = configurationService.getValue('debug').showSubSessionsInToolBar; + // Stop should be sent to the root parent session + while (!showSubSessions && session && session.parentSession) { + session = session.parentSession; } debugService.stopSession(session).then(undefined, onUnexpectedError); @@ -263,13 +280,12 @@ export function registerCommands(): void { CommandsRegistry.registerCommand({ id: RESTART_FRAME_ID, - handler: (accessor: ServicesAccessor, _: string, frame: IStackFrame | undefined) => { + handler: async (accessor: ServicesAccessor, _: string, frameId: string | undefined) => { const debugService = accessor.get(IDebugService); - if (!frame) { - frame = debugService.getViewModel().focusedStackFrame; + let frame = getFrame(debugService, frameId); + if (frame) { + await frame.restart(); } - - return frame!.restart(); } }); @@ -278,8 +294,8 @@ export function registerCommands(): void { weight: KeybindingWeight.WorkbenchContrib, primary: KeyCode.F5, when: CONTEXT_IN_DEBUG_MODE, - handler: (accessor: ServicesAccessor, _: string, thread: IThread | undefined) => { - getThreadAndRun(accessor, thread, thread => thread.continue()); + handler: (accessor: ServicesAccessor, threadId: number | any) => { + getThreadAndRun(accessor, threadId, thread => thread.continue()); } }); @@ -431,14 +447,11 @@ export function registerCommands(): void { weight: KeybindingWeight.WorkbenchContrib, when: undefined, primary: undefined, - handler: (accessor) => { + handler: async (accessor) => { const viewletService = accessor.get(IViewletService); - return viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true) - .then(viewlet => viewlet as IExtensionsViewlet) - .then(viewlet => { - viewlet.search('tag:debuggers @sort:installs'); - viewlet.focus(); - }); + const viewlet = await viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true) as IExtensionsViewlet; + viewlet.search('tag:debuggers @sort:installs'); + viewlet.focus(); } }); @@ -447,24 +460,23 @@ export function registerCommands(): void { weight: KeybindingWeight.WorkbenchContrib, when: undefined, primary: undefined, - handler: (accessor, launchUri: string) => { + handler: async (accessor, launchUri: string) => { const manager = accessor.get(IDebugService).getConfigurationManager(); if (accessor.get(IWorkspaceContextService).getWorkbenchState() === WorkbenchState.EMPTY) { accessor.get(INotificationService).info(nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration.")); - return undefined; + return; } - const launch = manager.getLaunches().filter(l => l.uri.toString() === launchUri).pop() || manager.selectedConfiguration.launch; - return launch!.openConfigFile(false, false).then(({ editor, created }) => { + const launch = manager.getLaunches().filter(l => l.uri.toString() === launchUri).pop() || manager.selectedConfiguration.launch; + if (launch) { + const { editor, created } = await launch.openConfigFile(false, false); if (editor && !created) { const codeEditor = editor.getControl(); if (codeEditor) { - return codeEditor.getContribution(EDITOR_CONTRIBUTION_ID).addLaunchConfiguration(); + await codeEditor.getContribution(EDITOR_CONTRIBUTION_ID).addLaunchConfiguration(); } } - - return undefined; - }); + } } }); diff --git a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts index bef32f8a8d2..c4f71f9db26 100644 --- a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts @@ -21,7 +21,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory } from 'vs/workbench/contrib/debug/common/debug'; import { Debugger } from 'vs/workbench/contrib/debug/common/debugger'; import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -32,10 +32,11 @@ import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/plat import { launchSchema, debuggersExtPoint, breakpointsExtPoint } from 'vs/workbench/contrib/debug/common/debugSchemas'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { onUnexpectedError } from 'vs/base/common/errors'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { CancellationToken } from 'vs/base/common/cancellation'; import { withUndefinedAsNull } from 'vs/base/common/types'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { first } from 'vs/base/common/arrays'; const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); jsonRegistry.registerSchema(launchSchemaId, launchSchema); @@ -57,7 +58,6 @@ export class ConfigurationManager implements IConfigurationManager { private debugConfigurationTypeContext: IContextKey; constructor( - private debugService: IDebugService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IEditorService private readonly editorService: IEditorService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -67,7 +67,8 @@ export class ConfigurationManager implements IConfigurationManager { @IStorageService private readonly storageService: IStorageService, @ILifecycleService lifecycleService: ILifecycleService, @IExtensionService private readonly extensionService: IExtensionService, - @IContextKeyService contextKeyService: IContextKeyService + @IContextKeyService contextKeyService: IContextKeyService, + @IHistoryService historyService: IHistoryService ) { this.configProviders = []; this.adapterDescriptorFactories = []; @@ -80,6 +81,14 @@ export class ConfigurationManager implements IConfigurationManager { this.debugConfigurationTypeContext = CONTEXT_DEBUG_CONFIGURATION_TYPE.bindTo(contextKeyService); if (previousSelectedLaunch) { this.selectConfiguration(previousSelectedLaunch, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE)); + } else if (this.launches.length > 0) { + const rootUri = historyService.getLastActiveWorkspaceRoot(); + let launch = this.getLaunch(rootUri); + if (!launch || launch.getConfigurationNames().length === 0) { + launch = first(this.launches, l => !!(l && l.getConfigurationNames().length), launch) || this.launches[0]; + } + + this.selectConfiguration(launch); } } @@ -242,12 +251,6 @@ export class ConfigurationManager implements IConfigurationManager { delta.removed.forEach(removed => { const removedTypes = removed.value.map(rawAdapter => rawAdapter.type); this.debuggers = this.debuggers.filter(d => removedTypes.indexOf(d.type) === -1); - this.debugService.getModel().getSessions().forEach(s => { - // Stop sessions if their debugger has been removed - if (removedTypes.indexOf(s.configuration.type) >= 0) { - this.debugService.stopSession(s).then(undefined, onUnexpectedError); - } - }); }); // update the schema to include all attributes, snippets and types from extensions. diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts index 784694a387a..d053a9d481a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts @@ -34,7 +34,7 @@ class ToggleBreakpointAction extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { + async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { if (editor.hasModel()) { const debugService = accessor.get(IDebugService); const modelUri = editor.getModel().uri; @@ -49,12 +49,10 @@ class ToggleBreakpointAction extends EditorAction { } else if (canSet) { return (debugService.addBreakpoints(modelUri, [{ lineNumber: line }], 'debugEditorActions.toggleBreakpointAction')); } else { - return Promise.resolve([]); + return []; } })); } - - return Promise.resolve(); } } @@ -75,7 +73,7 @@ class ConditionalBreakpointAction extends EditorAction { const position = editor.getPosition(); if (position && editor.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) { - editor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, undefined); + editor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, undefined, BreakpointWidgetContext.CONDITION); } } } @@ -97,15 +95,15 @@ class LogPointAction extends EditorAction { const position = editor.getPosition(); if (position && editor.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) { - editor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, BreakpointWidgetContext.LOG_MESSAGE); + editor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, position.column, BreakpointWidgetContext.LOG_MESSAGE); } } } export class RunToCursorAction extends EditorAction { - public static ID = 'editor.debug.action.runToCursor'; - public static LABEL = nls.localize('runToCursor', "Run to Cursor"); + public static readonly ID = 'editor.debug.action.runToCursor'; + public static readonly LABEL = nls.localize('runToCursor', "Run to Cursor"); constructor() { super({ @@ -120,11 +118,11 @@ export class RunToCursorAction extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { + async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { const debugService = accessor.get(IDebugService); const focusedSession = debugService.getViewModel().focusedSession; if (debugService.state !== State.Stopped || !focusedSession) { - return Promise.resolve(undefined); + return; } let breakpointToRemove: IBreakpoint; @@ -139,18 +137,18 @@ export class RunToCursorAction extends EditorAction { }); const position = editor.getPosition(); - if (!editor.hasModel() || !position) { - return Promise.resolve(); - } - - const uri = editor.getModel().uri; - const bpExists = !!(debugService.getModel().getBreakpoints({ column: position.column, lineNumber: position.lineNumber, uri }).length); - return (bpExists ? Promise.resolve(null) : >debugService.addBreakpoints(uri, [{ lineNumber: position.lineNumber, column: position.column }], 'debugEditorActions.runToCursorAction')).then((breakpoints) => { - if (breakpoints && breakpoints.length) { - breakpointToRemove = breakpoints[0]; + if (editor.hasModel() && position) { + const uri = editor.getModel().uri; + const bpExists = !!(debugService.getModel().getBreakpoints({ column: position.column, lineNumber: position.lineNumber, uri }).length); + if (!bpExists) { + const breakpoints = await debugService.addBreakpoints(uri, [{ lineNumber: position.lineNumber, column: position.column }], 'debugEditorActions.runToCursorAction'); + if (breakpoints && breakpoints.length) { + breakpointToRemove = breakpoints[0]; + } } - debugService.getViewModel().focusedThread!.continue(); - }); + + await debugService.getViewModel().focusedThread!.continue(); + } } } @@ -169,13 +167,13 @@ class SelectionToReplAction extends EditorAction { }); } - public async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { + async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { const debugService = accessor.get(IDebugService); const panelService = accessor.get(IPanelService); const viewModel = debugService.getViewModel(); const session = viewModel.focusedSession; if (!editor.hasModel() || !session) { - return Promise.resolve(); + return; } const text = editor.getModel().getValueInRange(editor.getSelection()); @@ -199,15 +197,16 @@ class SelectionToWatchExpressionsAction extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { + async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { const debugService = accessor.get(IDebugService); const viewletService = accessor.get(IViewletService); if (!editor.hasModel()) { - return Promise.resolve(); + return; } const text = editor.getModel().getValueInRange(editor.getSelection()); - return viewletService.openViewlet(VIEWLET_ID).then(() => debugService.addWatchExpression(text)); + await viewletService.openViewlet(VIEWLET_ID); + debugService.addWatchExpression(text); } } @@ -227,14 +226,14 @@ class ShowDebugHoverAction extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { + async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { const position = editor.getPosition(); if (!position || !editor.hasModel()) { - return Promise.resolve(); + return; } const word = editor.getModel().getWordAtPosition(position); if (!word) { - return Promise.resolve(); + return; } const range = new Range(position.lineNumber, position.column, position.lineNumber, word.endColumn); @@ -247,7 +246,7 @@ class GoToBreakpointAction extends EditorAction { super(opts); } - public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): Promise { + async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise { const debugService = accessor.get(IDebugService); const editorService = accessor.get(IEditorService); if (editor.hasModel()) { @@ -279,8 +278,6 @@ class GoToBreakpointAction extends EditorAction { return openBreakpointSource(moveBreakpoint, false, true, debugService, editorService); } } - - return Promise.resolve(null); } } diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index a395d10adc1..28fad67b439 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { RunOnceScheduler } from 'vs/base/common/async'; import * as env from 'vs/base/common/platform'; import { visit } from 'vs/base/common/json'; -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { KeyCode } from 'vs/base/common/keyCodes'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardTokenType } from 'vs/editor/common/modes'; @@ -98,7 +98,7 @@ class DebugEditorContribution implements IDebugEditorContribution { this.wordToLineNumbersMap = undefined; this.updateInlineValuesScheduler.schedule(); })); - this.toDispose.push(this.editor.onDidChangeModel(() => { + this.toDispose.push(this.editor.onDidChangeModel(async () => { const stackFrame = this.debugService.getViewModel().focusedStackFrame; const model = this.editor.getModel(); if (model) { @@ -108,7 +108,7 @@ class DebugEditorContribution implements IDebugEditorContribution { this.hideHoverWidget(); this.updateConfigurationWidgetVisibility(); this.wordToLineNumbersMap = undefined; - this.updateInlineValueDecorations(stackFrame); + await this.updateInlineValueDecorations(stackFrame); })); this.toDispose.push(this.editor.onDidScrollChange(() => this.hideHoverWidget)); this.toDispose.push(this.debugService.onDidChangeState((state: State) => { @@ -141,32 +141,26 @@ class DebugEditorContribution implements IDebugEditorContribution { } } - getId(): string { - return EDITOR_CONTRIBUTION_ID; - } - - showHover(range: Range, focus: boolean): Promise { + async showHover(range: Range, focus: boolean): Promise { const sf = this.debugService.getViewModel().focusedStackFrame; const model = this.editor.getModel(); if (sf && model && sf.source.uri.toString() === model.uri.toString()) { return this.hoverWidget.showAt(range, focus); } - - return Promise.resolve(); } - private onFocusStackFrame(sf: IStackFrame | undefined): void { + private async onFocusStackFrame(sf: IStackFrame | undefined): Promise { const model = this.editor.getModel(); if (model) { this._applyHoverConfiguration(model, sf); if (sf && sf.source.uri.toString() === model.uri.toString()) { - this.toggleExceptionWidget(); + await this.toggleExceptionWidget(); } else { this.hideHoverWidget(); } } - this.updateInlineValueDecorations(sf); + await this.updateInlineValueDecorations(sf); } @memoize @@ -261,7 +255,7 @@ class DebugEditorContribution implements IDebugEditorContribution { // end hover business // exception widget - private toggleExceptionWidget(): void { + private async toggleExceptionWidget(): Promise { // Toggles exception widget based on the state of the current editor model and debug stack frame const model = this.editor.getModel(); const focusedSf = this.debugService.getViewModel().focusedStackFrame; @@ -282,11 +276,10 @@ class DebugEditorContribution implements IDebugEditorContribution { if (this.exceptionWidget && !sameUri) { this.closeExceptionWidget(); } else if (sameUri) { - focusedSf.thread.exceptionInfo.then(exceptionInfo => { - if (exceptionInfo && exceptionSf.range.startLineNumber && exceptionSf.range.startColumn) { - this.showExceptionWidget(exceptionInfo, this.debugService.getViewModel().focusedSession, exceptionSf.range.startLineNumber, exceptionSf.range.startColumn); - } - }); + const exceptionInfo = await focusedSf.thread.exceptionInfo; + if (exceptionInfo && exceptionSf.range.startLineNumber && exceptionSf.range.startColumn) { + this.showExceptionWidget(exceptionInfo, this.debugService.getViewModel().focusedSession, exceptionSf.range.startLineNumber, exceptionSf.range.startColumn); + } } } @@ -320,7 +313,7 @@ class DebugEditorContribution implements IDebugEditorContribution { } } - addLaunchConfiguration(): Promise { + async addLaunchConfiguration(): Promise { /* __GDPR__ "debug/addLaunchConfiguration" : {} */ @@ -328,7 +321,7 @@ class DebugEditorContribution implements IDebugEditorContribution { let configurationsArrayPosition: Position | undefined; const model = this.editor.getModel(); if (!model) { - return Promise.resolve(); + return; } let depthInArray = 0; @@ -351,7 +344,7 @@ class DebugEditorContribution implements IDebugEditorContribution { this.editor.focus(); if (!configurationsArrayPosition) { - return Promise.resolve(); + return; } const insertLine = (position: Position): Promise => { @@ -364,7 +357,8 @@ class DebugEditorContribution implements IDebugEditorContribution { return this.commandService.executeCommand('editor.action.insertLineAfter'); }; - return insertLine(configurationsArrayPosition).then(() => this.commandService.executeCommand('editor.action.triggerSuggest')); + await insertLine(configurationsArrayPosition); + await this.commandService.executeCommand('editor.action.triggerSuggest'); } // Inline Decorations @@ -380,12 +374,12 @@ class DebugEditorContribution implements IDebugEditorContribution { @memoize private get updateInlineValuesScheduler(): RunOnceScheduler { return new RunOnceScheduler( - () => this.updateInlineValueDecorations(this.debugService.getViewModel().focusedStackFrame), + async () => await this.updateInlineValueDecorations(this.debugService.getViewModel().focusedStackFrame), 200 ); } - private updateInlineValueDecorations(stackFrame: IStackFrame | undefined): void { + private async updateInlineValueDecorations(stackFrame: IStackFrame | undefined): Promise { const model = this.editor.getModel(); if (!this.configurationService.getValue('debug').inlineValues || !model || !stackFrame || model.uri.toString() !== stackFrame.source.uri.toString()) { @@ -397,20 +391,20 @@ class DebugEditorContribution implements IDebugEditorContribution { this.removeInlineValuesScheduler.cancel(); - stackFrame.getMostSpecificScopes(stackFrame.range) - // Get all top level children in the scope chain - .then(scopes => Promise.all(scopes.map(scope => scope.getChildren() - .then(children => { - let range = new Range(0, 0, stackFrame.range.startLineNumber, stackFrame.range.startColumn); - if (scope.range) { - range = range.setStartPosition(scope.range.startLineNumber, scope.range.startColumn); - } + const scopes = await stackFrame.getMostSpecificScopes(stackFrame.range); + // Get all top level children in the scope chain + const decorationsPerScope = await Promise.all(scopes.map(async scope => { + const children = await scope.getChildren(); + let range = new Range(0, 0, stackFrame.range.startLineNumber, stackFrame.range.startColumn); + if (scope.range) { + range = range.setStartPosition(scope.range.startLineNumber, scope.range.startColumn); + } - return this.createInlineValueDecorationsInsideRange(children, range, model); - }))).then(decorationsPerScope => { - const allDecorations = decorationsPerScope.reduce((previous, current) => previous.concat(current), []); - this.editor.setDecorations(INLINE_VALUE_DECORATION_KEY, allDecorations); - })); + return this.createInlineValueDecorationsInsideRange(children, range, model); + })); + + const allDecorations = decorationsPerScope.reduce((previous, current) => previous.concat(current), []); + this.editor.setDecorations(INLINE_VALUE_DECORATION_KEY, allDecorations); } private createInlineValueDecorationsInsideRange(expressions: ReadonlyArray, range: Range, model: ITextModel): IDecorationOptions[] { @@ -547,4 +541,4 @@ class DebugEditorContribution implements IDebugEditorContribution { } } -registerEditorContribution(DebugEditorContribution); +registerEditorContribution(EDITOR_CONTRIBUTION_ID, DebugEditorContribution); diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index 506aafc1781..99dcef5b9cd 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -20,7 +20,7 @@ import { renderExpressionValue, replaceWhitespace } from 'vs/workbench/contrib/d import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { attachStylerCallback } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { editorHoverBackground, editorHoverBorder } from 'vs/platform/theme/common/colorRegistry'; +import { editorHoverBackground, editorHoverBorder, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { getExactExpressionStartAndEnd } from 'vs/workbench/contrib/debug/common/debugUtils'; import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; @@ -73,7 +73,7 @@ export class DebugHoverWidget implements IContentWidget { this.treeContainer.setAttribute('role', 'tree'); const dataSource = new DebugHoverDataSource(); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'DebugHover', this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)], + this.tree = this.instantiationService.createInstance>(WorkbenchAsyncDataTree, 'DebugHover', this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)], dataSource, { ariaLabel: nls.localize('treeAriaLabel', "Debug Hover"), accessibilityProvider: new DebugHoverAccessibilityProvider(), @@ -90,16 +90,21 @@ export class DebugHoverWidget implements IContentWidget { this.editor.applyFontInfo(this.domNode); - this.toDispose.push(attachStylerCallback(this.themeService, { editorHoverBackground, editorHoverBorder }, colors => { + this.toDispose.push(attachStylerCallback(this.themeService, { editorHoverBackground, editorHoverBorder, editorHoverForeground }, colors => { if (colors.editorHoverBackground) { this.domNode.style.backgroundColor = colors.editorHoverBackground.toString(); } else { - this.domNode.style.backgroundColor = null; + this.domNode.style.backgroundColor = ''; } if (colors.editorHoverBorder) { this.domNode.style.border = `1px solid ${colors.editorHoverBorder}`; } else { - this.domNode.style.border = null; + this.domNode.style.border = ''; + } + if (colors.editorHoverForeground) { + this.domNode.style.color = colors.editorHoverForeground.toString(); + } else { + this.domNode.style.color = null; } })); this.toDispose.push(this.tree.onDidChangeContentHeight(() => this.layoutTreeAndContainer())); @@ -174,7 +179,7 @@ export class DebugHoverWidget implements IContentWidget { return this.doShow(pos, expression, focus); } - private static _HOVER_HIGHLIGHT_DECORATION_OPTIONS = ModelDecorationOptions.register({ + private static readonly _HOVER_HIGHLIGHT_DECORATION_OPTIONS = ModelDecorationOptions.register({ className: 'hoverHighlight' }); diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index ccb8004fccc..1eb19f2c61d 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -24,14 +24,13 @@ import * as debugactions from 'vs/workbench/contrib/debug/browser/debugActions'; import { ConfigurationManager } from 'vs/workbench/contrib/debug/browser/debugConfigurationManager'; import Constants from 'vs/workbench/contrib/markers/browser/constants'; import { ITaskService, ITaskSummary } from 'vs/workbench/contrib/tasks/common/taskService'; -import { TaskError } from 'vs/workbench/contrib/tasks/common/taskSystem'; import { VIEWLET_ID as EXPLORER_VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { parse, getFirstFrame } from 'vs/base/common/console'; import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks'; @@ -121,7 +120,7 @@ export class DebugService implements IDebugService { this._onWillNewSession = new Emitter(); this._onDidEndSession = new Emitter(); - this.configurationManager = this.instantiationService.createInstance(ConfigurationManager, this); + this.configurationManager = this.instantiationService.createInstance(ConfigurationManager); this.toDispose.push(this.configurationManager); this.debugType = CONTEXT_DEBUG_TYPE.bindTo(contextKeyService); @@ -144,13 +143,13 @@ export class DebugService implements IDebugService { session.configuration.request = 'attach'; session.configuration.port = event.port; session.setSubId(event.subId); - this.launchOrAttachToSession(session).then(undefined, errors.onUnexpectedError); + this.launchOrAttachToSession(session); } })); this.toDispose.push(this.extensionHostDebugService.onTerminateSession(event => { const session = this.model.getSession(event.sessionId); if (session && session.subId === event.subId) { - session.disconnect().then(undefined, errors.onUnexpectedError); + session.disconnect(); } })); this.toDispose.push(this.extensionHostDebugService.onLogToSession(event => { @@ -253,96 +252,106 @@ export class DebugService implements IDebugService { * main entry point * properly manages compounds, checks for errors and handles the initializing state. */ - startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions): Promise { + async startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions): Promise { this.startInitializingState(); - // make sure to save all files and that the configuration is up to date - return this.extensionService.activateByEvent('onDebug').then(() => { - return this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration(launch ? launch.workspace : undefined).then(() => { - return this.extensionService.whenInstalledExtensionsRegistered().then(() => { + try { + // make sure to save all files and that the configuration is up to date + await this.extensionService.activateByEvent('onDebug'); + await this.textFileService.saveAll(); + await this.configurationService.reloadConfiguration(launch ? launch.workspace : undefined); + await this.extensionService.whenInstalledExtensionsRegistered(); - let config: IConfig | undefined; - let compound: ICompound | undefined; - if (!configOrName) { - configOrName = this.configurationManager.selectedConfiguration.name; + let config: IConfig | undefined; + let compound: ICompound | undefined; + if (!configOrName) { + configOrName = this.configurationManager.selectedConfiguration.name; + } + if (typeof configOrName === 'string' && launch) { + config = launch.getConfiguration(configOrName); + compound = launch.getCompound(configOrName); + + const sessions = this.model.getSessions(); + const alreadyRunningMessage = nls.localize('configurationAlreadyRunning', "There is already a debug configuration \"{0}\" running.", configOrName); + if (sessions.some(s => s.configuration.name === configOrName && (!launch || !launch.workspace || !s.root || s.root.uri.toString() === launch.workspace.uri.toString()))) { + throw new Error(alreadyRunningMessage); + } + if (compound && compound.configurations && sessions.some(p => compound!.configurations.indexOf(p.configuration.name) !== -1)) { + throw new Error(alreadyRunningMessage); + } + } else if (typeof configOrName !== 'string') { + config = configOrName; + } + + if (compound) { + // we are starting a compound debug, first do some error checking and than start each configuration in the compound + if (!compound.configurations) { + throw new Error(nls.localize({ key: 'compoundMustHaveConfigurations', comment: ['compound indicates a "compounds" configuration item', '"configurations" is an attribute and should not be localized'] }, + "Compound must have \"configurations\" attribute set in order to start multiple configurations.")); + } + if (compound.preLaunchTask) { + const taskResult = await this.runTaskAndCheckErrors(launch?.workspace || this.contextService.getWorkspace(), compound.preLaunchTask); + if (taskResult === TaskRunResult.Failure) { + this.endInitializingState(); + return false; } - if (typeof configOrName === 'string' && launch) { - config = launch.getConfiguration(configOrName); - compound = launch.getCompound(configOrName); + } - const sessions = this.model.getSessions(); - const alreadyRunningMessage = nls.localize('configurationAlreadyRunning', "There is already a debug configuration \"{0}\" running.", configOrName); - if (sessions.some(s => s.configuration.name === configOrName && (!launch || !launch.workspace || !s.root || s.root.uri.toString() === launch.workspace.uri.toString()))) { - return Promise.reject(new Error(alreadyRunningMessage)); + const values = await Promise.all(compound.configurations.map(configData => { + const name = typeof configData === 'string' ? configData : configData.name; + if (name === compound!.name) { + return Promise.resolve(false); + } + + let launchForName: ILaunch | undefined; + if (typeof configData === 'string') { + const launchesContainingName = this.configurationManager.getLaunches().filter(l => !!l.getConfiguration(name)); + if (launchesContainingName.length === 1) { + launchForName = launchesContainingName[0]; + } else if (launch && launchesContainingName.length > 1 && launchesContainingName.indexOf(launch) >= 0) { + // If there are multiple launches containing the configuration give priority to the configuration in the current launch + launchForName = launch; + } else { + throw new Error(launchesContainingName.length === 0 ? nls.localize('noConfigurationNameInWorkspace', "Could not find launch configuration '{0}' in the workspace.", name) + : nls.localize('multipleConfigurationNamesInWorkspace', "There are multiple launch configurations '{0}' in the workspace. Use folder name to qualify the configuration.", name)); } - if (compound && compound.configurations && sessions.some(p => compound!.configurations.indexOf(p.configuration.name) !== -1)) { - return Promise.reject(new Error(alreadyRunningMessage)); + } else if (configData.folder) { + const launchesMatchingConfigData = this.configurationManager.getLaunches().filter(l => l.workspace && l.workspace.name === configData.folder && !!l.getConfiguration(configData.name)); + if (launchesMatchingConfigData.length === 1) { + launchForName = launchesMatchingConfigData[0]; + } else { + throw new Error(nls.localize('noFolderWithName', "Can not find folder with name '{0}' for configuration '{1}' in compound '{2}'.", configData.folder, configData.name, compound!.name)); } - } else if (typeof configOrName !== 'string') { - config = configOrName; } - if (compound) { - // we are starting a compound debug, first do some error checking and than start each configuration in the compound - if (!compound.configurations) { - return Promise.reject(new Error(nls.localize({ key: 'compoundMustHaveConfigurations', comment: ['compound indicates a "compounds" configuration item', '"configurations" is an attribute and should not be localized'] }, - "Compound must have \"configurations\" attribute set in order to start multiple configurations."))); - } + return this.createSession(launchForName, launchForName!.getConfiguration(name), options); + })); - return Promise.all(compound.configurations.map(configData => { - const name = typeof configData === 'string' ? configData : configData.name; - if (name === compound!.name) { - return Promise.resolve(false); - } + const result = values.every(success => !!success); // Compound launch is a success only if each configuration launched successfully + this.endInitializingState(); + return result; + } - let launchForName: ILaunch | undefined; - if (typeof configData === 'string') { - const launchesContainingName = this.configurationManager.getLaunches().filter(l => !!l.getConfiguration(name)); - if (launchesContainingName.length === 1) { - launchForName = launchesContainingName[0]; - } else if (launch && launchesContainingName.length > 1 && launchesContainingName.indexOf(launch) >= 0) { - // If there are multiple launches containing the configuration give priority to the configuration in the current launch - launchForName = launch; - } else { - return Promise.reject(new Error(launchesContainingName.length === 0 ? nls.localize('noConfigurationNameInWorkspace', "Could not find launch configuration '{0}' in the workspace.", name) - : nls.localize('multipleConfigurationNamesInWorkspace', "There are multiple launch configurations '{0}' in the workspace. Use folder name to qualify the configuration.", name))); - } - } else if (configData.folder) { - const launchesMatchingConfigData = this.configurationManager.getLaunches().filter(l => l.workspace && l.workspace.name === configData.folder && !!l.getConfiguration(configData.name)); - if (launchesMatchingConfigData.length === 1) { - launchForName = launchesMatchingConfigData[0]; - } else { - return Promise.reject(new Error(nls.localize('noFolderWithName', "Can not find folder with name '{0}' for configuration '{1}' in compound '{2}'.", configData.folder, configData.name, compound!.name))); - } - } + if (configOrName && !config) { + const message = !!launch ? nls.localize('configMissing', "Configuration '{0}' is missing in 'launch.json'.", typeof configOrName === 'string' ? configOrName : JSON.stringify(configOrName)) : + nls.localize('launchJsonDoesNotExist', "'launch.json' does not exist."); + throw new Error(message); + } - return this.createSession(launchForName, launchForName!.getConfiguration(name), options); - })).then(values => values.every(success => !!success)); // Compound launch is a success only if each configuration launched successfully - } - - if (configOrName && !config) { - const message = !!launch ? nls.localize('configMissing', "Configuration '{0}' is missing in 'launch.json'.", typeof configOrName === 'string' ? configOrName : JSON.stringify(configOrName)) : - nls.localize('launchJsonDoesNotExist', "'launch.json' does not exist."); - return Promise.reject(new Error(message)); - } - - return this.createSession(launch, config, options); - }); - })); - }).then(success => { + const result = await this.createSession(launch, config, options); + this.endInitializingState(); + return result; + } catch (err) { // make sure to get out of initializing state, and propagate the result - this.endInitializingState(); - return success; - }, err => { this.endInitializingState(); return Promise.reject(err); - }); + } } /** * gets the debugger for the type, resolves configurations by providers, substitutes variables and runs prelaunch tasks */ - private createSession(launch: ILaunch | undefined, config: IConfig | undefined, options?: IDebugSessionOptions): Promise { + private async createSession(launch: ILaunch | undefined, config: IConfig | undefined, options?: IDebugSessionOptions): Promise { // We keep the debug type in a separate variable 'type' so that a no-folder config has no attributes. // Storing the type in the config would break extensions that assume that the no-folder case is indicated by an empty config. let type: string | undefined; @@ -358,66 +367,71 @@ export class DebugService implements IDebugService { config!.noDebug = true; } - const debuggerThenable: Promise = type ? Promise.resolve() : this.configurationManager.guessDebugger().then(dbgr => { type = dbgr && dbgr.type; }); - return debuggerThenable.then(() => { - this.initCancellationToken = new CancellationTokenSource(); - return this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!, this.initCancellationToken.token).then(config => { - // a falsy config indicates an aborted launch - if (config && config.type) { - return this.substituteVariables(launch, config).then(resolvedConfig => { + if (!type) { + const guess = await this.configurationManager.guessDebugger(); + if (guess) { + type = guess.type; + } + } - if (!resolvedConfig) { - // User canceled resolving of interactive variables, silently return - return false; - } + this.initCancellationToken = new CancellationTokenSource(); + const configByProviders = await this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!, this.initCancellationToken.token); + // a falsy config indicates an aborted launch + if (configByProviders && configByProviders.type) { + try { + const resolvedConfig = await this.substituteVariables(launch, configByProviders); - if (!this.configurationManager.getDebugger(resolvedConfig.type) || (config.request !== 'attach' && config.request !== 'launch')) { - let message: string; - if (config.request !== 'attach' && config.request !== 'launch') { - message = config.request ? nls.localize('debugRequestNotSupported', "Attribute '{0}' has an unsupported value '{1}' in the chosen debug configuration.", 'request', config.request) - : nls.localize('debugRequesMissing', "Attribute '{0}' is missing from the chosen debug configuration.", 'request'); - - } else { - message = resolvedConfig.type ? nls.localize('debugTypeNotSupported', "Configured debug type '{0}' is not supported.", resolvedConfig.type) : - nls.localize('debugTypeMissing', "Missing property 'type' for the chosen launch configuration."); - } - - return this.showError(message).then(() => false); - } - - const workspace = launch ? launch.workspace : undefined; - return this.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask).then(result => { - if (result === TaskRunResult.Success) { - return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options); - } - return false; - }); - }, err => { - if (err && err.message) { - return this.showError(err.message).then(() => false); - } - if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - return this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved and that you have a debug extension installed for that file type.")) - .then(() => false); - } - - return !!launch && launch.openConfigFile(false, true, undefined, this.initCancellationToken ? this.initCancellationToken.token : undefined).then(() => false); - }); + if (!resolvedConfig) { + // User canceled resolving of interactive variables, silently return + return false; } - if (launch && type && config === null) { // show launch.json only for "config" being "null". - return launch.openConfigFile(false, true, type, this.initCancellationToken ? this.initCancellationToken.token : undefined).then(() => false); + if (!this.configurationManager.getDebugger(resolvedConfig.type) || (configByProviders.request !== 'attach' && configByProviders.request !== 'launch')) { + let message: string; + if (configByProviders.request !== 'attach' && configByProviders.request !== 'launch') { + message = configByProviders.request ? nls.localize('debugRequestNotSupported', "Attribute '{0}' has an unsupported value '{1}' in the chosen debug configuration.", 'request', configByProviders.request) + : nls.localize('debugRequesMissing', "Attribute '{0}' is missing from the chosen debug configuration.", 'request'); + + } else { + message = resolvedConfig.type ? nls.localize('debugTypeNotSupported', "Configured debug type '{0}' is not supported.", resolvedConfig.type) : + nls.localize('debugTypeMissing', "Missing property 'type' for the chosen launch configuration."); + } + + await this.showError(message); + return false; + } + + const workspace = launch ? launch.workspace : this.contextService.getWorkspace(); + const taskResult = await this.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask); + if (taskResult === TaskRunResult.Success) { + return this.doCreateSession(launch?.workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options); + } + return false; + } catch (err) { + if (err && err.message) { + await this.showError(err.message); + } else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + await this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved and that you have a debug extension installed for that file type.")); + } + if (launch) { + await launch.openConfigFile(false, true, undefined, this.initCancellationToken ? this.initCancellationToken.token : undefined); } return false; - }); - }); + } + } + + if (launch && type && configByProviders === null) { // show launch.json only for "config" being "null". + await launch.openConfigFile(false, true, type, this.initCancellationToken ? this.initCancellationToken.token : undefined); + } + + return false; } /** * instantiates the new session, initializes the session, registers session listeners and reports telemetry */ - private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, options?: IDebugSessionOptions): Promise { + private async doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, options?: IDebugSessionOptions): Promise { const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model, options); this.model.addSession(session); @@ -431,10 +445,11 @@ export class DebugService implements IDebugService { const openDebug = this.configurationService.getValue('debug').openDebug; // Open debug viewlet based on the visibility of the side bar and openDebug setting. Do not open for 'run without debug' if (!configuration.resolved.noDebug && (openDebug === 'openOnSessionStart' || (openDebug === 'openOnFirstSessionStart' && this.viewModel.firstSessionStart))) { - this.viewletService.openViewlet(VIEWLET_ID).then(undefined, errors.onUnexpectedError); + await this.viewletService.openViewlet(VIEWLET_ID); } - return this.launchOrAttachToSession(session).then(() => { + try { + await this.launchOrAttachToSession(session); const internalConsoleOptions = session.configuration.internalConsoleOptions || this.configurationService.getValue('debug').internalConsoleOptions; if (internalConsoleOptions === 'openOnSessionStart' || (this.viewModel.firstSessionStart && internalConsoleOptions === 'openOnFirstSessionStart')) { @@ -452,12 +467,14 @@ export class DebugService implements IDebugService { // since the initialized response has arrived announce the new Session (including extensions) this._onDidNewSession.fire(session); - return this.telemetryDebugSessionStart(root, session.configuration.type); - }).then(() => true, (error: Error | string) => { + await this.telemetryDebugSessionStart(root, session.configuration.type); + + return true; + } catch (error) { if (errors.isPromiseCanceledError(error)) { // don't show 'canceled' error messages to the user #7906 - return Promise.resolve(false); + return false; } // Show the repl if some error got logged there #5870 @@ -467,27 +484,29 @@ export class DebugService implements IDebugService { if (session.configuration && session.configuration.request === 'attach' && session.configuration.__autoAttach) { // ignore attach timeouts in auto attach mode - return Promise.resolve(false); + return false; } const errorMessage = error instanceof Error ? error.message : error; this.telemetryDebugMisconfiguration(session.configuration ? session.configuration.type : undefined, errorMessage); - return this.showError(errorMessage, isErrorWithActions(error) ? error.actions : []).then(() => false); - }); + + await this.showError(errorMessage, isErrorWithActions(error) ? error.actions : []); + return false; + } } - private launchOrAttachToSession(session: IDebugSession, forceFocus = false): Promise { + private async launchOrAttachToSession(session: IDebugSession, forceFocus = false): Promise { const dbgr = this.configurationManager.getDebugger(session.configuration.type); - return session.initialize(dbgr!).then(() => { - return session.launchOrAttach(session.configuration).then(() => { - if (forceFocus || !this.viewModel.focusedSession) { - this.focusStackFrame(undefined, undefined, session); - } - }); - }).then(undefined, err => { + try { + await session.initialize(dbgr!); + await session.launchOrAttach(session.configuration); + if (forceFocus || !this.viewModel.focusedSession) { + await this.focusStackFrame(undefined, undefined, session); + } + } catch (err) { session.shutdown(); return Promise.reject(err); - }); + } } private registerSessionListeners(session: IDebugSession): void { @@ -506,7 +525,7 @@ export class DebugService implements IDebugService { } })); - this.toDispose.push(session.onDidEndAdapter(adapterExitEvent => { + this.toDispose.push(session.onDidEndAdapter(async adapterExitEvent => { if (adapterExitEvent.error) { this.notificationService.error(nls.localize('debugAdapterCrash', "Debug adapter process has terminated unexpectedly ({0})", adapterExitEvent.error.message || adapterExitEvent.error.toString())); @@ -520,9 +539,11 @@ export class DebugService implements IDebugService { this.telemetryDebugSessionStop(session, adapterExitEvent); if (session.configuration.postDebugTask) { - this.runTask(session.root, session.configuration.postDebugTask).then(undefined, err => - this.notificationService.error(err) - ); + try { + await this.runTask(session.root, session.configuration.postDebugTask); + } catch (err) { + this.notificationService.error(err); + } } session.shutdown(); this.endInitializingState(); @@ -530,7 +551,7 @@ export class DebugService implements IDebugService { const focusedSession = this.viewModel.focusedSession; if (focusedSession && focusedSession.getId() === session.getId()) { - this.focusStackFrame(undefined); + await this.focusStackFrame(undefined); } if (this.model.getSessions().length === 0) { @@ -548,87 +569,93 @@ export class DebugService implements IDebugService { })); } - restartSession(session: IDebugSession, restartData?: any): Promise { - return this.textFileService.saveAll().then(() => { - const isAutoRestart = !!restartData; - const runTasks: () => Promise = () => { - if (isAutoRestart) { - // Do not run preLaunch and postDebug tasks for automatic restarts - return Promise.resolve(TaskRunResult.Success); + async restartSession(session: IDebugSession, restartData?: any): Promise { + await this.textFileService.saveAll(); + const isAutoRestart = !!restartData; + + const runTasks: () => Promise = async () => { + if (isAutoRestart) { + // Do not run preLaunch and postDebug tasks for automatic restarts + return Promise.resolve(TaskRunResult.Success); + } + + await this.runTask(session.root, session.configuration.postDebugTask); + return this.runTaskAndCheckErrors(session.root, session.configuration.preLaunchTask); + }; + + if (session.capabilities.supportsRestartRequest) { + const taskResult = await runTasks(); + if (taskResult === TaskRunResult.Success) { + await session.restart(); + } + + return; + } + + if (isExtensionHostDebugging(session.configuration)) { + const taskResult = await runTasks(); + if (taskResult === TaskRunResult.Success) { + this.extensionHostDebugService.reload(session.getId()); + } + + return; + } + + const shouldFocus = !!this.viewModel.focusedSession && session.getId() === this.viewModel.focusedSession.getId(); + // If the restart is automatic -> disconnect, otherwise -> terminate #55064 + if (isAutoRestart) { + await session.disconnect(true); + } else { + await session.terminate(true); + } + + return new Promise((c, e) => { + setTimeout(async () => { + const taskResult = await runTasks(); + if (taskResult !== TaskRunResult.Success) { + return; } - return this.runTask(session.root, session.configuration.postDebugTask) - .then(() => this.runTaskAndCheckErrors(session.root, session.configuration.preLaunchTask)); - }; + // Read the configuration again if a launch.json has been changed, if not just use the inmemory configuration + let needsToSubstitute = false; + let unresolved: IConfig | undefined; + const launch = session.root ? this.configurationManager.getLaunch(session.root.uri) : undefined; + if (launch) { + unresolved = launch.getConfiguration(session.configuration.name); + if (unresolved && !equals(unresolved, session.unresolvedConfiguration)) { + // Take the type from the session since the debug extension might overwrite it #21316 + unresolved.type = session.configuration.type; + unresolved.noDebug = session.configuration.noDebug; + needsToSubstitute = true; + } + } - if (session.capabilities.supportsRestartRequest) { - return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? session.restart() : undefined); - } + let resolved: IConfig | undefined | null = session.configuration; + if (launch && needsToSubstitute && unresolved) { + this.initCancellationToken = new CancellationTokenSource(); + const resolvedByProviders = await this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved, this.initCancellationToken.token); + if (resolvedByProviders) { + resolved = await this.substituteVariables(launch, resolvedByProviders); + } else { + resolved = resolvedByProviders; + } + } - if (isExtensionHostDebugging(session.configuration)) { - return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? this.extensionHostDebugService.reload(session.getId()) : undefined); - } + if (!resolved) { + return c(undefined); + } - const shouldFocus = !!this.viewModel.focusedSession && session.getId() === this.viewModel.focusedSession.getId(); - // If the restart is automatic -> disconnect, otherwise -> terminate #55064 - return (isAutoRestart ? session.disconnect(true) : session.terminate(true)).then(() => { + session.setConfiguration({ resolved, unresolved }); + session.configuration.__restart = restartData; - return new Promise((c, e) => { - setTimeout(() => { - runTasks().then(taskResult => { - if (taskResult !== TaskRunResult.Success) { - return; - } - - // Read the configuration again if a launch.json has been changed, if not just use the inmemory configuration - let needsToSubstitute = false; - let unresolved: IConfig | undefined; - const launch = session.root ? this.configurationManager.getLaunch(session.root.uri) : undefined; - if (launch) { - unresolved = launch.getConfiguration(session.configuration.name); - if (unresolved && !equals(unresolved, session.unresolvedConfiguration)) { - // Take the type from the session since the debug extension might overwrite it #21316 - unresolved.type = session.configuration.type; - unresolved.noDebug = session.configuration.noDebug; - needsToSubstitute = true; - } - } - - let substitutionThenable: Promise = Promise.resolve(session.configuration); - if (launch && needsToSubstitute && unresolved) { - this.initCancellationToken = new CancellationTokenSource(); - substitutionThenable = this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved, this.initCancellationToken.token) - .then(resolved => { - if (resolved) { - // start debugging - return this.substituteVariables(launch, resolved); - } else if (resolved === null) { - // abort debugging silently and open launch.json - return Promise.resolve(null); - } else { - // abort debugging silently - return Promise.resolve(undefined); - } - }); - } - substitutionThenable.then(resolved => { - - if (!resolved) { - return c(undefined); - } - - session.setConfiguration({ resolved, unresolved }); - session.configuration.__restart = restartData; - - this.launchOrAttachToSession(session, shouldFocus).then(() => { - this._onDidNewSession.fire(session); - c(undefined); - }, err => e(err)); - }); - }); - }, 300); - }); - }); + try { + await this.launchOrAttachToSession(session, shouldFocus); + this._onDidNewSession.fire(session); + c(undefined); + } catch (error) { + e(error); + } + }, 300); }); } @@ -646,7 +673,7 @@ export class DebugService implements IDebugService { return Promise.all(sessions.map(s => s.terminate())); } - private substituteVariables(launch: ILaunch | undefined, config: IConfig): Promise { + private async substituteVariables(launch: ILaunch | undefined, config: IConfig): Promise { const dbg = this.configurationManager.getDebugger(config.type); if (dbg) { let folder: IWorkspaceFolder | undefined = undefined; @@ -658,12 +685,12 @@ export class DebugService implements IDebugService { folder = folders[0]; } } - return dbg.substituteVariables(folder, config).then(config => { - return config; - }, (err: Error) => { + try { + return await dbg.substituteVariables(folder, config); + } catch (err) { this.showError(err.message); return undefined; // bail out - }); + } } return Promise.resolve(config); } @@ -681,13 +708,13 @@ export class DebugService implements IDebugService { //---- task management - private runTaskAndCheckErrors(root: IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise { - - return this.runTask(root, taskId).then((taskSummary: ITaskSummary) => { + private async runTaskAndCheckErrors(root: IWorkspaceFolder | IWorkspace | undefined, taskId: string | TaskIdentifier | undefined): Promise { + try { + const taskSummary = await this.runTask(root, taskId); const errorCount = taskId ? this.markerService.getStatistics().errors : 0; const successExitCode = taskSummary && taskSummary.exitCode === 0; - const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0; + const failureExitCode = taskSummary && taskSummary.exitCode !== 0; const onTaskErrors = this.configurationService.getValue('debug').onTaskErrors; if (successExitCode || onTaskErrors === 'debugAnyway' || (errorCount === 0 && !failureExitCode)) { return TaskRunResult.Success; @@ -702,34 +729,35 @@ export class DebugService implements IDebugService { ? nls.localize('preLaunchTaskErrors', "Errors exist after running preLaunchTask '{0}'.", taskLabel) : errorCount === 1 ? nls.localize('preLaunchTaskError', "Error exists after running preLaunchTask '{0}'.", taskLabel) - : nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary.exitCode); + : nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary ? taskSummary.exitCode : 0); - return this.dialogService.show(severity.Warning, message, [nls.localize('debugAnyway', "Debug Anyway"), nls.localize('showErrors', "Show Errors"), nls.localize('cancel', "Cancel")], { + const result = await this.dialogService.show(severity.Warning, message, [nls.localize('debugAnyway', "Debug Anyway"), nls.localize('showErrors', "Show Errors"), nls.localize('cancel', "Cancel")], { checkbox: { label: nls.localize('remember', "Remember my choice in user settings"), }, cancelId: 2 - }).then(result => { - if (result.choice === 2) { - return Promise.resolve(TaskRunResult.Failure); - } - const debugAnyway = result.choice === 0; - if (result.checkboxChecked) { - this.configurationService.updateValue('debug.onTaskErrors', debugAnyway ? 'debugAnyway' : 'showErrors'); - } - if (debugAnyway) { - return TaskRunResult.Success; - } - - this.panelService.openPanel(Constants.MARKERS_PANEL_ID); - return Promise.resolve(TaskRunResult.Failure); }); - }, (err: TaskError) => { - return this.showError(err.message, [this.taskService.configureAction()]); - }); + + if (result.choice === 2) { + return Promise.resolve(TaskRunResult.Failure); + } + const debugAnyway = result.choice === 0; + if (result.checkboxChecked) { + this.configurationService.updateValue('debug.onTaskErrors', debugAnyway ? 'debugAnyway' : 'showErrors'); + } + if (debugAnyway) { + return TaskRunResult.Success; + } + + this.panelService.openPanel(Constants.MARKERS_PANEL_ID); + return Promise.resolve(TaskRunResult.Failure); + } catch (err) { + await this.showError(err.message, [this.taskService.configureAction()]); + return TaskRunResult.Failure; + } } - private runTask(root: IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise { + private async runTask(root: IWorkspace | IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise { if (!taskId) { return Promise.resolve(null); } @@ -737,58 +765,73 @@ export class DebugService implements IDebugService { return Promise.reject(new Error(nls.localize('invalidTaskReference', "Task '{0}' can not be referenced from a launch configuration that is in a different workspace folder.", typeof taskId === 'string' ? taskId : taskId.type))); } // run a task before starting a debug session - return this.taskService.getTask(root, taskId).then(task => { - if (!task) { - const errorMessage = typeof taskId === 'string' - ? nls.localize('DebugTaskNotFoundWithTaskId', "Could not find the task '{0}'.", taskId) - : nls.localize('DebugTaskNotFound', "Could not find the specified task."); - return Promise.reject(createErrorWithActions(errorMessage)); + const task = await this.taskService.getTask(root, taskId); + if (!task) { + const errorMessage = typeof taskId === 'string' + ? nls.localize('DebugTaskNotFoundWithTaskId', "Could not find the task '{0}'.", taskId) + : nls.localize('DebugTaskNotFound', "Could not find the specified task."); + return Promise.reject(createErrorWithActions(errorMessage)); + } + + // If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340 + let taskStarted = false; + const inactivePromise: Promise = new Promise((c, e) => once(e => { + // When a task isBackground it will go inactive when it is safe to launch. + // But when a background task is terminated by the user, it will also fire an inactive event. + // This means that we will not get to see the real exit code from running the task (undefined when terminated by the user). + // Catch the ProcessEnded event here, which occurs before inactive, and capture the exit code to prevent this. + return (e.kind === TaskEventKind.Inactive + || (e.kind === TaskEventKind.ProcessEnded && e.exitCode === undefined)) + && e.taskId === task._id; + }, this.taskService.onDidStateChange)(e => { + taskStarted = true; + c(e.kind === TaskEventKind.ProcessEnded ? { exitCode: e.exitCode } : null); + })); + + const promise: Promise = this.taskService.getActiveTasks().then(async (tasks): Promise => { + if (tasks.filter(t => t._id === task._id).length) { + // Check that the task isn't busy and if it is, wait for it + const busyTasks = await this.taskService.getBusyTasks(); + if (busyTasks.filter(t => t._id === task._id).length) { + taskStarted = true; + return inactivePromise; + } + // task is already running and isn't busy - nothing to do. + return Promise.resolve(null); + } + once(e => ((e.kind === TaskEventKind.Active) || (e.kind === TaskEventKind.DependsOnStarted)) && e.taskId === task._id, this.taskService.onDidStateChange)(() => { + // Task is active, so everything seems to be fine, no need to prompt after 10 seconds + // Use case being a slow running task should not be prompted even though it takes more than 10 seconds + taskStarted = true; + }); + const taskPromise = this.taskService.run(task); + if (task.configurationProperties.isBackground) { + return inactivePromise; } - // If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340 - let taskStarted = false; - const promise: Promise = this.taskService.getActiveTasks().then(tasks => { - if (tasks.filter(t => t._id === task._id).length) { - // task is already running - nothing to do. - return Promise.resolve(null); + return taskPromise; + }); + + return new Promise((c, e) => { + promise.then(result => { + taskStarted = true; + c(result); + }, error => e(error)); + + setTimeout(() => { + if (!taskStarted) { + const errorMessage = typeof taskId === 'string' + ? nls.localize('taskNotTrackedWithTaskId', "The specified task cannot be tracked.") + : nls.localize('taskNotTracked', "The task '{0}' cannot be tracked.", JSON.stringify(taskId)); + e({ severity: severity.Error, message: errorMessage }); } - once(e => ((e.kind === TaskEventKind.Active) || (e.kind === TaskEventKind.DependsOnStarted)) && e.taskId === task._id, this.taskService.onDidStateChange)(() => { - // Task is active, so everything seems to be fine, no need to prompt after 10 seconds - // Use case being a slow running task should not be prompted even though it takes more than 10 seconds - taskStarted = true; - }); - const taskPromise = this.taskService.run(task); - if (task.configurationProperties.isBackground) { - return new Promise((c, e) => once(e => e.kind === TaskEventKind.Inactive && e.taskId === task._id, this.taskService.onDidStateChange)(() => { - taskStarted = true; - c(null); - })); - } - - return taskPromise; - }); - - return new Promise((c, e) => { - promise.then(result => { - taskStarted = true; - c(result); - }, error => e(error)); - - setTimeout(() => { - if (!taskStarted) { - const errorMessage = typeof taskId === 'string' - ? nls.localize('taskNotTrackedWithTaskId', "The specified task cannot be tracked.") - : nls.localize('taskNotTracked', "The task '{0}' cannot be tracked.", JSON.stringify(taskId)); - e({ severity: severity.Error, message: errorMessage }); - } - }, 10000); - }); + }, 10000); }); } //---- focus management - focusStackFrame(stackFrame: IStackFrame | undefined, thread?: IThread, session?: IDebugSession, explicit?: boolean): void { + async focusStackFrame(stackFrame: IStackFrame | undefined, thread?: IThread, session?: IDebugSession, explicit?: boolean): Promise { if (!session) { if (stackFrame || thread) { session = stackFrame ? stackFrame.thread.session : thread!.session; @@ -817,18 +860,17 @@ export class DebugService implements IDebugService { } if (stackFrame) { - stackFrame.openInEditor(this.editorService, true).then(editor => { - if (editor) { - const control = editor.getControl(); - if (stackFrame && isCodeEditor(control) && control.hasModel()) { - const model = control.getModel(); - if (stackFrame.range.startLineNumber <= model.getLineCount()) { - const lineContent = control.getModel().getLineContent(stackFrame.range.startLineNumber); - aria.alert(nls.localize('debuggingPaused', "Debugging paused {0}, {1} {2} {3}", thread && thread.stoppedDetails ? `, reason ${thread.stoppedDetails.reason}` : '', stackFrame.source ? stackFrame.source.name : '', stackFrame.range.startLineNumber, lineContent)); - } + const editor = await stackFrame.openInEditor(this.editorService, true); + if (editor) { + const control = editor.getControl(); + if (stackFrame && isCodeEditor(control) && control.hasModel()) { + const model = control.getModel(); + if (stackFrame.range.startLineNumber <= model.getLineCount()) { + const lineContent = control.getModel().getLineContent(stackFrame.range.startLineNumber); + aria.alert(nls.localize('debuggingPaused', "Debugging paused {0}, {1} {2} {3}", thread && thread.stoppedDetails ? `, reason ${thread.stoppedDetails.reason}` : '', stackFrame.source ? stackFrame.source.name : '', stackFrame.range.startLineNumber, lineContent)); } } - }); + } } if (session) { this.debugType.set(session.configuration.type); @@ -949,12 +991,12 @@ export class DebugService implements IDebugService { this.storeBreakpoints(); } - sendAllBreakpoints(session?: IDebugSession): Promise { - return Promise.all(distinct(this.model.getBreakpoints(), bp => bp.uri.toString()).map(bp => this.sendBreakpoints(bp.uri, false, session))) - .then(() => this.sendFunctionBreakpoints(session)) - // send exception breakpoints at the end since some debug adapters rely on the order - .then(() => this.sendExceptionBreakpoints(session)) - .then(() => this.sendDataBreakpoints(session)); + async sendAllBreakpoints(session?: IDebugSession): Promise { + await Promise.all(distinct(this.model.getBreakpoints(), bp => bp.uri.toString()).map(bp => this.sendBreakpoints(bp.uri, false, session))); + await this.sendFunctionBreakpoints(session); + await this.sendDataBreakpoints(session); + // send exception breakpoints at the end since some debug adapters rely on the order + await this.sendExceptionBreakpoints(session); } private sendBreakpoints(modelUri: uri, sourceModified = false, session?: IDebugSession): Promise { @@ -989,11 +1031,12 @@ export class DebugService implements IDebugService { }); } - private sendToOneOrAllSessions(session: IDebugSession | undefined, send: (session: IDebugSession) => Promise): Promise { + private async sendToOneOrAllSessions(session: IDebugSession | undefined, send: (session: IDebugSession) => Promise): Promise { if (session) { - return send(session); + await send(session); + } else { + await Promise.all(this.model.getSessions().map(s => send(s))); } - return Promise.all(this.model.getSessions().map(s => send(s))).then(() => undefined); } private onFileChanges(fileChangesEvent: FileChangesEvent): void { diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 7e9679a260e..89f0cb1e6d2 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -30,8 +30,6 @@ import { Range } from 'vs/editor/common/core/range'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { INotificationService } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { variableSetEmitter } from 'vs/workbench/contrib/debug/browser/variablesView'; import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; @@ -65,7 +63,7 @@ export class DebugSession implements IDebugSession { constructor( private _configuration: { resolved: IConfig, unresolved: IConfig | undefined }, - public root: IWorkspaceFolder, + public root: IWorkspaceFolder | undefined, private model: DebugModel, options: IDebugSessionOptions | undefined, @IDebugService private readonly debugService: IDebugService, @@ -74,7 +72,6 @@ export class DebugSession implements IDebugSession { @IConfigurationService private readonly configurationService: IConfigurationService, @IViewletService private readonly viewletService: IViewletService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @INotificationService private readonly notificationService: INotificationService, @IProductService private readonly productService: IProductService, @IExtensionHostDebugService private readonly extensionHostDebugService: IExtensionHostDebugService, @IOpenerService private readonly openerService: IOpenerService @@ -86,6 +83,7 @@ export class DebugSession implements IDebugSession { } else { this.repl = (this.parentSession as DebugSession).repl; } + this.repl.onDidChangeElements(() => this._onDidChangeREPLElements.fire()); } getId(): string { @@ -182,110 +180,100 @@ export class DebugSession implements IDebugSession { /** * create and initialize a new debug adapter for this session */ - initialize(dbgr: IDebugger): Promise { + async initialize(dbgr: IDebugger): Promise { if (this.raw) { // if there was already a connection make sure to remove old listeners this.shutdown(); } - return dbgr.getCustomTelemetryService().then(customTelemetryService => { + try { + const customTelemetryService = await dbgr.getCustomTelemetryService(); + const debugAdapter = await dbgr.createDebugAdapter(this); + this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.extensionHostDebugService, this.openerService); - return dbgr.createDebugAdapter(this).then(debugAdapter => { - - this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.extensionHostDebugService, this.openerService); - - return this.raw.start().then(() => { - - this.registerListeners(); - - return this.raw!.initialize({ - clientID: 'vscode', - clientName: this.productService.nameLong, - adapterID: this.configuration.type, - pathFormat: 'path', - linesStartAt1: true, - columnsStartAt1: true, - supportsVariableType: true, // #8858 - supportsVariablePaging: true, // #9537 - supportsRunInTerminalRequest: true, // #10574 - locale: platform.locale - }).then(() => { - this.initialized = true; - this._onDidChangeState.fire(); - this.model.setExceptionBreakpoints(this.raw!.capabilities.exceptionBreakpointFilters || []); - }); - }); + await this.raw.start(); + this.registerListeners(); + await this.raw!.initialize({ + clientID: 'vscode', + clientName: this.productService.nameLong, + adapterID: this.configuration.type, + pathFormat: 'path', + linesStartAt1: true, + columnsStartAt1: true, + supportsVariableType: true, // #8858 + supportsVariablePaging: true, // #9537 + supportsRunInTerminalRequest: true, // #10574 + locale: platform.locale }); - }).then(undefined, err => { + this.initialized = true; this._onDidChangeState.fire(); - return Promise.reject(err); - }); + this.model.setExceptionBreakpoints(this.raw!.capabilities.exceptionBreakpointFilters || []); + } catch (err) { + this.initialized = true; + this._onDidChangeState.fire(); + throw err; + } } /** * launch or attach to the debuggee */ - launchOrAttach(config: IConfig): Promise { - if (this.raw) { - - // __sessionID only used for EH debugging (but we add it always for now...) - config.__sessionId = this.getId(); - - return this.raw.launchOrAttach(config).then(result => { - return undefined; - }); + async launchOrAttach(config: IConfig): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + // __sessionID only used for EH debugging (but we add it always for now...) + config.__sessionId = this.getId(); + await this.raw.launchOrAttach(config); + } /** * end the current debug adapter session */ - terminate(restart = false): Promise { - if (this.raw) { - this.cancelAllRequests(); - if (this.raw.capabilities.supportsTerminateRequest && this._configuration.resolved.request === 'launch') { - return this.raw.terminate(restart).then(response => { - return undefined; - }); - } - return this.raw.disconnect(restart).then(response => { - return undefined; - }); + async terminate(restart = false): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); + } + + this.cancelAllRequests(); + if (this.raw.capabilities.supportsTerminateRequest && this._configuration.resolved.request === 'launch') { + await this.raw.terminate(restart); + } else { + await this.raw.disconnect(restart); } - return Promise.reject(new Error('no debug adapter')); } /** * end the current debug adapter session */ - disconnect(restart = false): Promise { - if (this.raw) { - this.cancelAllRequests(); - return this.raw.disconnect(restart).then(response => { - return undefined; - }); + async disconnect(restart = false): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + this.cancelAllRequests(); + await this.raw.disconnect(restart); } /** * restart debug adapter session */ - restart(): Promise { - if (this.raw) { - this.cancelAllRequests(); - return this.raw.restart().then(() => undefined); + async restart(): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + this.cancelAllRequests(); + await this.raw.restart(); } - sendBreakpoints(modelUri: URI, breakpointsToSend: IBreakpoint[], sourceModified: boolean): Promise { - + async sendBreakpoints(modelUri: URI, breakpointsToSend: IBreakpoint[], sourceModified: boolean): Promise { if (!this.raw) { - return Promise.reject(new Error('no debug adapter')); + throw new Error('no debug adapter'); } if (!this.raw.readyForBreakpoints) { @@ -301,233 +289,252 @@ export class DebugSession implements IDebugSession { rawSource.path = normalizeDriveLetter(rawSource.path); } - return this.raw.setBreakpoints({ + const response = await this.raw.setBreakpoints({ source: rawSource, lines: breakpointsToSend.map(bp => bp.sessionAgnosticData.lineNumber), breakpoints: breakpointsToSend.map(bp => ({ line: bp.sessionAgnosticData.lineNumber, column: bp.sessionAgnosticData.column, condition: bp.condition, hitCondition: bp.hitCondition, logMessage: bp.logMessage })), sourceModified - }).then(response => { + }); + if (response && response.body) { + const data = new Map(); + for (let i = 0; i < breakpointsToSend.length; i++) { + data.set(breakpointsToSend[i].getId(), response.body.breakpoints[i]); + } + + this.model.setBreakpointSessionData(this.getId(), this.capabilities, data); + } + } + + async sendFunctionBreakpoints(fbpts: IFunctionBreakpoint[]): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); + } + + if (this.raw.readyForBreakpoints) { + const response = await this.raw.setFunctionBreakpoints({ breakpoints: fbpts }); if (response && response.body) { const data = new Map(); - for (let i = 0; i < breakpointsToSend.length; i++) { - data.set(breakpointsToSend[i].getId(), response.body.breakpoints[i]); + for (let i = 0; i < fbpts.length; i++) { + data.set(fbpts[i].getId(), response.body.breakpoints[i]); } - this.model.setBreakpointSessionData(this.getId(), this.capabilities, data); } - }); + } } - sendFunctionBreakpoints(fbpts: IFunctionBreakpoint[]): Promise { - if (this.raw) { - if (this.raw.readyForBreakpoints) { - return this.raw.setFunctionBreakpoints({ breakpoints: fbpts }).then(response => { - if (response && response.body) { - const data = new Map(); - for (let i = 0; i < fbpts.length; i++) { - data.set(fbpts[i].getId(), response.body.breakpoints[i]); - } - this.model.setBreakpointSessionData(this.getId(), this.capabilities, data); - } - }); - } - - return Promise.resolve(undefined); + async sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + if (this.raw.readyForBreakpoints) { + await this.raw.setExceptionBreakpoints({ filters: exbpts.map(exb => exb.filter) }); + } } - sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise { - if (this.raw) { - if (this.raw.readyForBreakpoints) { - return this.raw.setExceptionBreakpoints({ filters: exbpts.map(exb => exb.filter) }).then(() => undefined); - } - return Promise.resolve(undefined); + async dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }> { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + if (!this.raw.readyForBreakpoints) { + throw new Error(nls.localize('sessionNotReadyForBreakpoints', "Session is not ready for breakpoints")); + } + + const response = await this.raw.dataBreakpointInfo({ name, variablesReference }); + return response.body; } - dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }> { - if (this.raw) { - if (this.raw.readyForBreakpoints) { - return this.raw.dataBreakpointInfo({ name, variablesReference }).then(response => response.body); - } - return Promise.reject(new Error(nls.localize('sessionNotReadyForBreakpoints', "Session is not ready for breakpoints"))); + async sendDataBreakpoints(dataBreakpoints: IDataBreakpoint[]): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); - } - sendDataBreakpoints(dataBreakpoints: IDataBreakpoint[]): Promise { - if (this.raw) { - if (this.raw.readyForBreakpoints) { - return this.raw.setDataBreakpoints({ breakpoints: dataBreakpoints }).then(response => { - if (response && response.body) { - const data = new Map(); - for (let i = 0; i < dataBreakpoints.length; i++) { - data.set(dataBreakpoints[i].getId(), response.body.breakpoints[i]); - } - this.model.setBreakpointSessionData(this.getId(), this.capabilities, data); - } - }); + if (this.raw.readyForBreakpoints) { + const response = await this.raw.setDataBreakpoints({ breakpoints: dataBreakpoints }); + if (response && response.body) { + const data = new Map(); + for (let i = 0; i < dataBreakpoints.length; i++) { + data.set(dataBreakpoints[i].getId(), response.body.breakpoints[i]); + } + this.model.setBreakpointSessionData(this.getId(), this.capabilities, data); } - return Promise.resolve(undefined); } - return Promise.reject(new Error('no debug adapter')); } async breakpointsLocations(uri: URI, lineNumber: number): Promise { - if (this.raw) { - const source = this.getRawSource(uri); - const response = await this.raw.breakpointLocations({ source, line: lineNumber }); - const positions = response.body.breakpoints.map(bp => ({ lineNumber: bp.line, column: bp.column || 1 })); - - return distinct(positions, p => `${p.lineNumber}:${p.column}`); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + const source = this.getRawSource(uri); + const response = await this.raw.breakpointLocations({ source, line: lineNumber }); + if (!response.body || !response.body.breakpoints) { + return []; + } + + const positions = response.body.breakpoints.map(bp => ({ lineNumber: bp.line, column: bp.column || 1 })); + + return distinct(positions, p => `${p.lineNumber}:${p.column}`); } customRequest(request: string, args: any): Promise { - if (this.raw) { - return this.raw.custom(request, args); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + return this.raw.custom(request, args); } stackTrace(threadId: number, startFrame: number, levels: number): Promise { - if (this.raw) { - const token = this.getNewCancellationToken(threadId); - return this.raw.stackTrace({ threadId, startFrame, levels }, token); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + const token = this.getNewCancellationToken(threadId); + return this.raw.stackTrace({ threadId, startFrame, levels }, token); } - exceptionInfo(threadId: number): Promise { - if (this.raw) { - return this.raw.exceptionInfo({ threadId }).then(response => { - if (response) { - return { - id: response.body.exceptionId, - description: response.body.description, - breakMode: response.body.breakMode, - details: response.body.details - }; - } - return undefined; - }); + async exceptionInfo(threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + const response = await this.raw.exceptionInfo({ threadId }); + if (response) { + return { + id: response.body.exceptionId, + description: response.body.description, + breakMode: response.body.breakMode, + details: response.body.details + }; + } + + return undefined; } scopes(frameId: number, threadId: number): Promise { - if (this.raw) { - const token = this.getNewCancellationToken(threadId); - return this.raw.scopes({ frameId }, token); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + const token = this.getNewCancellationToken(threadId); + return this.raw.scopes({ frameId }, token); } variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise { - if (this.raw) { - const token = threadId ? this.getNewCancellationToken(threadId) : undefined; - return this.raw.variables({ variablesReference, filter, start, count }, token); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + const token = threadId ? this.getNewCancellationToken(threadId) : undefined; + return this.raw.variables({ variablesReference, filter, start, count }, token); } evaluate(expression: string, frameId: number, context?: string): Promise { - if (this.raw) { - return this.raw.evaluate({ expression, frameId, context }); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + return this.raw.evaluate({ expression, frameId, context }); } - restartFrame(frameId: number, threadId: number): Promise { - if (this.raw) { - return this.raw.restartFrame({ frameId }, threadId).then(() => undefined); + async restartFrame(frameId: number, threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.restartFrame({ frameId }, threadId); } - next(threadId: number): Promise { - if (this.raw) { - return this.raw.next({ threadId }).then(() => undefined); + async next(threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.next({ threadId }); } - stepIn(threadId: number): Promise { - if (this.raw) { - return this.raw.stepIn({ threadId }).then(() => undefined); + async stepIn(threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.stepIn({ threadId }); } - stepOut(threadId: number): Promise { - if (this.raw) { - return this.raw.stepOut({ threadId }).then(() => undefined); + async stepOut(threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.stepOut({ threadId }); } - stepBack(threadId: number): Promise { - if (this.raw) { - return this.raw.stepBack({ threadId }).then(() => undefined); + async stepBack(threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.stepBack({ threadId }); } - continue(threadId: number): Promise { - if (this.raw) { - return this.raw.continue({ threadId }).then(() => undefined); + async continue(threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.continue({ threadId }); } - reverseContinue(threadId: number): Promise { - if (this.raw) { - return this.raw.reverseContinue({ threadId }).then(() => undefined); + async reverseContinue(threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.reverseContinue({ threadId }); } - pause(threadId: number): Promise { - if (this.raw) { - return this.raw.pause({ threadId }).then(() => undefined); + async pause(threadId: number): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.pause({ threadId }); } - terminateThreads(threadIds?: number[]): Promise { - if (this.raw) { - return this.raw.terminateThreads({ threadIds }).then(() => undefined); + async terminateThreads(threadIds?: number[]): Promise { + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + await this.raw.terminateThreads({ threadIds }); } setVariable(variablesReference: number, name: string, value: string): Promise { - if (this.raw) { - return this.raw.setVariable({ variablesReference, name, value }); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + return this.raw.setVariable({ variablesReference, name, value }); } gotoTargets(source: DebugProtocol.Source, line: number, column?: number): Promise { - if (this.raw) { - return this.raw.gotoTargets({ source, line, column }); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + return this.raw.gotoTargets({ source, line, column }); } goto(threadId: number, targetId: number): Promise { - if (this.raw) { - return this.raw.goto({ threadId, targetId }); + if (!this.raw) { + throw new Error('no debug adapter'); } - return Promise.reject(new Error('no debug adapter')); + + return this.raw.goto({ threadId, targetId }); } loadSource(resource: URI): Promise { - if (!this.raw) { return Promise.reject(new Error('no debug adapter')); } @@ -545,50 +552,48 @@ export class DebugSession implements IDebugSession { return this.raw.source({ sourceReference: rawSource.sourceReference || 0, source: rawSource }); } - getLoadedSources(): Promise { - if (this.raw) { - return this.raw.loadedSources({}).then(response => { - if (response.body && response.body.sources) { - return response.body.sources.map(src => this.getSource(src)); - } else { - return []; - } - }, () => { - return []; - }); + async getLoadedSources(): Promise { + if (!this.raw) { + return Promise.reject(new Error('no debug adapter')); + } + + const response = await this.raw.loadedSources({}); + if (response.body && response.body.sources) { + return response.body.sources.map(src => this.getSource(src)); + } else { + return []; } - return Promise.reject(new Error('no debug adapter')); } - completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise { - if (this.raw) { - return this.raw.completions({ - frameId, - text, - column: position.column, - line: position.lineNumber, - }, token).then(response => { + async completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise { + if (!this.raw) { + return Promise.reject(new Error('no debug adapter')); + } - const result: CompletionItem[] = []; - if (response && response.body && response.body.targets) { - response.body.targets.forEach(item => { - if (item && item.label) { - result.push({ - label: item.label, - insertText: item.text || item.label, - kind: completionKindFromString(item.type || 'property'), - filterText: (item.start && item.length) ? text.substr(item.start, item.length).concat(item.label) : undefined, - range: Range.fromPositions(position.delta(0, -(item.length || overwriteBefore)), position), - sortText: item.sortText - }); - } + const response = await this.raw.completions({ + frameId, + text, + column: position.column, + line: position.lineNumber, + }, token); + + const result: CompletionItem[] = []; + if (response && response.body && response.body.targets) { + response.body.targets.forEach(item => { + if (item && item.label) { + result.push({ + label: item.label, + insertText: item.text || item.label, + kind: completionKindFromString(item.type || 'property'), + filterText: (item.start && item.length) ? text.substr(item.start, item.length).concat(item.label) : undefined, + range: Range.fromPositions(position.delta(0, -(item.length || overwriteBefore)), position), + sortText: item.sortText }); } - - return result; }); } - return Promise.reject(new Error('no debug adapter')); + + return result; } //---- threads @@ -673,8 +678,9 @@ export class DebugSession implements IDebugSession { } } - private fetchThreads(stoppedDetails?: IRawStoppedDetails): Promise { - return this.raw ? this.raw.threads().then(response => { + private async fetchThreads(stoppedDetails?: IRawStoppedDetails): Promise { + if (this.raw) { + const response = await this.raw.threads(); if (response && response.body && response.body.threads) { this.model.rawUpdate({ sessionId: this.getId(), @@ -682,7 +688,7 @@ export class DebugSession implements IDebugSession { stoppedDetails }); } - }) : Promise.resolve(undefined); + } } //---- private @@ -692,60 +698,63 @@ export class DebugSession implements IDebugSession { return; } - this.rawListeners.push(this.raw.onDidInitialize(() => { + this.rawListeners.push(this.raw.onDidInitialize(async () => { aria.status(nls.localize('debuggingStarted', "Debugging started.")); - const sendConfigurationDone = () => { + const sendConfigurationDone = async () => { if (this.raw && this.raw.capabilities.supportsConfigurationDoneRequest) { - return this.raw.configurationDone().then(undefined, e => { + try { + await this.raw.configurationDone(); + } catch (e) { // Disconnect the debug session on configuration done error #10596 if (this.raw) { this.raw.disconnect(); } - if (e.command !== 'canceled' && e.message !== 'canceled') { - this.notificationService.error(e); - } - }); + } } return undefined; }; // Send all breakpoints - this.debugService.sendAllBreakpoints(this).then(sendConfigurationDone, sendConfigurationDone) - .then(() => this.fetchThreads()); + try { + await this.debugService.sendAllBreakpoints(this); + } finally { + await sendConfigurationDone(); + } + await this.fetchThreads(); })); - this.rawListeners.push(this.raw.onDidStop(event => { - this.fetchThreads(event.body).then(() => { - const thread = typeof event.body.threadId === 'number' ? this.getThread(event.body.threadId) : undefined; - if (thread) { - // Call fetch call stack twice, the first only return the top stack frame. - // Second retrieves the rest of the call stack. For performance reasons #25605 - const promises = this.model.fetchCallStack(thread); - const focus = () => { - if (!event.body.preserveFocusHint && thread.getCallStack().length) { - this.debugService.focusStackFrame(undefined, thread); - if (thread.stoppedDetails) { - if (this.configurationService.getValue('debug').openDebug === 'openOnDebugBreak') { - this.viewletService.openViewlet(VIEWLET_ID); - } + this.rawListeners.push(this.raw.onDidStop(async event => { + await this.fetchThreads(event.body); + const thread = typeof event.body.threadId === 'number' ? this.getThread(event.body.threadId) : undefined; + if (thread) { + // Call fetch call stack twice, the first only return the top stack frame. + // Second retrieves the rest of the call stack. For performance reasons #25605 + const promises = this.model.fetchCallStack(thread); + const focus = async () => { + if (!event.body.preserveFocusHint && thread.getCallStack().length) { + await this.debugService.focusStackFrame(undefined, thread); + if (thread.stoppedDetails) { + if (this.configurationService.getValue('debug').openDebug === 'openOnDebugBreak') { + this.viewletService.openViewlet(VIEWLET_ID); + } - if (this.configurationService.getValue('debug').focusWindowOnBreak) { - this.hostService.focus(); - } + if (this.configurationService.getValue('debug').focusWindowOnBreak) { + this.hostService.focus(); } } - }; + } + }; - promises.topCallStack.then(focus); - promises.wholeCallStack.then(() => { - if (!this.debugService.getViewModel().focusedStackFrame) { - // The top stack frame can be deemphesized so try to focus again #68616 - focus(); - } - }); + await promises.topCallStack; + focus(); + await promises.wholeCallStack; + if (!this.debugService.getViewModel().focusedStackFrame) { + // The top stack frame can be deemphesized so try to focus again #68616 + focus(); } - }).then(() => this._onDidChangeState.fire()); + } + this._onDidChangeState.fire(); })); this.rawListeners.push(this.raw.onDidThread(event => { @@ -762,15 +771,21 @@ export class DebugSession implements IDebugSession { } } else if (event.body.reason === 'exited') { this.model.clearThreads(this.getId(), true, event.body.threadId); + const viewModel = this.debugService.getViewModel(); + const focusedThread = viewModel.focusedThread; + if (focusedThread && event.body.threadId === focusedThread.threadId) { + // De-focus the thread in case it was focused + this.debugService.focusStackFrame(undefined, undefined, viewModel.focusedSession, false); + } } })); - this.rawListeners.push(this.raw.onDidTerminateDebugee(event => { + this.rawListeners.push(this.raw.onDidTerminateDebugee(async event => { aria.status(nls.localize('debuggingStopped', "Debugging stopped.")); if (event.body && event.body.restart) { - this.debugService.restartSession(this, event.body.restart).then(undefined, onUnexpectedError); + await this.debugService.restartSession(this, event.body.restart); } else if (this.raw) { - this.raw.disconnect(); + await this.raw.disconnect(); } })); @@ -791,7 +806,7 @@ export class DebugSession implements IDebugSession { })); let outpuPromises: Promise[] = []; - this.rawListeners.push(this.raw.onDidOutput(event => { + this.rawListeners.push(this.raw.onDidOutput(async event => { if (!event.body || !this.raw) { return; } @@ -817,17 +832,21 @@ export class DebugSession implements IDebugSession { } : undefined; if (event.body.variablesReference) { const container = new ExpressionContainer(this, undefined, event.body.variablesReference, generateUuid()); - outpuPromises.push(container.getChildren().then(children => { - return Promise.all(waitFor).then(() => children.forEach(child => { + outpuPromises.push(container.getChildren().then(async children => { + await Promise.all(waitFor); + children.forEach(child => { // Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names) (child).name = null; this.appendToRepl(child, outputSeverity, source); - })); + }); })); } else if (typeof event.body.output === 'string') { - Promise.all(waitFor).then(() => this.appendToRepl(event.body.output, outputSeverity, source)); + await Promise.all(waitFor); + this.appendToRepl(event.body.output, outputSeverity, source); } - Promise.all(outpuPromises).then(() => outpuPromises = []); + + await Promise.all(outpuPromises); + outpuPromises = []; })); this.rawListeners.push(this.raw.onDidBreakpoint(event => { @@ -967,25 +986,19 @@ export class DebugSession implements IDebugSession { removeReplExpressions(): void { this.repl.removeReplExpressions(); - this._onDidChangeREPLElements.fire(); } async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise { - const expressionEvaluated = this.repl.addReplExpression(this, stackFrame, name); - this._onDidChangeREPLElements.fire(); - await expressionEvaluated; - this._onDidChangeREPLElements.fire(); + await this.repl.addReplExpression(this, stackFrame, name); // Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some. variableSetEmitter.fire(); } appendToRepl(data: string | IExpression, severity: severity, source?: IReplElementSource): void { this.repl.appendToRepl(this, data, severity, source); - this._onDidChangeREPLElements.fire(); } logToRepl(sev: severity, args: any[], frame?: { uri: URI, line: number, column: number }) { this.repl.logToRepl(this, sev, args, frame); - this._onDidChangeREPLElements.fire(); } } diff --git a/src/vs/workbench/contrib/debug/browser/debugStatus.ts b/src/vs/workbench/contrib/debug/browser/debugStatus.ts index 20f73614519..ac48ec84a4e 100644 --- a/src/vs/workbench/contrib/debug/browser/debugStatus.ts +++ b/src/vs/workbench/contrib/debug/browser/debugStatus.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IDebugService, State, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IStatusbarEntry, IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarEntry, IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/common/statusbar'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index ba384a37df3..781ac16a5de 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -19,7 +19,7 @@ import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/co import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Themable } from 'vs/workbench/common/theme'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService'; import { registerColor, contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { localize } from 'vs/nls'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -41,12 +41,67 @@ export const debugToolBarBackground = registerColor('debugToolBar.background', { light: '#F3F3F3', hc: '#000000' }, localize('debugToolBarBackground', "Debug toolbar background color.")); + export const debugToolBarBorder = registerColor('debugToolBar.border', { dark: null, light: null, hc: null }, localize('debugToolBarBorder', "Debug toolbar border color.")); +export const debugIconStartForeground = registerColor('debugIcon.startForeground', { + dark: '#89D185', + light: '#388A34', + hc: '#89D185' +}, localize('debugIcon.startForeground', "Debug toolbar icon for start debugging.")); + +export const debugIconPauseForeground = registerColor('debugIcon.pauseForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('debugIcon.pauseForeground', "Debug toolbar icon for pause.")); + +export const debugIconStopForeground = registerColor('debugIcon.stopForeground', { + dark: '#F48771', + light: '#A1260D', + hc: '#F48771' +}, localize('debugIcon.stopForeground', "Debug toolbar icon for stop.")); + +export const debugIconDisconnectForeground = registerColor('debugIcon.disconnectForeground', { + dark: '#F48771', + light: '#A1260D', + hc: '#F48771' +}, localize('debugIcon.disconnectForeground', "Debug toolbar icon for disconnect.")); + +export const debugIconRestartForeground = registerColor('debugIcon.restartForeground', { + dark: '#89D185', + light: '#388A34', + hc: '#89D185' +}, localize('debugIcon.restartForeground', "Debug toolbar icon for restart.")); + +export const debugIconStepOverForeground = registerColor('debugIcon.stepOverForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('debugIcon.stepOverForeground', "Debug toolbar icon for step over.")); + +export const debugIconStepIntoForeground = registerColor('debugIcon.stepIntoForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('debugIcon.stepIntoForeground', "Debug toolbar icon for step into.")); + +export const debugIconStepOutForeground = registerColor('debugIcon.stepOutForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('debugIcon.stepOutForeground', "Debug toolbar icon for step over.")); + +export const debugIconContinueForeground = registerColor('debugIcon.continueForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('debugIcon.continueForeground', "Debug toolbar icon for continue.")); + export class DebugToolBar extends Themable implements IWorkbenchContribution { private $el: HTMLElement; @@ -176,7 +231,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { }); })); - this._register(this.layoutService.onTitleBarVisibilityChange(() => this.setYCoordinate())); + this._register(this.layoutService.onPartVisibilityChange(() => this.setYCoordinate())); this._register(browser.onDidChangeZoomLevel(() => this.setYCoordinate())); } @@ -192,10 +247,10 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { super.updateStyles(); if (this.$el) { - this.$el.style.backgroundColor = this.getColor(debugToolBarBackground); + this.$el.style.backgroundColor = this.getColor(debugToolBarBackground) || ''; const widgetShadowColor = this.getColor(widgetShadow); - this.$el.style.boxShadow = widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : null; + this.$el.style.boxShadow = widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : ''; const contrastBorderColor = this.getColor(contrastBorder); const borderColor = this.getColor(debugToolBarBorder); @@ -289,3 +344,51 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { } } } + +registerThemingParticipant((theme, collector) => { + + const debugIconStartColor = theme.getColor(debugIconStartForeground); + if (debugIconStartColor) { + collector.addRule(`.monaco-workbench .codicon-debug-start { color: ${debugIconStartColor} !important; }`); + } + + const debugIconPauseColor = theme.getColor(debugIconPauseForeground); + if (debugIconPauseColor) { + collector.addRule(`.monaco-workbench .codicon-debug-pause { color: ${debugIconPauseColor} !important; }`); + } + + const debugIconStopColor = theme.getColor(debugIconStopForeground); + if (debugIconStopColor) { + collector.addRule(`.monaco-workbench .codicon-debug-stop { color: ${debugIconStopColor} !important; }`); + } + + const debugIconDisconnectColor = theme.getColor(debugIconDisconnectForeground); + if (debugIconDisconnectColor) { + collector.addRule(`.monaco-workbench .codicon-debug-disconnect { color: ${debugIconDisconnectColor} !important; }`); + } + + const debugIconRestartColor = theme.getColor(debugIconRestartForeground); + if (debugIconRestartColor) { + collector.addRule(`.monaco-workbench .codicon-debug-restart { color: ${debugIconRestartColor} !important; }`); + } + + const debugIconStepOverColor = theme.getColor(debugIconStepOverForeground); + if (debugIconStepOverColor) { + collector.addRule(`.monaco-workbench .codicon-debug-step-over { color: ${debugIconStepOverColor} !important; }`); + } + + const debugIconStepIntoColor = theme.getColor(debugIconStepIntoForeground); + if (debugIconStepIntoColor) { + collector.addRule(`.monaco-workbench .codicon-debug-step-into { color: ${debugIconStepIntoColor} !important; }`); + } + + const debugIconStepOutColor = theme.getColor(debugIconStepOutForeground); + if (debugIconStepOutColor) { + collector.addRule(`.monaco-workbench .codicon-debug-step-out { color: ${debugIconStepOutColor} !important; }`); + } + + const debugIconContinueColor = theme.getColor(debugIconContinueForeground); + if (debugIconContinueColor) { + collector.addRule(`.monaco-workbench .codicon-debug-continue { color: ${debugIconContinueColor} !important; }`); + } +}); diff --git a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts index 10681dbeda0..b3eb22bde17 100644 --- a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts +++ b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts @@ -214,12 +214,12 @@ export class DebugViewlet extends ViewContainerViewlet { class ToggleReplAction extends TogglePanelAction { static readonly ID = 'debug.toggleRepl'; - static LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugConsoleAction' }, 'Debug Console'); + static readonly LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugConsoleAction' }, 'Debug Console'); constructor(id: string, label: string, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IPanelService panelService: IPanelService ) { - super(id, label, REPL_ID, panelService, layoutService, 'debug-action toggle-repl'); + super(id, label, REPL_ID, panelService, layoutService, 'debug-action codicon-terminal'); } } diff --git a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts index f8ce2c468c0..bdcd9cb8f79 100644 --- a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts @@ -5,7 +5,6 @@ import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; @@ -13,18 +12,21 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; -import { IProcessEnvironment } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; +import { mapToSerializable } from 'vs/base/common/map'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IWorkspaceProvider, IWorkspace } from 'vs/workbench/services/host/browser/browserHostService'; +import { IProcessEnvironment } from 'vs/base/common/platform'; class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient implements IExtensionHostDebugService { + private workspaceProvider: IWorkspaceProvider; + constructor( @IRemoteAgentService remoteAgentService: IRemoteAgentService, - // @IWindowService windowService: IWindowService, // TODO@weinand TODO@isidorn cyclic dependency? - @IEnvironmentService environmentService: IEnvironmentService + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService ) { const connection = remoteAgentService.getConnection(); - let channel: IChannel; if (connection) { channel = connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName); @@ -36,11 +38,21 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i super(channel); + if (environmentService.options && environmentService.options.workspaceProvider) { + this.workspaceProvider = environmentService.options.workspaceProvider; + } else { + this.workspaceProvider = { open: async () => undefined, workspace: undefined }; + console.warn('Extension Host Debugging not available due to missing workspace provider.'); + } + + // Reload window on reload request this._register(this.onReload(event => { if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) { window.location.reload(); } })); + + // Close window on close request this._register(this.onClose(event => { if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) { window.close(); @@ -48,8 +60,52 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i })); } - openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { - // we pass the "ParsedArgs" as query parameters of the URL + openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment): Promise { + + if (!this.workspaceProvider.payload) { + // TODO@Ben remove me once environment is adopted + return this.openExtensionDevelopmentHostWindowLegacy(args); + } + + // Find out which workspace to open debug window on + let debugWorkspace: IWorkspace = undefined; + const folderUriArg = this.findArgument('folder-uri', args); + if (folderUriArg) { + debugWorkspace = { folderUri: URI.parse(folderUriArg) }; + } + + // Add environment parameters required for debug to work + const environment = new Map(); + + const extensionDevelopmentPath = this.findArgument('extensionDevelopmentPath', args); + if (extensionDevelopmentPath) { + environment.set('extensionDevelopmentPath', extensionDevelopmentPath); + } + + const extensionTestsPath = this.findArgument('extensionTestsPath', args); + if (extensionTestsPath) { + environment.set('extensionTestsPath', extensionTestsPath); + } + + const debugId = this.findArgument('debugId', args); + if (debugId) { + environment.set('debugId', debugId); + } + + const inspectBrkExtensions = this.findArgument('inspect-brk-extensions', args); + if (inspectBrkExtensions) { + environment.set('inspect-brk-extensions', inspectBrkExtensions); + } + + // Open debug window as new window. Pass ParsedArgs over. + return this.workspaceProvider.open(debugWorkspace, { + reuse: false, // debugging always requires a new window + payload: mapToSerializable(environment) // mandatory properties to enable debugging + }); + } + + private openExtensionDevelopmentHostWindowLegacy(args: string[]): Promise { + // we pass the "args" as query parameters of the URL let newAddress = `${document.location.origin}${document.location.pathname}?`; let gotFolder = false; @@ -62,9 +118,19 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i newAddress += `${key}=${encodeURIComponent(value)}`; }; - const f = args['folder-uri']; + const findArgument = (key: string) => { + for (let a of args) { + const k = `--${key}=`; + if (a.indexOf(k) === 0) { + return a.substr(k.length); + } + } + return undefined; + }; + + const f = findArgument('folder-uri'); if (f) { - const u = URI.parse(f[0]); + const u = URI.parse(f); gotFolder = true; addQueryParameter('folder', u.path); } @@ -73,26 +139,41 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i addQueryParameter('ew', 'true'); } - const ep = args['extensionDevelopmentPath']; + const ep = findArgument('extensionDevelopmentPath'); if (ep) { - let u = ep[0]; - addQueryParameter('edp', u); + addQueryParameter('extensionDevelopmentPath', ep); } - const di = args['debugId']; + const etp = findArgument('extensionTestsPath'); + if (etp) { + addQueryParameter('extensionTestsPath', etp); + } + + const di = findArgument('debugId'); if (di) { - addQueryParameter('di', di); + addQueryParameter('debugId', di); } - const ibe = args['inspect-brk-extensions']; + const ibe = findArgument('inspect-brk-extensions'); if (ibe) { - addQueryParameter('ibe', ibe); + addQueryParameter('inspect-brk-extensions', ibe); } window.open(newAddress); return Promise.resolve(); } + + private findArgument(key: string, args: string[]): string | undefined { + for (const a of args) { + const k = `--${key}=`; + if (a.indexOf(k) === 0) { + return a.substr(k.length); + } + } + + return undefined; + } } registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService); diff --git a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts index da8e4c728e8..5cc13614bb1 100644 --- a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts +++ b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts @@ -111,7 +111,11 @@ class BaseTreeItem { // a dynamic ID based on the parent chain; required for reparenting (see #55448) getId(): string { const parent = this.getParent(); - return parent ? `${parent.getId()}/${this._label}` : this._label; + return parent ? `${parent.getId()}/${this.getInternalId()}` : this.getInternalId(); + } + + getInternalId(): string { + return this._label; } // skips intermediate single-child nodes @@ -240,7 +244,7 @@ class RootTreeItem extends BaseTreeItem { class SessionTreeItem extends BaseTreeItem { - private static URL_REGEXP = /^(https?:\/\/[^/]+)(\/.*)$/; + private static readonly URL_REGEXP = /^(https?:\/\/[^/]+)(\/.*)$/; private _session: IDebugSession; private _initialized: boolean; @@ -254,6 +258,10 @@ class SessionTreeItem extends BaseTreeItem { this._session = session; } + getInternalId(): string { + return this._session.getId(); + } + getSession(): IDebugSession { return this._session; } @@ -419,7 +427,7 @@ export class LoadedScriptsView extends ViewletPanel { this.treeLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility }); this._register(this.treeLabels); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'LoadedScriptsView', this.treeContainer, new LoadedScriptsDelegate(), + this.tree = this.instantiationService.createInstance>(WorkbenchAsyncDataTree, 'LoadedScriptsView', this.treeContainer, new LoadedScriptsDelegate(), [new LoadedScriptsRenderer(this.treeLabels)], new LoadedScriptsDataSource(), { diff --git a/src/vs/workbench/contrib/debug/browser/media/add-dark.svg b/src/vs/workbench/contrib/debug/browser/media/add-dark.svg deleted file mode 100644 index 4d9389336b9..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/add-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/add-hc.svg b/src/vs/workbench/contrib/debug/browser/media/add-hc.svg deleted file mode 100644 index fb50c6c2849..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/add-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/add-light.svg b/src/vs/workbench/contrib/debug/browser/media/add-light.svg deleted file mode 100644 index 01a9de7d5ab..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/add-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-disabled.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-disabled.svg old mode 100755 new mode 100644 diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-unverified.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-function-unverified.svg old mode 100755 new mode 100644 diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpoint-function.svg b/src/vs/workbench/contrib/debug/browser/media/breakpoint-function.svg old mode 100755 new mode 100644 diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css b/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css index a78dd13c2d8..aa0a39e4705 100644 --- a/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css +++ b/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css @@ -18,5 +18,4 @@ .monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .inputContainer { flex: 1; - margin-top: 8px; } diff --git a/src/vs/workbench/contrib/debug/browser/media/configure-dark.svg b/src/vs/workbench/contrib/debug/browser/media/configure-dark.svg deleted file mode 100644 index ace01a5ddf5..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/configure-dark.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/configure-hc.svg b/src/vs/workbench/contrib/debug/browser/media/configure-hc.svg deleted file mode 100644 index bd59cb81f6d..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/configure-hc.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/configure-light.svg b/src/vs/workbench/contrib/debug/browser/media/configure-light.svg deleted file mode 100644 index 4194780bbaa..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/configure-light.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/console-dark.svg b/src/vs/workbench/contrib/debug/browser/media/console-dark.svg deleted file mode 100644 index 1e2d3b4ee13..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/console-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/console-hc.svg b/src/vs/workbench/contrib/debug/browser/media/console-hc.svg deleted file mode 100644 index 44b59552d8b..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/console-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/console-light.svg b/src/vs/workbench/contrib/debug/browser/media/console-light.svg deleted file mode 100644 index 429cb22b71f..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/console-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/continue-white.svg b/src/vs/workbench/contrib/debug/browser/media/continue-white.svg deleted file mode 100644 index 69d48e9984e..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/continue-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/current-and-breakpoint.svg b/src/vs/workbench/contrib/debug/browser/media/current-and-breakpoint.svg old mode 100755 new mode 100644 diff --git a/src/vs/workbench/contrib/debug/browser/media/current-arrow.svg b/src/vs/workbench/contrib/debug/browser/media/current-arrow.svg old mode 100755 new mode 100644 diff --git a/src/vs/workbench/contrib/debug/browser/media/debug-activity-bar.svg b/src/vs/workbench/contrib/debug/browser/media/debug-activity-bar.svg deleted file mode 100644 index fcb9413c8c2..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/debug-activity-bar.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 7bb29ce694b..3ab961601ac 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -4,16 +4,13 @@ *--------------------------------------------------------------------------------------------*/ /* Activity Bar */ -.monaco-workbench .activitybar .monaco-action-bar .action-label.debug { - -webkit-mask: url('debug-activity-bar.svg') no-repeat 50% 50%; -} - .monaco-editor .debug-top-stack-frame-column::before { background: url('current-arrow.svg') center center no-repeat; } .debug-breakpoint-hint { background: url('breakpoint-hint.svg') center center no-repeat; + cursor: pointer; } .debug-breakpoint-disabled, @@ -50,21 +47,26 @@ .monaco-editor .debug-breakpoint-placeholder::before, .monaco-editor .debug-top-stack-frame-column::before { content: " "; - width: 1.3em; + width: 0.9em; display: inline-block; vertical-align: text-bottom; margin-right: 2px; margin-left: 2px; } +/* Do not show call stack decoration when we plan to show breakpoint and top stack frame in one decoration */ +.monaco-editor .debug-breakpoint-placeholder ~ .debug-top-stack-frame-column::before { + width: 0em; + content: ""; + margin-right: 0px; + margin-left: 0px; +} + .monaco-editor .debug-top-stack-frame-column::before { height: 1.3em; } .monaco-editor .inline-breakpoint-widget { - width: 1.3em; - height: 1.3em; - margin-left: 0.61em; cursor: pointer; } @@ -117,10 +119,8 @@ background: url('breakpoint-unsupported.svg') center center no-repeat; } -.monaco-editor .debug-top-stack-frame.debug-breakpoint, -.monaco-editor .debug-top-stack-frame.debug-breakpoint-conditional, -.monaco-editor .debug-top-stack-frame.debug-breakpoint-log, -.monaco-editor .inline-breakpoint-widget.debug-top-stack-frame-column { +.monaco-editor .debug-top-stack-frame.debug-breakpoint-and-top-stack-frame, +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-and-top-stack-frame-at-column { background: url('current-and-breakpoint.svg') center center no-repeat; } @@ -178,7 +178,7 @@ /* White color when element is selected and list is focused. White looks better on blue selection background. */ .monaco-workbench .monaco-list:focus .monaco-list-row.selected .expression .name, .monaco-workbench .monaco-list:focus .monaco-list-row.selected .expression .value { - color: white; + color: inherit; } .monaco-workbench .monaco-list-row .expression .name { diff --git a/src/vs/workbench/contrib/debug/browser/media/debugHover.css b/src/vs/workbench/contrib/debug/browser/media/debugHover.css index de0027f8dc9..9a405382bf6 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugHover.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugHover.css @@ -10,6 +10,7 @@ animation-duration: 0.15s; animation-name: fadeIn; user-select: text; + -webkit-user-select: text; word-break: break-all; padding: 4px 5px; } @@ -22,6 +23,7 @@ padding-left: 15px; padding-right: 2px; font-size: 11px; + line-height: 18px; word-break: normal; text-overflow: ellipsis; height: 18px; @@ -37,6 +39,7 @@ .monaco-editor .debug-hover-widget .debug-hover-tree .monaco-list-row .monaco-tl-contents { user-select: text; + -webkit-user-select: text; } /* Disable tree highlight in debug hover tree. */ diff --git a/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css b/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css index 57ea84f3421..c16ed97a7b7 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css @@ -17,6 +17,11 @@ .monaco-workbench .debug-toolbar .monaco-action-bar .action-item.select-container { margin-right: 7px; + +} + +.monaco-workbench .start-debug-action-item .select-container .monaco-select-box { + padding: 0 22px 0 6px; } .monaco-workbench .debug-toolbar .drag-area { diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 2ed61ccf6b0..8ce5999aea8 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -13,40 +13,14 @@ height: 100%; } -/* Actionbar actions */ - -.monaco-workbench .debug-action.configure { - background: url('configure-light.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .debug-action.configure { - background: url('configure-dark.svg') center center no-repeat; -} - -.hc-black .monaco-workbench .debug-action.configure { - background: url('configure-hc.svg') center center no-repeat; -} - -.monaco-workbench .debug-action.toggle-repl { - background: url('console-light.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .debug-action.toggle-repl { - background: url('console-dark.svg') center center no-repeat; -} - -.hc-black .monaco-workbench .debug-action.toggle-repl { - background: url('console-hc.svg') center center no-repeat; -} - -.monaco-workbench .debug-action.notification:before { +.monaco-workbench .debug-action.notification:after { content: ''; width: 6px; height: 6px; background-color: #CC6633; position: absolute; - top: 11px; - right: 5px; + top: 10px; + right: 6px; border-radius: 10px; border: 1px solid white; } @@ -65,24 +39,11 @@ border-radius: 4px; } -.monaco-workbench .part > .title > .title-actions .start-debug-action-item .icon { - height: 20px; - width: 20px; - background: url('start-light.svg') no-repeat; - background-size: 16px 16px; - background-position: center center; +.monaco-workbench .part > .title > .title-actions .start-debug-action-item .codicon { flex-shrink: 0; transition: transform 50ms ease; } -.vs-dark .monaco-workbench .part > .title > .title-actions .start-debug-action-item .icon { - background-image: url('start-dark.svg'); -} - -.hc-black .monaco-workbench .part > .title > .title-actions .start-debug-action-item .icon { - background-image: url('start-hc.svg'); -} - .monaco-workbench .monaco-action-bar .start-debug-action-item .configuration .monaco-select-box { border: none; margin-top: 0px; @@ -95,7 +56,7 @@ cursor: initial; } -.monaco-workbench .part > .title > .title-actions .start-debug-action-item .icon.active { +.monaco-workbench .part > .title > .title-actions .start-debug-action-item .codicon.active { transform: scale(1.272019649, 1.272019649); } @@ -224,6 +185,7 @@ flex: 1; flex-shrink: 0; min-width: fit-content; + min-width: -moz-fit-content; } .debug-viewlet .debug-call-stack .stack-frame.subtle { @@ -278,100 +240,8 @@ overflow: hidden; } -.debug-viewlet .debug-call-stack .debug-action.stop { - background: url('stop-light.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.stop { - background: url('stop-white.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-call-stack .debug-action.stop { - background: url('stop-dark.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .debug-action.disconnect { - background: url('disconnect-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-call-stack .debug-action.disconnect { - background: url('disconnect-dark.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.disconnect { - background: url('disconnect-white.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .debug-action.restart { - background: url('restart-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-call-stack .debug-action.restart { - background: url('restart-dark.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.restart { - background: url('restart-white.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .debug-action.step-over { - background: url('step-over-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-over { - background: url('step-over-dark.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-over { - background: url('step-over-white.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .debug-action.step-into { - background: url('step-into-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-into { - background: url('step-into-dark.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-into { - background: url('step-into-white.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .debug-action.step-out { - background: url('step-out-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-out { - background: url('step-out-dark.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-out { - background: url('step-out-white.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .debug-action.pause { - background: url('pause-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-call-stack .debug-action.pause { - background: url('pause-dark.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.pause { - background: url('pause-white.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .debug-action.continue { - background: url('continue-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-call-stack .debug-action.continue { - background: url('continue-dark.svg') center center no-repeat; -} - -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.continue { - background: url('continue-white.svg') center center no-repeat; +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected.focused .codicon { + color: inherit !important; } /* Variables & Expression view */ @@ -435,20 +305,6 @@ flex : 1; } -.debug-viewlet .debug-action.add-watch-expression, -.debug-viewlet .debug-action.add-function-breakpoint { - background: url('add-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-action.add-watch-expression, -.vs-dark .debug-viewlet .debug-action.add-function-breakpoint { - background: url('add-dark.svg') center center no-repeat; -} - -.hc-black .debug-viewlet .debug-action.add-watch-expression { - background: url('add-hc.svg') center center no-repeat; -} - .vs-dark .debug-viewlet .monaco-list-row .expression .value.changed { animation-name: debugViewletValueChanged; } @@ -498,30 +354,6 @@ text-overflow: ellipsis } -.debug-viewlet .debug-action.remove-all { - background: url('close-all-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-action.remove-all { - background: url('close-all-dark.svg') center center no-repeat; -} - -.hc-black .debug-viewlet .debug-action.remove-all { - background: url('close-all-hc.svg') center center no-repeat; -} - -.debug-viewlet .debug-action.breakpoints-activate { - background: url('toggle-breakpoints-light.svg') center center no-repeat; -} - -.vs-dark .debug-viewlet .debug-action.breakpoints-activate { - background: url('toggle-breakpoints-dark.svg') center center no-repeat; -} - -.hc-black .debug-viewlet .debug-action.breakpoints-activate { - background: url('toggle-breakpoints-hc.svg') center center no-repeat; -} - /* No workspace view */ .debug-viewlet > .noworkspace-view { diff --git a/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg b/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg deleted file mode 100644 index 42e2e75e091..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/disconnect-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css b/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css index 14e674738d5..df149d3b430 100644 --- a/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css +++ b/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css @@ -11,6 +11,7 @@ padding: 6px 10px; white-space: pre-wrap; user-select: text; + -webkit-user-select: text; } .monaco-editor .zone-widget .zone-widget-container.exception-widget .title { diff --git a/src/vs/workbench/contrib/debug/browser/media/pause-white.svg b/src/vs/workbench/contrib/debug/browser/media/pause-white.svg deleted file mode 100644 index bd634a35a5a..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/pause-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index e7befa20952..9b6b7dccecc 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -13,6 +13,7 @@ .repl .repl-tree .monaco-tl-contents { user-select: text; + -webkit-user-select: text; } .repl .repl-tree.word-wrap .monaco-tl-contents { diff --git a/src/vs/workbench/contrib/debug/browser/media/restart-white.svg b/src/vs/workbench/contrib/debug/browser/media/restart-white.svg deleted file mode 100644 index cf498da0c7f..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/restart-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/start-dark.svg b/src/vs/workbench/contrib/debug/browser/media/start-dark.svg deleted file mode 100644 index 5d91244bff1..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/start-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/start-hc.svg b/src/vs/workbench/contrib/debug/browser/media/start-hc.svg deleted file mode 100644 index 5d91244bff1..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/start-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/start-light.svg b/src/vs/workbench/contrib/debug/browser/media/start-light.svg deleted file mode 100644 index b6effa36f71..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/start-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg deleted file mode 100644 index 77ef1cbf34b..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-into-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg deleted file mode 100644 index 906cd8d33ca..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-out-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg b/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg deleted file mode 100644 index bac3022c88f..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/step-over-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/stop-white.svg b/src/vs/workbench/contrib/debug/browser/media/stop-white.svg deleted file mode 100644 index f33eb6181db..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/stop-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-dark.svg b/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-dark.svg deleted file mode 100644 index 2e8b9f34e5e..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-hc.svg b/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-hc.svg deleted file mode 100644 index ab1b9e54f98..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-light.svg b/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-light.svg deleted file mode 100644 index 479dc5f81e5..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/toggle-breakpoints-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 16da4c39488..bddadea7078 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -12,7 +12,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { formatPII, isUri } from 'vs/workbench/contrib/debug/common/debugUtils'; import { IDebugAdapter, IConfig, AdapterEndEvent, IDebugger } from 'vs/workbench/contrib/debug/common/debug'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { URI } from 'vs/base/common/uri'; import { IProcessEnvironment } from 'vs/base/common/platform'; @@ -228,25 +227,23 @@ export class RawDebugSession implements IDisposable { /** * Starts the underlying debug adapter and tracks the session time for telemetry. */ - start(): Promise { + async start(): Promise { if (!this.debugAdapter) { return Promise.reject(new Error('no debug adapter')); } - return this.debugAdapter.startSession().then(() => { - this.startTime = new Date().getTime(); - }, err => { - return Promise.reject(err); - }); + + await this.debugAdapter.startSession(); + this.startTime = new Date().getTime(); } /** * Send client capabilities to the debug adapter and receive DA capabilities in return. */ - initialize(args: DebugProtocol.InitializeRequestArguments): Promise { - return this.send('initialize', args).then((response: DebugProtocol.InitializeResponse) => { - this.mergeCapabilities(response.body); - return response; - }); + async initialize(args: DebugProtocol.InitializeRequestArguments): Promise { + const response = await this.send('initialize', args); + this.mergeCapabilities(response.body); + + return response; } /** @@ -258,11 +255,11 @@ export class RawDebugSession implements IDisposable { //---- DAP requests - launchOrAttach(config: IConfig): Promise { - return this.send(config.request, config).then(response => { - this.mergeCapabilities(response.body); - return response; - }); + async launchOrAttach(config: IConfig): Promise { + const response = await this.send(config.request, config); + this.mergeCapabilities(response.body); + + return response; } /** @@ -286,35 +283,32 @@ export class RawDebugSession implements IDisposable { return Promise.reject(new Error('restart not supported')); } - next(args: DebugProtocol.NextArguments): Promise { - return this.send('next', args).then(response => { - this.fireSimulatedContinuedEvent(args.threadId); - return response; - }); + async next(args: DebugProtocol.NextArguments): Promise { + const response = await this.send('next', args); + this.fireSimulatedContinuedEvent(args.threadId); + return response; } - stepIn(args: DebugProtocol.StepInArguments): Promise { - return this.send('stepIn', args).then(response => { - this.fireSimulatedContinuedEvent(args.threadId); - return response; - }); + async stepIn(args: DebugProtocol.StepInArguments): Promise { + const response = await this.send('stepIn', args); + this.fireSimulatedContinuedEvent(args.threadId); + return response; } - stepOut(args: DebugProtocol.StepOutArguments): Promise { - return this.send('stepOut', args).then(response => { - this.fireSimulatedContinuedEvent(args.threadId); - return response; - }); + async stepOut(args: DebugProtocol.StepOutArguments): Promise { + const response = await this.send('stepOut', args); + this.fireSimulatedContinuedEvent(args.threadId); + return response; } - continue(args: DebugProtocol.ContinueArguments): Promise { - return this.send('continue', args).then(response => { - if (response && response.body && response.body.allThreadsContinued !== undefined) { - this.allThreadsContinued = response.body.allThreadsContinued; - } - this.fireSimulatedContinuedEvent(args.threadId, this.allThreadsContinued); - return response; - }); + async continue(args: DebugProtocol.ContinueArguments): Promise { + const response = await this.send('continue', args); + if (response && response.body && response.body.allThreadsContinued !== undefined) { + this.allThreadsContinued = response.body.allThreadsContinued; + } + this.fireSimulatedContinuedEvent(args.threadId, this.allThreadsContinued); + + return response; } pause(args: DebugProtocol.PauseArguments): Promise { @@ -335,12 +329,11 @@ export class RawDebugSession implements IDisposable { return Promise.reject(new Error('setVariable not supported')); } - restartFrame(args: DebugProtocol.RestartFrameArguments, threadId: number): Promise { + async restartFrame(args: DebugProtocol.RestartFrameArguments, threadId: number): Promise { if (this.capabilities.supportsRestartFrame) { - return this.send('restartFrame', args).then(response => { - this.fireSimulatedContinuedEvent(threadId); - return response; - }); + const response = await this.send('restartFrame', args); + this.fireSimulatedContinuedEvent(threadId); + return response; } return Promise.reject(new Error('restartFrame not supported')); } @@ -433,26 +426,24 @@ export class RawDebugSession implements IDisposable { return this.send('evaluate', args); } - stepBack(args: DebugProtocol.StepBackArguments): Promise { + async stepBack(args: DebugProtocol.StepBackArguments): Promise { if (this.capabilities.supportsStepBack) { - return this.send('stepBack', args).then(response => { - if (response.body === undefined) { // TODO@AW why this check? - this.fireSimulatedContinuedEvent(args.threadId); - } - return response; - }); + const response = await this.send('stepBack', args); + if (response.body === undefined) { // TODO@AW why this check? + this.fireSimulatedContinuedEvent(args.threadId); + } + return response; } return Promise.reject(new Error('stepBack not supported')); } - reverseContinue(args: DebugProtocol.ReverseContinueArguments): Promise { + async reverseContinue(args: DebugProtocol.ReverseContinueArguments): Promise { if (this.capabilities.supportsStepBack) { - return this.send('reverseContinue', args).then(response => { - if (response.body === undefined) { // TODO@AW why this check? - this.fireSimulatedContinuedEvent(args.threadId); - } - return response; - }); + const response = await this.send('reverseContinue', args); + if (response.body === undefined) { // TODO@AW why this check? + this.fireSimulatedContinuedEvent(args.threadId); + } + return response; } return Promise.reject(new Error('reverseContinue not supported')); } @@ -464,13 +455,13 @@ export class RawDebugSession implements IDisposable { return Promise.reject(new Error('gotoTargets is not supported')); } - goto(args: DebugProtocol.GotoArguments): Promise { + async goto(args: DebugProtocol.GotoArguments): Promise { if (this.capabilities.supportsGotoTargetsRequest) { - return this.send('goto', args).then(res => { - this.fireSimulatedContinuedEvent(args.threadId); - return res; - }); + const response = await this.send('goto', args); + this.fireSimulatedContinuedEvent(args.threadId); + return response; } + return Promise.reject(new Error('goto is not supported')); } @@ -484,36 +475,32 @@ export class RawDebugSession implements IDisposable { //---- private - private shutdown(error?: Error, restart = false): Promise { + private async shutdown(error?: Error, restart = false): Promise { if (!this.inShutdown) { this.inShutdown = true; if (this.debugAdapter) { - return this.send('disconnect', { restart }, undefined, 500).then(() => { + try { + await this.send('disconnect', { restart }, undefined, 500); + } finally { this.stopAdapter(error); - }, () => { - // ignore error - this.stopAdapter(error); - }); + } + } else { + return this.stopAdapter(error); } - return this.stopAdapter(error); } - return Promise.resolve(undefined); } - private stopAdapter(error?: Error): Promise { - if (this.debugAdapter) { - const da = this.debugAdapter; - this.debugAdapter = null; - return da.stopSession().then(_ => { + private async stopAdapter(error?: Error): Promise { + try { + if (this.debugAdapter) { + const da = this.debugAdapter; + this.debugAdapter = null; + await da.stopSession(); this.debugAdapterStopped = true; - this.fireAdapterExitEvent(error); - }, err => { - this.fireAdapterExitEvent(error); - }); - } else { + } + } finally { this.fireAdapterExitEvent(error); } - return Promise.resolve(undefined); } private fireAdapterExitEvent(error?: Error): void { @@ -557,18 +544,19 @@ export class RawDebugSession implements IDisposable { }); break; case 'runInTerminal': - dbgr.runInTerminal(request.arguments as DebugProtocol.RunInTerminalRequestArguments).then(shellProcessId => { + try { + const shellProcessId = await dbgr.runInTerminal(request.arguments as DebugProtocol.RunInTerminalRequestArguments); const resp = response as DebugProtocol.RunInTerminalResponse; resp.body = {}; if (typeof shellProcessId === 'number') { resp.body.shellProcessId = shellProcessId; } safeSendResponse(resp); - }, err => { + } catch (err) { response.success = false; response.message = err.message; safeSendResponse(response); - }); + } break; default: response.success = false; @@ -580,47 +568,21 @@ export class RawDebugSession implements IDisposable { private launchVsCode(vscodeArgs: ILaunchVSCodeArguments): Promise { - let args: ParsedArgs = { - _: [] - }; + const args: string[] = []; for (let arg of vscodeArgs.args) { - if (arg.prefix) { - const a2 = (arg.prefix || '') + (arg.path || ''); - const match = /^--(.+)=(.+)$/.exec(a2); - if (match && match.length === 3) { - const key = match[1]; - let value = match[2]; + const a2 = (arg.prefix || '') + (arg.path || ''); + const match = /^--(.+)=(.+)$/.exec(a2); + if (match && match.length === 3) { + const key = match[1]; + let value = match[2]; - if ((key === 'file-uri' || key === 'folder-uri') && !isUri(arg.path)) { - value = URI.file(value).toString(); - - const v = args[key]; - if (v) { - v.push(value); - } else { - args[key] = [value]; - } - } else if (key === 'extensionDevelopmentPath' || key === 'enable-proposed-api') { - const v = args[key]; - if (v) { - v.push(value); - } else { - args[key] = [value]; - } - } else { - (args)[key] = value; - } - - } else { - const match = /^--(.+)$/.exec(a2); - if (match && match.length === 2) { - const key = match[1]; - (args)[key] = true; - } else { - args._.push(a2); - } + if ((key === 'file-uri' || key === 'folder-uri') && !isUri(arg.path)) { + value = URI.file(value).toString(); } + args.push(`--${key}=${value}`); + } else { + args.push(a2); } } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 3935ae45643..37ed56928be 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -46,7 +46,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { Variable } from 'vs/workbench/contrib/debug/common/debugModel'; import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel'; -import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { CachedListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { renderExpressionValue, AbstractExpressionsRenderer, IExpressionTemplateData, renderVariable, IInputBoxOptions } from 'vs/workbench/contrib/debug/browser/baseDebugView'; @@ -74,8 +74,8 @@ interface IPrivateReplService { _serviceBrand: undefined; acceptReplInput(): void; getVisibleContent(): string; - selectSession(session?: IDebugSession): void; - clearRepl(): void; + selectSession(session?: IDebugSession): Promise; + clearRepl(): Promise; focusRepl(): void; } @@ -129,7 +129,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } private registerListeners(): void { - this._register(this.debugService.getViewModel().onDidFocusSession(session => { + this._register(this.debugService.getViewModel().onDidFocusSession(async session => { if (session) { sessionsToIgnore.delete(session); if (this.completionItemProvider) { @@ -159,13 +159,13 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } } - this.selectSession(); + await this.selectSession(); })); - this._register(this.debugService.onWillNewSession(newSession => { + this._register(this.debugService.onWillNewSession(async newSession => { // Need to listen to output events for sessions which are not yet fully initialised const input = this.tree.getInput(); if (!input || input.state === State.Inactive) { - this.selectSession(newSession); + await this.selectSession(newSession); } this.updateTitleArea(); })); @@ -252,7 +252,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } } - selectSession(session?: IDebugSession): void { + async selectSession(session?: IDebugSession): Promise { const treeInput = this.tree.getInput(); if (!session) { const focusedSession = this.debugService.getViewModel().focusedSession; @@ -272,7 +272,8 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati }); if (this.tree && treeInput !== session) { - this.tree.setInput(session).then(() => revealLastElement(this.tree)).then(undefined, errors.onUnexpectedError); + await this.tree.setInput(session); + revealLastElement(this.tree); } } @@ -280,14 +281,14 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.updateInputDecoration(); } - clearRepl(): void { + async clearRepl(): Promise { const session = this.tree.getInput(); if (session) { session.removeReplExpressions(); if (session.state === State.Inactive) { // Ignore inactive sessions which got cleared - so they are not shown any more sessionsToIgnore.add(session); - this.selectSession(); + await this.selectSession(); this.updateTitleArea(); } } @@ -405,7 +406,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati const wordWrap = this.configurationService.getValue('debug').console.wordWrap; dom.toggleClass(treeContainer, 'word-wrap', wordWrap); const linkDetector = this.instantiationService.createInstance(LinkDetector); - this.tree = this.instantiationService.createInstance( + this.tree = this.instantiationService.createInstance>( WorkbenchAsyncDataTree, 'DebugRepl', treeContainer, @@ -646,7 +647,7 @@ class ReplEvaluationResultsRenderer implements ITreeRenderer { +class ReplDelegate extends CachedListVirtualDelegate { - constructor(private configurationService: IConfigurationService) { } + constructor(private configurationService: IConfigurationService) { + super(); + } getHeight(element: IReplElement): number { - const countNumberOfLines = (str: string) => Math.max(1, (str && str.match(/\r\n|\n/g) || []).length); - - // Give approximate heights. Repl has dynamic height so the tree will measure the actual height on its own. const config = this.configurationService.getValue('debug'); - const fontSize = config.console.fontSize; - const rowHeight = Math.ceil(1.4 * fontSize); - const wordWrap = config.console.wordWrap; - if (!wordWrap) { - return rowHeight; + + if (!config.console.wordWrap) { + return Math.ceil(1.4 * config.console.fontSize); } - // In order to keep scroll position we need to give a good approximation to the tree - // For every 150 characters increase the number of lines needed - if (element instanceof ReplEvaluationResult) { + return super.getHeight(element); + } + + protected estimateHeight(element: IReplElement): number { + const config = this.configurationService.getValue('debug'); + const rowHeight = Math.ceil(1.4 * config.console.fontSize); + const countNumberOfLines = (str: string) => Math.max(1, (str && str.match(/\r\n|\n/g) || []).length); + const hasValue = (e: any): e is { value: string } => typeof e.value === 'string'; + + // Calculate a rough overestimation for the height + // For every 30 characters increase the number of lines needed + if (hasValue(element)) { let value = element.value; - - if (element.hasChildren) { - return rowHeight; - } - - let valueRows = value ? (countNumberOfLines(value) + Math.floor(value.length / 150)) : 0; - return rowHeight * valueRows; - } - - if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput) { - let value = element.value; - let valueRows = countNumberOfLines(value) + Math.floor(value.length / 150); + let valueRows = countNumberOfLines(value) + Math.floor(value.length / 30); return valueRows * rowHeight; } @@ -851,7 +847,7 @@ class ReplDelegate implements IListVirtualDelegate { return ReplRawObjectsRenderer.ID; } - hasDynamicHeight?(element: IReplElement): boolean { + hasDynamicHeight(element: IReplElement): boolean { // Empty elements should not have dynamic height since they will be invisible return element.toString().length > 0; } @@ -919,7 +915,7 @@ class AcceptReplInputAction extends EditorAction { } run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise { - SuggestController.get(editor).acceptSelectedSuggestion(); + SuggestController.get(editor).acceptSelectedSuggestion(false, true); accessor.get(IPrivateReplService).acceptReplInput(); } } @@ -941,7 +937,7 @@ class FilterReplAction extends EditorAction { } run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise { - SuggestController.get(editor).acceptSelectedSuggestion(); + SuggestController.get(editor).acceptSelectedSuggestion(false, true); accessor.get(IPrivateReplService).focusRepl(); } } @@ -984,7 +980,7 @@ class SelectReplActionViewItem extends FocusSessionActionViewItem { class SelectReplAction extends Action { static readonly ID = 'workbench.action.debug.selectRepl'; - static LABEL = nls.localize('selectRepl', "Select Debug Console"); + static readonly LABEL = nls.localize('selectRepl', "Select Debug Console"); constructor(id: string, label: string, @IDebugService private readonly debugService: IDebugService, @@ -993,12 +989,12 @@ class SelectReplAction extends Action { super(id, label); } - run(session: IDebugSession): Promise { + async run(session: IDebugSession): Promise { // If session is already the focused session we need to manualy update the tree since view model will not send a focused change event if (session && session.state !== State.Inactive && session !== this.debugService.getViewModel().focusedSession) { - this.debugService.focusStackFrame(undefined, undefined, session, true); + await this.debugService.focusStackFrame(undefined, undefined, session, true); } else { - this.replService.selectSession(session); + await this.replService.selectSession(session); } return Promise.resolve(undefined); @@ -1007,7 +1003,7 @@ class SelectReplAction extends Action { export class ClearReplAction extends Action { static readonly ID = 'workbench.debug.panel.action.clearReplAction'; - static LABEL = nls.localize('clearRepl', "Clear Console"); + static readonly LABEL = nls.localize('clearRepl', "Clear Console"); constructor(id: string, label: string, @IPanelService private readonly panelService: IPanelService @@ -1015,11 +1011,9 @@ export class ClearReplAction extends Action { super(id, label, 'debug-action codicon-clear-all'); } - run(): Promise { + async run(): Promise { const repl = this.panelService.openPanel(REPL_ID); - repl.clearRepl(); + await repl.clearRepl(); aria.status(nls.localize('debugConsoleCleared', "Debug console was cleared")); - - return Promise.resolve(undefined); } } diff --git a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts index 6078564168b..31c26f24f25 100644 --- a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts @@ -12,6 +12,7 @@ import { IDebugService, State } from 'vs/workbench/contrib/debug/common/debug'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_BACKGROUND, Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_BORDER } from 'vs/workbench/common/theme'; import { addClass, removeClass, createStyleSheet } from 'vs/base/browser/dom'; +import { assertIsDefined } from 'vs/base/common/types'; // colors for theming @@ -56,7 +57,7 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri protected updateStyles(): void { super.updateStyles(); - const container = this.layoutService.getContainer(Parts.STATUSBAR_PART); + const container = assertIsDefined(this.layoutService.getContainer(Parts.STATUSBAR_PART)); if (isStatusbarInDebugMode(this.debugService)) { addClass(container, 'debugging'); } else { @@ -65,7 +66,7 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri // Container Colors const backgroundColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_DEBUGGING_BACKGROUND, STATUS_BAR_BACKGROUND)); - container.style.backgroundColor = backgroundColor; + container.style.backgroundColor = backgroundColor || ''; container.style.color = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_DEBUGGING_FOREGROUND, STATUS_BAR_FOREGROUND)); // Border Color @@ -108,7 +109,7 @@ export function isStatusbarInDebugMode(debugService: IDebugService): boolean { } const session = debugService.getViewModel().focusedSession; - const isRunningWithoutDebug = session && session.configuration && session.configuration.noDebug; + const isRunningWithoutDebug = session?.configuration?.noDebug; if (isRunningWithoutDebug) { return false; } diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts index 56483de1cb2..e84983e6c7b 100644 --- a/src/vs/workbench/contrib/debug/browser/variablesView.ts +++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts @@ -25,7 +25,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { Emitter } from 'vs/base/common/event'; import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; import { IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree'; -import { onUnexpectedError } from 'vs/base/common/errors'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; @@ -57,28 +56,27 @@ export class VariablesView extends ViewletPanel { super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('variablesSection', "Variables Section") }, keybindingService, contextMenuService, configurationService, contextKeyService); // Use scheduler to prevent unnecessary flashing - this.onFocusStackFrameScheduler = new RunOnceScheduler(() => { + this.onFocusStackFrameScheduler = new RunOnceScheduler(async () => { const stackFrame = this.debugService.getViewModel().focusedStackFrame; this.needsRefresh = false; if (stackFrame && this.savedViewState) { - this.tree.setInput(this.debugService.getViewModel(), this.savedViewState).then(null, onUnexpectedError); + await this.tree.setInput(this.debugService.getViewModel(), this.savedViewState); this.savedViewState = undefined; } else { if (!stackFrame) { // We have no stackFrame, save tree state before it is cleared this.savedViewState = this.tree.getViewState(); } - this.tree.updateChildren().then(() => { - if (stackFrame) { - stackFrame.getScopes().then(scopes => { - // Expand the first scope if it is not expensive and if there is no expansion state (all are collapsed) - if (scopes.every(s => this.tree.getNode(s).collapsed) && scopes.length > 0 && !scopes[0].expensive) { - this.tree.expand(scopes[0]).then(undefined, onUnexpectedError); - } - }); + await this.tree.updateChildren(); + if (stackFrame) { + const scopes = await stackFrame.getScopes(); + // Expand the first scope if it is not expensive and if there is no expansion state (all are collapsed) + if (scopes.every(s => this.tree.getNode(s).collapsed) && scopes.length > 0 && !scopes[0].expensive) { + this.tree.expand(scopes[0]); } - }, onUnexpectedError); + } + } }, 400); } @@ -87,7 +85,7 @@ export class VariablesView extends ViewletPanel { dom.addClass(container, 'debug-variables'); const treeContainer = renderViewTree(container); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'VariablesView', treeContainer, new VariablesDelegate(), + this.tree = this.instantiationService.createInstance>(WorkbenchAsyncDataTree, 'VariablesView', treeContainer, new VariablesDelegate(), [this.instantiationService.createInstance(VariablesRenderer), new ScopesRenderer()], new VariablesDataSource(), { ariaLabel: nls.localize('variablesAriaTreeLabel', "Debug Variables"), @@ -96,12 +94,14 @@ export class VariablesView extends ViewletPanel { keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression | IScope) => e } }); - this.tree.setInput(this.debugService.getViewModel()).then(null, onUnexpectedError); + this.tree.setInput(this.debugService.getViewModel()); CONTEXT_VARIABLES_FOCUSED.bindTo(this.tree.contextKeyService); - const collapseAction = new CollapseAction(this.tree, true, 'explorer-action collapse-explorer'); - this.toolbar.setActions([collapseAction])(); + if (this.toolbar) { + const collapseAction = new CollapseAction(this.tree, true, 'explorer-action codicon-collapse-all'); + this.toolbar.setActions([collapseAction])(); + } this.tree.updateChildren(); this._register(this.debugService.getViewModel().onDidFocusStackFrame(sf => { diff --git a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts index b48786ed88b..e416cc5565a 100644 --- a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts +++ b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts @@ -24,7 +24,6 @@ import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; import { IAsyncDataSource, ITreeMouseEvent, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeDragOverReaction } from 'vs/base/browser/ui/tree/tree'; import { IDragAndDropData } from 'vs/base/browser/dnd'; -import { onUnexpectedError } from 'vs/base/common/errors'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { FuzzyScore } from 'vs/base/common/filters'; import { IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; @@ -62,7 +61,7 @@ export class WatchExpressionsView extends ViewletPanel { const treeContainer = renderViewTree(container); const expressionsRenderer = this.instantiationService.createInstance(WatchExpressionsRenderer); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'WatchExpressions', treeContainer, new WatchExpressionsDelegate(), [expressionsRenderer, this.instantiationService.createInstance(VariablesRenderer)], + this.tree = this.instantiationService.createInstance>(WorkbenchAsyncDataTree, 'WatchExpressions', treeContainer, new WatchExpressionsDelegate(), [expressionsRenderer, this.instantiationService.createInstance(VariablesRenderer)], new WatchExpressionsDataSource(), { ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'watchAriaTreeLabel' }, "Debug Watch Expressions"), accessibilityProvider: new WatchExpressionsAccessibilityProvider(), @@ -71,13 +70,15 @@ export class WatchExpressionsView extends ViewletPanel { dnd: new WatchExpressionsDragAndDrop(this.debugService), }); - this.tree.setInput(this.debugService).then(undefined, onUnexpectedError); + this.tree.setInput(this.debugService); CONTEXT_WATCH_EXPRESSIONS_FOCUSED.bindTo(this.tree.contextKeyService); - const addWatchExpressionAction = new AddWatchExpressionAction(AddWatchExpressionAction.ID, AddWatchExpressionAction.LABEL, this.debugService, this.keybindingService); - const collapseAction = new CollapseAction(this.tree, true, 'explorer-action collapse-explorer'); - const removeAllWatchExpressionsAction = new RemoveAllWatchExpressionsAction(RemoveAllWatchExpressionsAction.ID, RemoveAllWatchExpressionsAction.LABEL, this.debugService, this.keybindingService); - this.toolbar.setActions([addWatchExpressionAction, collapseAction, removeAllWatchExpressionsAction])(); + if (this.toolbar) { + const addWatchExpressionAction = new AddWatchExpressionAction(AddWatchExpressionAction.ID, AddWatchExpressionAction.LABEL, this.debugService, this.keybindingService); + const collapseAction = new CollapseAction(this.tree, true, 'explorer-action codicon-collapse-all'); + const removeAllWatchExpressionsAction = new RemoveAllWatchExpressionsAction(RemoveAllWatchExpressionsAction.ID, RemoveAllWatchExpressionsAction.LABEL, this.debugService, this.keybindingService); + this.toolbar.setActions([addWatchExpressionAction, collapseAction, removeAllWatchExpressionsAction])(); + } this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); this._register(this.tree.onMouseDblClick(e => this.onMouseDblClick(e))); @@ -152,7 +153,7 @@ export class WatchExpressionsView extends ViewletPanel { return Promise.resolve(); })); if (!expression.hasChildren) { - actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, expression.value, 'watch', this.debugService)); + actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, expression.value, 'watch')); } actions.push(new Separator()); @@ -166,7 +167,7 @@ export class WatchExpressionsView extends ViewletPanel { if (element instanceof Variable) { const variable = element as Variable; if (!variable.hasChildren) { - actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, variable, 'watch', this.debugService)); + actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, variable, 'watch')); } actions.push(new Separator()); } diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 81e4d032dba..1ef64079bba 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -160,7 +160,7 @@ export interface IDebugSession extends ITreeElement { readonly configuration: IConfig; readonly unresolvedConfiguration: IConfig | undefined; readonly state: State; - readonly root: IWorkspaceFolder; + readonly root: IWorkspaceFolder | undefined; readonly parentSession: IDebugSession | undefined; readonly subId: string | undefined; @@ -467,6 +467,7 @@ export interface IDebugConfiguration { }; focusWindowOnBreak: boolean; onTaskErrors: 'debugAnyway' | 'showErrors' | 'prompt'; + showBreakpointsInOverviewRuler: boolean; } export interface IGlobalConfig { @@ -504,6 +505,7 @@ export interface IConfig extends IEnvConfig { export interface ICompound { name: string; + preLaunchTask?: string | TaskIdentifier; configurations: (string | { name: string, folder: string })[]; } @@ -732,7 +734,7 @@ export interface IDebugService { /** * Sets the focused stack frame and evaluates all expressions against the newly focused stack frame, */ - focusStackFrame(focusedStackFrame: IStackFrame | undefined, thread?: IThread, session?: IDebugSession, explicit?: boolean): void; + focusStackFrame(focusedStackFrame: IStackFrame | undefined, thread?: IThread, session?: IDebugSession, explicit?: boolean): Promise; /** * Adds new breakpoints to the model for the file specified with the uri. Notifies debug adapter of breakpoint changes. diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index ec8d05b8078..2dc46ce56f9 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -27,7 +27,7 @@ import { mixin } from 'vs/base/common/objects'; export class ExpressionContainer implements IExpressionContainer { - public static allValues = new Map(); + public static readonly allValues = new Map(); // Use chunks to support variable paging #9537 private static readonly BASE_CHUNK_SIZE = 100; @@ -65,7 +65,7 @@ export class ExpressionContainer implements IExpressionContainer { private async doGetChildren(): Promise { if (!this.hasChildren) { - return Promise.resolve([]); + return []; } if (!this.getChildrenInChunks) { @@ -114,13 +114,16 @@ export class ExpressionContainer implements IExpressionContainer { return !!this.reference && this.reference > 0; } - private fetchVariables(start: number | undefined, count: number | undefined, filter: 'indexed' | 'named' | undefined): Promise { - return this.session!.variables(this.reference || 0, this.threadId, filter, start, count).then(response => { + private async fetchVariables(start: number | undefined, count: number | undefined, filter: 'indexed' | 'named' | undefined): Promise { + try { + const response = await this.session!.variables(this.reference || 0, this.threadId, filter, start, count); return response && response.body && response.body.variables ? distinct(response.body.variables.filter(v => !!v && isString(v.name)), (v: DebugProtocol.Variable) => v.name).map((v: DebugProtocol.Variable) => new Variable(this.session, this.threadId, this, v.variablesReference, v.name, v.evaluateName, v.value, v.namedVariables, v.indexedVariables, v.presentationHint, v.type)) : []; - }, (e: Error) => [new Variable(this.session, this.threadId, this, 0, e.message, e.message, '', 0, 0, { kind: 'virtual' }, undefined, false)]); + } catch (e) { + return [new Variable(this.session, this.threadId, this, 0, e.message, e.message, '', 0, 0, { kind: 'virtual' }, undefined, false)]; + } } // The adapter explicitly sents the children count of an expression only if there are lots of children which should be chunked. @@ -172,7 +175,7 @@ export class ExpressionContainer implements IExpressionContainer { } export class Expression extends ExpressionContainer implements IExpression { - static DEFAULT_VALUE = nls.localize('notAvailable', "not available"); + static readonly DEFAULT_VALUE = nls.localize('notAvailable', "not available"); public available: boolean; @@ -221,7 +224,7 @@ export class Variable extends ExpressionContainer implements IExpression { async setVariable(value: string): Promise { if (!this.session) { - return Promise.resolve(undefined); + return; } try { @@ -313,18 +316,17 @@ export class StackFrame implements IStackFrame { return (from > 0 ? '...' : '') + this.source.uri.path.substr(from); } - getMostSpecificScopes(range: IRange): Promise { - return this.getScopes().then(scopes => { - scopes = scopes.filter(s => !s.expensive); - const haveRangeInfo = scopes.some(s => !!s.range); - if (!haveRangeInfo) { - return scopes; - } + async getMostSpecificScopes(range: IRange): Promise { + const scopes = await this.getScopes(); + const nonExpensiveScopes = scopes.filter(s => !s.expensive); + const haveRangeInfo = nonExpensiveScopes.some(s => !!s.range); + if (!haveRangeInfo) { + return nonExpensiveScopes; + } - const scopesContainingRange = scopes.filter(scope => scope.range && Range.containsRange(scope.range, range)) - .sort((first, second) => (first.range!.endLineNumber - first.range!.startLineNumber) - (second.range!.endLineNumber - second.range!.startLineNumber)); - return scopesContainingRange.length ? scopesContainingRange : scopes; - }); + const scopesContainingRange = nonExpensiveScopes.filter(scope => scope.range && Range.containsRange(scope.range, range)) + .sort((first, second) => (first.range!.endLineNumber - first.range!.startLineNumber) - (second.range!.endLineNumber - second.range!.startLineNumber)); + return scopesContainingRange.length ? scopesContainingRange : nonExpensiveScopes; } restart(): Promise { @@ -342,9 +344,11 @@ export class StackFrame implements IStackFrame { return sourceToString === UNKNOWN_SOURCE_LABEL ? this.name : `${this.name} (${sourceToString})`; } - openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise { - return !this.source.available ? Promise.resolve(undefined) : - this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide, pinned); + async openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise { + if (this.source.available) { + return this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide, pinned); + } + return undefined; } equals(other: IStackFrame): boolean { @@ -399,23 +403,21 @@ export class Thread implements IThread { * Only fetches the first stack frame for performance reasons. Calling this method consecutive times * gets the remainder of the call stack. */ - fetchCallStack(levels = 20): Promise { - if (!this.stopped) { - return Promise.resolve(undefined); - } - - const start = this.callStack.length; - return this.getCallStackImpl(start, levels).then(callStack => { + async fetchCallStack(levels = 20): Promise { + if (this.stopped) { + const start = this.callStack.length; + const callStack = await this.getCallStackImpl(start, levels); if (start < this.callStack.length) { // Set the stack frames for exact position we requested. To make sure no concurrent requests create duplicate stack frames #30660 this.callStack.splice(start, this.callStack.length - start); } this.callStack = this.callStack.concat(callStack || []); - }); + } } - private getCallStackImpl(startFrame: number, levels: number): Promise { - return this.session.stackTrace(this.threadId, startFrame, levels).then(response => { + private async getCallStackImpl(startFrame: number, levels: number): Promise { + try { + const response = await this.session.stackTrace(this.threadId, startFrame, levels); if (!response || !response.body) { return []; } @@ -434,13 +436,13 @@ export class Thread implements IThread { rsf.endColumn || rsf.column ), startFrame + index); }); - }, (err: Error) => { + } catch (err) { if (this.stoppedDetails) { this.stoppedDetails.framesErrorMessage = err.message; } return []; - }); + } } /** @@ -617,8 +619,7 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint { } get column(): number | undefined { - // Only respect the column if the user explictly set the column to have an inline breakpoint - return this.verified && this.data && typeof this.data.column === 'number' && typeof this._column === 'number' ? this.data.column : this._column; + return this.verified && this.data && typeof this.data.column === 'number' ? this.data.column : this._column; } get message(): string | undefined { diff --git a/src/vs/workbench/contrib/debug/common/debugSchemas.ts b/src/vs/workbench/contrib/debug/common/debugSchemas.ts index 3a0dceb7532..a2a4b16a6bf 100644 --- a/src/vs/workbench/contrib/debug/common/debugSchemas.ts +++ b/src/vs/workbench/contrib/debug/common/debugSchemas.ts @@ -190,6 +190,11 @@ export const launchSchema: IJSONSchema = { }] }, description: nls.localize('app.launch.json.compounds.configurations', "Names of configurations that will be started as part of this compound.") + }, + preLaunchTask: { + type: 'string', + default: '', + description: nls.localize('compoundPrelaunchTask', "Task to run before any of the compound configurations start.") } }, default: defaultCompound diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index 8dbe2680204..ca30e45a3ac 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -4,32 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { equalsIgnoreCase } from 'vs/base/common/strings'; -import { IConfig, IDebuggerContribution, IDebugService, IDebugSession } from 'vs/workbench/contrib/debug/common/debug'; +import { IConfig, IDebuggerContribution, IDebugSession } from 'vs/workbench/contrib/debug/common/debug'; import { URI as uri } from 'vs/base/common/uri'; import { isAbsolute } from 'vs/base/common/path'; import { deepClone } from 'vs/base/common/objects'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { first } from 'vs/base/common/arrays'; const _formatPIIRegexp = /{([^}]+)}/g; -export function startDebugging(debugService: IDebugService, historyService: IHistoryService, noDebug: boolean, ): Promise { - const configurationManager = debugService.getConfigurationManager(); - let launch = configurationManager.selectedConfiguration.launch; - if (!launch || launch.getConfigurationNames().length === 0) { - const rootUri = historyService.getLastActiveWorkspaceRoot(); - launch = configurationManager.getLaunch(rootUri); - if (!launch || launch.getConfigurationNames().length === 0) { - const launches = configurationManager.getLaunches(); - launch = first(launches, l => !!(l && l.getConfigurationNames().length), launch); - } - - configurationManager.selectConfiguration(launch); - } - - return debugService.startDebugging(launch, undefined, { noDebug }); -} - export function formatPII(value: string, excludePII: boolean, args: { [key: string]: string }): string { return value.replace(_formatPIIRegexp, function (match, group) { if (excludePII && group.length > 0 && group[0] !== '_') { @@ -196,6 +177,9 @@ function convertPaths(msg: DebugProtocol.ProtocolMessage, fixSourcePath: (toDA: case 'setBreakpoints': fixSourcePath(true, (request.arguments).source); break; + case 'breakpointLocations': + fixSourcePath(true, (request.arguments).source); + break; case 'source': fixSourcePath(true, (request.arguments).source); break; diff --git a/src/vs/workbench/contrib/debug/common/replModel.ts b/src/vs/workbench/contrib/debug/common/replModel.ts index 3b828be1d58..a02e8305f8d 100644 --- a/src/vs/workbench/contrib/debug/common/replModel.ts +++ b/src/vs/workbench/contrib/debug/common/replModel.ts @@ -12,6 +12,7 @@ import { basenameOrAuthority } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { endsWith } from 'vs/base/common/strings'; import { generateUuid } from 'vs/base/common/uuid'; +import { Emitter } from 'vs/base/common/event'; const MAX_REPL_LENGTH = 10000; let topReplElementCounter = 0; @@ -108,6 +109,8 @@ export class ReplEvaluationResult extends ExpressionContainer implements IReplEl export class ReplModel { private replElements: IReplElement[] = []; + private readonly _onDidChangeElements = new Emitter(); + readonly onDidChangeElements = this._onDidChangeElements.event; getReplElements(): IReplElement[] { return this.replElements; @@ -150,6 +153,7 @@ export class ReplModel { if (this.replElements.length > MAX_REPL_LENGTH) { this.replElements.splice(0, this.replElements.length - MAX_REPL_LENGTH); } + this._onDidChangeElements.fire(); } logToRepl(session: IDebugSession, sev: severity, args: any[], frame?: { uri: URI, line: number, column: number }) { @@ -228,6 +232,7 @@ export class ReplModel { removeReplExpressions(): void { if (this.replElements.length > 0) { this.replElements = []; + this._onDidChangeElements.fire(); } } } diff --git a/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts index d3c1b805766..ce00abedcab 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts @@ -7,24 +7,14 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; 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'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { IProcessEnvironment } from 'vs/base/common/platform'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; -import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient { constructor( - @IMainProcessService readonly mainProcessService: IMainProcessService, - @IWindowsService private readonly windowsService: IWindowsService + @IMainProcessService readonly mainProcessService: IMainProcessService ) { super(mainProcessService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName)); } - - openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { - // TODO@Isidor use debug IPC channel - return (this.windowsService as WindowsService).openExtensionDevelopmentHostWindow(args, env); - } } registerSingleton(IExtensionHostDebugService, ExtensionHostDebugService, true); diff --git a/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts index 84ec75a9c84..70ddc23e1b5 100644 --- a/src/vs/workbench/contrib/debug/node/debugAdapter.ts +++ b/src/vs/workbench/contrib/debug/node/debugAdapter.ts @@ -133,7 +133,6 @@ export class SocketDebugAdapter extends StreamDebugAdapter { this.socket.end(); this.socket = undefined; } - return Promise.resolve(undefined); } } @@ -178,7 +177,6 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { if (options.env) { env = objects.mixin(env, options.env); } - delete env.VSCODE_PREVENT_FOREIGN_INSPECT; if (command === 'node') { if (Array.isArray(args) && args.length > 0) { @@ -216,14 +214,14 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { this._onExit.fire(code); }); - this.serverProcess.stdout.on('close', () => { + this.serverProcess.stdout!.on('close', () => { this._onError.fire(new Error('read error')); }); - this.serverProcess.stdout.on('error', error => { + this.serverProcess.stdout!.on('error', error => { this._onError.fire(error); }); - this.serverProcess.stdin.on('error', error => { + this.serverProcess.stdin!.on('error', error => { this._onError.fire(error); }); @@ -233,7 +231,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { // this.serverProcess.stdout.on('data', (data: string) => { // console.log('%c' + sanitize(data), 'background: #ddd; font-style: italic;'); // }); - this.serverProcess.stderr.on('data', (data: string) => { + this.serverProcess.stderr!.on('data', (data: string) => { const channel = outputService.getChannel(ExtensionsChannelId); if (channel) { channel.append(sanitize(data)); @@ -242,7 +240,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { } // finally connect to the DA - this.connect(this.serverProcess.stdout, this.serverProcess.stdin); + this.connect(this.serverProcess.stdout!, this.serverProcess.stdin!); } catch (err) { this._onError.fire(err); diff --git a/src/vs/workbench/contrib/debug/node/terminals.ts b/src/vs/workbench/contrib/debug/node/terminals.ts index 7813de75b26..7142a363971 100644 --- a/src/vs/workbench/contrib/debug/node/terminals.ts +++ b/src/vs/workbench/contrib/debug/node/terminals.ts @@ -29,34 +29,49 @@ export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestAr } } -export function hasChildProcesses(processId: number): boolean { - if (processId) { - try { - // if shell has at least one child process, assume that shell is busy - if (env.isWindows) { - const result = cp.spawnSync('wmic', ['process', 'get', 'ParentProcessId']); - if (result.stdout) { - const pids = result.stdout.toString().split('\r\n'); - if (!pids.some(p => parseInt(p) === processId)) { - return false; - } - } - } else { - const result = cp.spawnSync('/usr/bin/pgrep', ['-lP', String(processId)]); - if (result.stdout) { - const r = result.stdout.toString().trim(); - if (r.length === 0 || r.indexOf(' tmux') >= 0) { // ignore 'tmux'; see #43683 - return false; - } - } - } +function spawnAsPromised(command: string, args: string[]): Promise { + return new Promise((resolve, reject) => { + let stdout = ''; + const child = cp.spawn(command, args); + if (child.pid) { + child.stdout.on('data', (data: Buffer) => { + stdout += data.toString(); + }); } - catch (e) { - // silently ignore + child.on('error', err => { + reject(err); + }); + child.on('close', code => { + resolve(stdout); + }); + }); +} + +export function hasChildProcesses(processId: number): Promise { + if (processId) { + // if shell has at least one child process, assume that shell is busy + if (env.isWindows) { + return spawnAsPromised('wmic', ['process', 'get', 'ParentProcessId']).then(stdout => { + const pids = stdout.split('\r\n'); + return pids.some(p => parseInt(p) === processId); + }, error => { + return true; + }); + } else { + return spawnAsPromised('/usr/bin/pgrep', ['-lP', String(processId)]).then(stdout => { + const r = stdout.trim(); + if (r.length === 0 || r.indexOf(' tmux') >= 0) { // ignore 'tmux'; see #43683 + return false; + } else { + return true; + } + }, error => { + return true; + }); } } // fall back to safe side - return true; + return Promise.resolve(true); } const enum ShellType { cmd, powershell, bash } @@ -90,8 +105,6 @@ export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments shellType = ShellType.cmd; } else if (shell.indexOf('bash') >= 0) { shellType = ShellType.bash; - } else if (shell.indexOf('git\\bin\\bash.exe') >= 0) { - shellType = ShellType.bash; } let quote: (s: string) => string; @@ -148,7 +161,7 @@ export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments if (value === null) { command += `set "${key}=" && `; } else { - value = value.replace(/[\^\&]/g, s => `^${s}`); + value = value.replace(/[\^\&\|\<\>]/g, s => `^${s}`); command += `set "${key}=${value}" && `; } } diff --git a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts index db1f057192b..bead472a090 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts @@ -30,7 +30,7 @@ suite('Debug - ANSI Handling', () => { */ setup(() => { model = new DebugModel([], [], [], [], [], { isDirty: (e: any) => false }); - session = new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService); + session = new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService); const instantiationService: TestInstantiationService = workbenchInstantiationService(); linkDetector = instantiationService.createInstance(LinkDetector); diff --git a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts index 0f8e20d843b..9198304bfab 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts @@ -16,7 +16,7 @@ import { IBreakpointUpdateData, IDebugSessionOptions } from 'vs/workbench/contri import { NullOpenerService } from 'vs/platform/opener/common/opener'; function createMockSession(model: DebugModel, name = 'mockSession', options?: IDebugSessionOptions): DebugSession { - return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService); + return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService); } suite('Debug - Model', () => { @@ -513,7 +513,11 @@ suite('Debug - Model', () => { const grandChild = createMockSession(model, 'grandChild', { parentSession: child2, repl: 'mergeWithParent' }); const child3 = createMockSession(model, 'child3', { parentSession: parent }); + let parentChanges = 0; + parent.onDidChangeReplElements(() => ++parentChanges); + parent.appendToRepl('1\n', severity.Info); + assert.equal(parentChanges, 1); assert.equal(parent.getReplElements().length, 1); assert.equal(child1.getReplElements().length, 0); assert.equal(child2.getReplElements().length, 1); @@ -521,6 +525,7 @@ suite('Debug - Model', () => { assert.equal(child3.getReplElements().length, 0); grandChild.appendToRepl('1\n', severity.Info); + assert.equal(parentChanges, 2); assert.equal(parent.getReplElements().length, 2); assert.equal(child1.getReplElements().length, 0); assert.equal(child2.getReplElements().length, 2); @@ -528,6 +533,7 @@ suite('Debug - Model', () => { assert.equal(child3.getReplElements().length, 0); child3.appendToRepl('1\n', severity.Info); + assert.equal(parentChanges, 2); assert.equal(parent.getReplElements().length, 2); assert.equal(child1.getReplElements().length, 0); assert.equal(child2.getReplElements().length, 2); @@ -535,6 +541,7 @@ suite('Debug - Model', () => { assert.equal(child3.getReplElements().length, 1); child1.appendToRepl('1\n', severity.Info); + assert.equal(parentChanges, 2); assert.equal(parent.getReplElements().length, 2); assert.equal(child1.getReplElements().length, 1); assert.equal(child2.getReplElements().length, 2); diff --git a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts index 9ce2b7f792e..9178e857417 100644 --- a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts @@ -40,7 +40,8 @@ export class MockDebugService implements IDebugService { throw new Error('not implemented'); } - public focusStackFrame(focusedStackFrame: IStackFrame): void { + public focusStackFrame(focusedStackFrame: IStackFrame): Promise { + throw new Error('not implemented'); } sendAllBreakpoints(session?: IDebugSession): Promise { diff --git a/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts index 4e73431371f..188efd95a27 100644 --- a/src/vs/workbench/contrib/experiments/common/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/common/experimentService.ts @@ -6,7 +6,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Emitter, Event } from 'vs/base/common/event'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -120,7 +119,6 @@ export class ExperimentService extends Disposable implements IExperimentService @IStorageService private readonly storageService: IStorageService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @ITextFileService private readonly textFileService: ITextFileService, - @IEnvironmentService private readonly environmentService: IEnvironmentService, @ITelemetryService private readonly telemetryService: ITelemetryService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IRequestService private readonly requestService: IRequestService, @@ -333,7 +331,7 @@ export class ExperimentService extends Disposable implements IExperimentService return Promise.resolve(ExperimentState.NoRun); } - if (this.environmentService.appQuality === 'stable' && condition.insidersOnly === true) { + if (this.productService.quality === 'stable' && condition.insidersOnly === true) { return Promise.resolve(ExperimentState.NoRun); } diff --git a/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts index ab7a75444b5..700064e4cd9 100644 --- a/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts +++ b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts @@ -6,7 +6,6 @@ import * as assert from 'assert'; import { ExperimentActionType, ExperimentState, IExperiment, ExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices'; import { IExtensionManagementService, DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, ILocalExtension @@ -27,6 +26,7 @@ import { URI } from 'vs/base/common/uri'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { IProductService } from 'vs/platform/product/common/productService'; interface ExperimentSettings { enabled?: boolean; @@ -88,7 +88,7 @@ suite('Experiment Service', () => { instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => c, getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { } }); setup(() => { - instantiationService.stub(IEnvironmentService, {}); + instantiationService.stub(IProductService, {}); instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => c, getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { } }); }); @@ -174,7 +174,7 @@ suite('Experiment Service', () => { ] }; - instantiationService.stub(IEnvironmentService, { appQuality: 'stable' }); + instantiationService.stub(IProductService, { quality: 'stable' }); testObject = instantiationService.createInstance(TestExperimentService); return testObject.getExperimentById('experiment1').then(result => { assert.equal(result.enabled, true); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 1a2be4015cd..3a353120a20 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -55,7 +55,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { platform } from 'vs/base/common/process'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; -import { renderMarkdownDocument } from 'vs/workbench/common/markdownDocumentRenderer'; +import { renderMarkdownDocument } from 'vs/workbench/contrib/markdown/common/markdownDocumentRenderer'; import { IModeService } from 'vs/editor/common/services/modeService'; import { TokenizationRegistry } from 'vs/editor/common/modes'; import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; @@ -589,7 +589,6 @@ export class ExtensionEditor extends BaseEditor { this.contentDisposables.add(webviewElement.onDidFocus(() => this.fireOnDidFocus())); const removeLayoutParticipant = arrays.insert(this.layoutParticipants, { layout: () => { - webviewElement.layout(); webviewElement.layoutWebviewOverElement(template.content); } }); @@ -645,6 +644,8 @@ export class ExtensionEditor extends BaseEditor { body { padding: 10px 20px; line-height: 22px; + max-width: 780px; + margin: 0 auto; } img { @@ -855,7 +856,8 @@ export class ExtensionEditor extends BaseEditor { this.renderDebuggers(content, manifest, layout), this.renderViewContainers(content, manifest, layout), this.renderViews(content, manifest, layout), - this.renderLocalizations(content, manifest, layout) + this.renderLocalizations(content, manifest, layout), + this.renderCustomEditors(content, manifest, layout), ]; scrollableContent.scanDomNode(); @@ -1055,6 +1057,31 @@ export class ExtensionEditor extends BaseEditor { return true; } + private renderCustomEditors(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): boolean { + const webviewEditors = (manifest.contributes && manifest.contributes.webviewEditors) || []; + if (!webviewEditors.length) { + return false; + } + + const details = $('details', { open: true, ontoggle: onDetailsToggle }, + $('summary', { tabindex: '0' }, localize('customEditors', "Custom Editors ({0})", webviewEditors.length)), + $('table', undefined, + $('tr', undefined, + $('th', undefined, localize('customEditors view type', "View Type")), + $('th', undefined, localize('customEditors priority', "Priority")), + $('th', undefined, localize('customEditors filenamePattern', "Filename Pattern"))), + ...webviewEditors.map(webviewEditor => + $('tr', undefined, + $('td', undefined, webviewEditor.viewType), + $('td', undefined, webviewEditor.priority), + $('td', undefined, arrays.coalesce(webviewEditor.selector.map(x => x.filenamePattern)).join(', ')))) + ) + ); + + append(container, details); + return true; + } + private renderColorThemes(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): boolean { const contributes = manifest.contributes; const contrib = contributes && contributes.themes || []; @@ -1327,12 +1354,10 @@ export class ExtensionEditor extends BaseEditor { private loadContents(loadingTask: () => CacheResult, template: IExtensionEditorTemplate): Promise { addClass(template.content, 'loading'); - const result = loadingTask(); + const result = this.contentDisposables.add(loadingTask()); const onDone = () => removeClass(template.content, 'loading'); result.promise.then(onDone, onDone); - this.contentDisposables.add(toDisposable(() => result.dispose())); - return result.promise; } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts index b106359a0df..e7b3de3e4c1 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts @@ -80,7 +80,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe private _allIgnoredRecommendations: string[] = []; private _globallyIgnoredRecommendations: string[] = []; private _workspaceIgnoredRecommendations: string[] = []; - private _extensionsRecommendationsUrl: string; + private _extensionsRecommendationsUrl: string | undefined; public loadWorkspaceConfigPromise: Promise; private proactiveRecommendationsFetched: boolean = false; @@ -113,6 +113,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe super(); if (!this.isEnabled()) { + this.sessionSeed = 0; + this.loadWorkspaceConfigPromise = Promise.resolve(); return; } @@ -513,9 +515,26 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe return false; } - const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); let recommendationsToSuggest = Object.keys(this._importantExeBasedRecommendations); - recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); + + const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); + recommendationsToSuggest = this.filterInstalled(recommendationsToSuggest, installed, (extensionId) => { + const tip = this._importantExeBasedRecommendations[extensionId]; + + /* __GDPR__ + "exeExtensionRecommendations:alreadyInstalled" : { + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "exeName": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:alreadyInstalled', { extensionId, exeName: tip.exeFriendlyName || basename(tip.windowsPath!) }); + + }); + if (recommendationsToSuggest.length === 0) { + return false; + } + + recommendationsToSuggest = this.filterIgnoredOrNotAllowed(recommendationsToSuggest); if (recommendationsToSuggest.length === 0) { return false; } @@ -747,7 +766,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe private async promptRecommendedExtensionForFileType(recommendationsToSuggest: string[], installed: ILocalExtension[]): Promise { - recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); + recommendationsToSuggest = this.filterIgnoredOrNotAllowed(recommendationsToSuggest); + if (recommendationsToSuggest.length === 0) { + return false; + } + + recommendationsToSuggest = this.filterInstalled(recommendationsToSuggest, installed); if (recommendationsToSuggest.length === 0) { return false; } @@ -903,10 +927,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe ); } - private filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest: string[], installed: ILocalExtension[]): string[] { - + private filterIgnoredOrNotAllowed(recommendationsToSuggest: string[]): string[] { const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); - const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); return recommendationsToSuggest.filter(id => { if (importantRecommendationsIgnoreList.indexOf(id) !== -1) { return false; @@ -914,7 +936,17 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (!this.isExtensionAllowedToBeRecommended(id)) { return false; } + return true; + }); + } + + private filterInstalled(recommendationsToSuggest: string[], installed: ILocalExtension[], onAlreadyInstalled?: (id: string) => void): string[] { + const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); + return recommendationsToSuggest.filter(id => { if (installedExtensionsIds.has(id.toLowerCase())) { + if (onAlreadyInstalled) { + onAlreadyInstalled(id); + } return false; } return true; diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index db05deb3e72..b75b365641b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/extensions'; import { localize } from 'vs/nls'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -20,7 +19,7 @@ import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/brow import { OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction, ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowBuiltInExtensionsAction, UpdateAllAction, - EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction + EnableAllAction, EnableAllWorkspaceAction, DisableAllAction, DisableAllWorkspaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; @@ -81,7 +80,7 @@ const viewletDescriptor = new ViewletDescriptor( ExtensionsViewlet, VIEWLET_ID, localize('extensions', "Extensions"), - 'extensions', + 'codicon-extensions', 4 ); @@ -136,13 +135,13 @@ actionRegistry.registerWorkbenchAction(installVSIXActionDescriptor, 'Extensions: const disableAllAction = new SyncActionDescriptor(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL); actionRegistry.registerWorkbenchAction(disableAllAction, 'Extensions: Disable All Installed Extensions', ExtensionsLabel); -const disableAllWorkspaceAction = new SyncActionDescriptor(DisableAllWorkpsaceAction, DisableAllWorkpsaceAction.ID, DisableAllWorkpsaceAction.LABEL); +const disableAllWorkspaceAction = new SyncActionDescriptor(DisableAllWorkspaceAction, DisableAllWorkspaceAction.ID, DisableAllWorkspaceAction.LABEL); actionRegistry.registerWorkbenchAction(disableAllWorkspaceAction, 'Extensions: Disable All Installed Extensions for this Workspace', ExtensionsLabel); const enableAllAction = new SyncActionDescriptor(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL); actionRegistry.registerWorkbenchAction(enableAllAction, 'Extensions: Enable All Extensions', ExtensionsLabel); -const enableAllWorkspaceAction = new SyncActionDescriptor(EnableAllWorkpsaceAction, EnableAllWorkpsaceAction.ID, EnableAllWorkpsaceAction.LABEL); +const enableAllWorkspaceAction = new SyncActionDescriptor(EnableAllWorkspaceAction, EnableAllWorkspaceAction.ID, EnableAllWorkspaceAction.LABEL); actionRegistry.registerWorkbenchAction(enableAllWorkspaceAction, 'Extensions: Enable All Extensions for this Workspace', ExtensionsLabel); const checkForUpdatesAction = new SyncActionDescriptor(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL); @@ -274,12 +273,13 @@ CommandsRegistry.registerCommand({ throw new Error(localize('id required', "Extension id required.")); } const extensionManagementService = accessor.get(IExtensionManagementService); + const installed = await extensionManagementService.getInstalled(ExtensionType.User); + const [extensionToUninstall] = installed.filter(e => areSameExtensions(e.identifier, { id })); + if (!extensionToUninstall) { + throw new Error(localize('notInstalled', "Extension '{0}' is not installed. Make sure you use the full extension ID, including the publisher, e.g.: ms-vscode.csharp.", id)); + } + try { - const installed = await extensionManagementService.getInstalled(ExtensionType.User); - const [extensionToUninstall] = installed.filter(e => areSameExtensions(e.identifier, { id })); - if (!extensionToUninstall) { - return Promise.reject(new Error(localize('notInstalled', "Extension '{0}' is not installed. Make sure you use the full extension ID, including the publisher, e.g.: ms-vscode.csharp.", id))); - } await extensionManagementService.uninstall(extensionToUninstall, true); } catch (e) { onUnexpectedError(e); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 9b7717747f1..60e3786f299 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -54,7 +54,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING, IFileIconTheme, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ILabelService } from 'vs/platform/label/common/label'; -import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { prefersExecuteOnUI } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -143,8 +143,8 @@ export abstract class ExtensionAction extends Action implements IExtensionContai export class InstallAction extends ExtensionAction { - private static INSTALL_LABEL = localize('install', "Install"); - private static INSTALLING_LABEL = localize('installing', "Installing"); + private static readonly INSTALL_LABEL = localize('install', "Install"); + private static readonly INSTALLING_LABEL = localize('installing', "Installing"); private static readonly Class = 'extension-action prominent install'; private static readonly InstallingClass = 'extension-action install installing'; @@ -198,7 +198,7 @@ export class InstallAction extends ExtensionAction { this.tooltip = InstallAction.INSTALLING_LABEL; } else { if (this._manifest && this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { - if (isUIExtension(this._manifest, this.productService, this.configurationService)) { + if (prefersExecuteOnUI(this._manifest, this.productService, this.configurationService)) { this.label = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`; this.tooltip = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`; } else { @@ -277,8 +277,8 @@ export class InstallAction extends ExtensionAction { export abstract class InstallInOtherServerAction extends ExtensionAction { - protected static INSTALL_LABEL = localize('install', "Install"); - protected static INSTALLING_LABEL = localize('installing', "Installing"); + protected static readonly INSTALL_LABEL = localize('install', "Install"); + protected static readonly INSTALLING_LABEL = localize('installing', "Installing"); private static readonly Class = 'extension-action prominent install'; private static readonly InstallingClass = 'extension-action install installing'; @@ -566,7 +566,7 @@ export class ExtensionActionViewItem extends ActionViewItem { updateEnabled(): void { super.updateEnabled(); - if (this.options.tabOnlyOnFocus && this.getAction().enabled && !this._hasFocus) { + if (this.label && this.options.tabOnlyOnFocus && this.getAction().enabled && !this._hasFocus) { DOM.removeTabIndexAndUpdateFocus(this.label); } } @@ -577,7 +577,7 @@ export class ExtensionActionViewItem extends ActionViewItem { return; } this._hasFocus = value; - if (this.getAction().enabled) { + if (this.label && this.getAction().enabled) { if (this._hasFocus) { this.label.tabIndex = 0; } else { @@ -726,7 +726,7 @@ export class ManageExtensionAction extends ExtensionDropDownAction { export class InstallAnotherVersionAction extends ExtensionAction { static readonly ID = 'workbench.extensions.action.install.anotherVersion'; - static LABEL = localize('install another version', "Install Another Version..."); + static readonly LABEL = localize('install another version', "Install Another Version..."); constructor( @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @@ -832,7 +832,7 @@ export class ExtensionSettingsAction extends ExtensionAction { export class EnableForWorkspaceAction extends ExtensionAction { static readonly ID = 'extensions.enableForWorkspace'; - static LABEL = localize('enableForWorkspaceAction', "Enable (Workspace)"); + static readonly LABEL = localize('enableForWorkspaceAction', "Enable (Workspace)"); constructor( @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @@ -859,7 +859,7 @@ export class EnableForWorkspaceAction extends ExtensionAction { export class EnableGloballyAction extends ExtensionAction { static readonly ID = 'extensions.enableGlobally'; - static LABEL = localize('enableGloballyAction', "Enable"); + static readonly LABEL = localize('enableGloballyAction', "Enable"); constructor( @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @@ -886,7 +886,7 @@ export class EnableGloballyAction extends ExtensionAction { export class DisableForWorkspaceAction extends ExtensionAction { static readonly ID = 'extensions.disableForWorkspace'; - static LABEL = localize('disableForWorkspaceAction', "Disable (Workspace)"); + static readonly LABEL = localize('disableForWorkspaceAction', "Disable (Workspace)"); constructor(readonly runningExtensions: IExtensionDescription[], @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @@ -914,7 +914,7 @@ export class DisableForWorkspaceAction extends ExtensionAction { export class DisableGloballyAction extends ExtensionAction { static readonly ID = 'extensions.disableGlobally'; - static LABEL = localize('disableGloballyAction', "Disable"); + static readonly LABEL = localize('disableGloballyAction', "Disable"); constructor(readonly runningExtensions: IExtensionDescription[], @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @@ -1010,7 +1010,7 @@ export class DisableDropDownAction extends ExtensionEditorDropDownAction { export class CheckForUpdatesAction extends Action { static readonly ID = 'workbench.extensions.action.checkForUpdates'; - static LABEL = localize('checkForUpdates', "Check for Extension Updates"); + static readonly LABEL = localize('checkForUpdates', "Check for Extension Updates"); constructor( id = CheckForUpdatesAction.ID, @@ -1082,7 +1082,7 @@ export class ToggleAutoUpdateAction extends Action { export class EnableAutoUpdateAction extends ToggleAutoUpdateAction { static readonly ID = 'workbench.extensions.action.enableAutoUpdate'; - static LABEL = localize('enableAutoUpdate', "Enable Auto Updating Extensions"); + static readonly LABEL = localize('enableAutoUpdate', "Enable Auto Updating Extensions"); constructor( id = EnableAutoUpdateAction.ID, @@ -1096,7 +1096,7 @@ export class EnableAutoUpdateAction extends ToggleAutoUpdateAction { export class DisableAutoUpdateAction extends ToggleAutoUpdateAction { static readonly ID = 'workbench.extensions.action.disableAutoUpdate'; - static LABEL = localize('disableAutoUpdate', "Disable Auto Updating Extensions"); + static readonly LABEL = localize('disableAutoUpdate', "Disable Auto Updating Extensions"); constructor( id = EnableAutoUpdateAction.ID, @@ -1110,7 +1110,7 @@ export class DisableAutoUpdateAction extends ToggleAutoUpdateAction { export class UpdateAllAction extends Action { static readonly ID = 'workbench.extensions.action.updateAllExtensions'; - static LABEL = localize('updateAll', "Update All Extensions"); + static readonly LABEL = localize('updateAll', "Update All Extensions"); constructor( id = UpdateAllAction.ID, @@ -1417,7 +1417,7 @@ export class InstallExtensionsAction extends OpenExtensionsViewletAction { export class ShowEnabledExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.showEnabledExtensions'; - static LABEL = localize('showEnabledExtensions', "Show Enabled Extensions"); + static readonly LABEL = localize('showEnabledExtensions', "Show Enabled Extensions"); constructor( id: string, @@ -1440,7 +1440,7 @@ export class ShowEnabledExtensionsAction extends Action { export class ShowInstalledExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.showInstalledExtensions'; - static LABEL = localize('showInstalledExtensions', "Show Installed Extensions"); + static readonly LABEL = localize('showInstalledExtensions', "Show Installed Extensions"); constructor( id: string, @@ -1463,7 +1463,7 @@ export class ShowInstalledExtensionsAction extends Action { export class ShowDisabledExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.showDisabledExtensions'; - static LABEL = localize('showDisabledExtensions', "Show Disabled Extensions"); + static readonly LABEL = localize('showDisabledExtensions', "Show Disabled Extensions"); constructor( id: string, @@ -1486,7 +1486,7 @@ export class ShowDisabledExtensionsAction extends Action { export class ClearExtensionsInputAction extends Action { static readonly ID = 'workbench.extensions.action.clearExtensionsInput'; - static LABEL = localize('clearExtensionsInput', "Clear Extensions Input"); + static readonly LABEL = localize('clearExtensionsInput', "Clear Extensions Input"); constructor( id: string, @@ -1517,7 +1517,7 @@ export class ClearExtensionsInputAction extends Action { export class ShowBuiltInExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.listBuiltInExtensions'; - static LABEL = localize('showBuiltInExtensions', "Show Built-in Extensions"); + static readonly LABEL = localize('showBuiltInExtensions', "Show Built-in Extensions"); constructor( id: string, @@ -1540,7 +1540,7 @@ export class ShowBuiltInExtensionsAction extends Action { export class ShowOutdatedExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.listOutdatedExtensions'; - static LABEL = localize('showOutdatedExtensions', "Show Outdated Extensions"); + static readonly LABEL = localize('showOutdatedExtensions', "Show Outdated Extensions"); constructor( id: string, @@ -1563,7 +1563,7 @@ export class ShowOutdatedExtensionsAction extends Action { export class ShowPopularExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.showPopularExtensions'; - static LABEL = localize('showPopularExtensions', "Show Popular Extensions"); + static readonly LABEL = localize('showPopularExtensions', "Show Popular Extensions"); constructor( id: string, @@ -1586,7 +1586,7 @@ export class ShowPopularExtensionsAction extends Action { export class ShowRecommendedExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.showRecommendedExtensions'; - static LABEL = localize('showRecommendedExtensions', "Show Recommended Extensions"); + static readonly LABEL = localize('showRecommendedExtensions', "Show Recommended Extensions"); constructor( id: string, @@ -1606,33 +1606,10 @@ export class ShowRecommendedExtensionsAction extends Action { } } -export class ShowSyncedExtensionsAction extends Action { - - static readonly ID = 'workbench.extensions.action.listSyncedExtensions'; - static LABEL = localize('showSyncedExtensions', "Show My Accoount Extensions"); - - constructor( - id: string, - label: string, - @IViewletService private readonly viewletService: IViewletService - ) { - super(id, label, undefined, true); - } - - run(): Promise { - return this.viewletService.openViewlet(VIEWLET_ID, true) - .then(viewlet => viewlet as IExtensionsViewlet) - .then(viewlet => { - viewlet.search('@myaccount '); - viewlet.focus(); - }); - } -} - export class InstallWorkspaceRecommendedExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.installWorkspaceRecommendedExtensions'; - static LABEL = localize('installWorkspaceRecommendedExtensions', "Install All Workspace Recommended Extensions"); + static readonly LABEL = localize('installWorkspaceRecommendedExtensions', "Install All Workspace Recommended Extensions"); private _recommendations: IExtensionRecommendation[] = []; get recommendations(): IExtensionRecommendation[] { return this._recommendations; } @@ -1676,7 +1653,7 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action { private async installExtension(extension: IExtension): Promise { try { if (extension.local && extension.gallery) { - if (isUIExtension(extension.local.manifest, this.productService, this.configurationService)) { + if (prefersExecuteOnUI(extension.local.manifest, this.productService, this.configurationService)) { if (this.extensionManagementServerService.localExtensionManagementServer) { await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(extension.gallery); return; @@ -1697,7 +1674,7 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action { export class InstallRecommendedExtensionAction extends Action { static readonly ID = 'workbench.extensions.action.installRecommendedExtension'; - static LABEL = localize('installRecommendedExtension', "Install Recommended Extension"); + static readonly LABEL = localize('installRecommendedExtension', "Install Recommended Extension"); private extensionId: string; @@ -1788,7 +1765,7 @@ export class UndoIgnoreExtensionRecommendationAction extends Action { export class ShowRecommendedKeymapExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.showRecommendedKeymapExtensions'; - static SHORT_LABEL = localize('showRecommendedKeymapExtensionsShort', "Keymaps"); + static readonly SHORT_LABEL = localize('showRecommendedKeymapExtensionsShort', "Keymaps"); constructor( id: string, @@ -1811,7 +1788,7 @@ export class ShowRecommendedKeymapExtensionsAction extends Action { export class ShowLanguageExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.showLanguageExtensions'; - static SHORT_LABEL = localize('showLanguageExtensionsShort', "Language Extensions"); + static readonly SHORT_LABEL = localize('showLanguageExtensionsShort', "Language Extensions"); constructor( id: string, @@ -1834,7 +1811,7 @@ export class ShowLanguageExtensionsAction extends Action { export class ShowAzureExtensionsAction extends Action { static readonly ID = 'workbench.extensions.action.showAzureExtensions'; - static SHORT_LABEL = localize('showAzureExtensionsShort', "Azure Extensions"); + static readonly SHORT_LABEL = localize('showAzureExtensionsShort', "Azure Extensions"); constructor( id: string, @@ -2124,7 +2101,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio protected getWorkspaceFolderExtensionsConfigContent(extensionsFileResource: URI): Promise { return Promise.resolve(this.fileService.readFile(extensionsFileResource)) .then(content => { - return (json.parse(content.value.toString())); + return (json.parse(content.value.toString()) || {}); }, err => ({ recommendations: [], unwantedRecommendations: [] })); } @@ -2176,7 +2153,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction { static readonly ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions'; - static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)"); + static readonly LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)"); constructor( @@ -2212,7 +2189,7 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction { static readonly ID = 'workbench.extensions.action.configureWorkspaceFolderRecommendedExtensions'; - static LABEL = localize('configureWorkspaceFolderRecommendedExtensions', "Configure Recommended Extensions (Workspace Folder)"); + static readonly LABEL = localize('configureWorkspaceFolderRecommendedExtensions', "Configure Recommended Extensions (Workspace Folder)"); constructor( @@ -2685,7 +2662,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { export class DisableAllAction extends Action { static readonly ID = 'workbench.extensions.action.disableAll'; - static LABEL = localize('disableAll', "Disable All Installed Extensions"); + static readonly LABEL = localize('disableAll', "Disable All Installed Extensions"); constructor( @@ -2707,14 +2684,14 @@ export class DisableAllAction extends Action { } } -export class DisableAllWorkpsaceAction extends Action { +export class DisableAllWorkspaceAction extends Action { static readonly ID = 'workbench.extensions.action.disableAllWorkspace'; - static LABEL = localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace"); + static readonly LABEL = localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace"); constructor( - id: string = DisableAllWorkpsaceAction.ID, label: string = DisableAllWorkpsaceAction.LABEL, + id: string = DisableAllWorkspaceAction.ID, label: string = DisableAllWorkspaceAction.LABEL, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService @@ -2737,7 +2714,7 @@ export class DisableAllWorkpsaceAction extends Action { export class EnableAllAction extends Action { static readonly ID = 'workbench.extensions.action.enableAll'; - static LABEL = localize('enableAll', "Enable All Extensions"); + static readonly LABEL = localize('enableAll', "Enable All Extensions"); constructor( @@ -2759,14 +2736,14 @@ export class EnableAllAction extends Action { } } -export class EnableAllWorkpsaceAction extends Action { +export class EnableAllWorkspaceAction extends Action { static readonly ID = 'workbench.extensions.action.enableAllWorkspace'; - static LABEL = localize('enableAllWorkspace', "Enable All Extensions for this Workspace"); + static readonly LABEL = localize('enableAllWorkspace', "Enable All Extensions for this Workspace"); constructor( - id: string = EnableAllWorkpsaceAction.ID, label: string = EnableAllWorkpsaceAction.LABEL, + id: string = EnableAllWorkspaceAction.ID, label: string = EnableAllWorkspaceAction.LABEL, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService @@ -2789,7 +2766,7 @@ export class EnableAllWorkpsaceAction extends Action { export class InstallVSIXAction extends Action { static readonly ID = 'workbench.extensions.action.installVSIX'; - static LABEL = localize('installVSIX', "Install from VSIX..."); + static readonly LABEL = localize('installVSIX', "Install from VSIX..."); constructor( id = InstallVSIXAction.ID, @@ -2841,7 +2818,7 @@ export class InstallVSIXAction extends Action { export class ReinstallAction extends Action { static readonly ID = 'workbench.extensions.action.reinstall'; - static LABEL = localize('reinstall', "Reinstall Extension..."); + static readonly LABEL = localize('reinstall', "Reinstall Extension..."); constructor( id: string = ReinstallAction.ID, label: string = ReinstallAction.LABEL, @@ -2907,7 +2884,7 @@ export class ReinstallAction extends Action { export class InstallSpecificVersionOfExtensionAction extends Action { static readonly ID = 'workbench.extensions.action.install.specificVersion'; - static LABEL = localize('install previous version', "Install Specific Version of Extension..."); + static readonly LABEL = localize('install previous version', "Install Specific Version of Extension..."); constructor( id: string = InstallSpecificVersionOfExtensionAction.ID, label: string = InstallSpecificVersionOfExtensionAction.LABEL, diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts index 919c3762319..41bb90eb632 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts @@ -213,7 +213,7 @@ export class ExtensionsTree extends WorkbenchAsyncDataTree { + this.disposables.add(this.onDidChangeSelection(event => { if (event.browserEvent && event.browserEvent instanceof KeyboardEvent) { extensionsWorkdbenchService.open(event.elements[0].extension, false); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 8278838492b..2bee5aa811e 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -22,12 +22,12 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, AutoUpdate import { ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction, - EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, ShowSyncedExtensionsAction + EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; -import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView, SyncedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews'; +import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews'; import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -58,7 +58,6 @@ import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsView import { RemoteNameContext } from 'vs/workbench/browser/contextkeys'; import { ILabelService } from 'vs/platform/label/common/label'; import { MementoObject } from 'vs/workbench/common/memento'; -import { SyncStatus, CONTEXT_SYNC_STATE } from 'vs/platform/userDataSync/common/userDataSync'; const NonEmptyWorkspaceContext = new RawContextKey('nonEmptyWorkspace', false); const DefaultViewsContext = new RawContextKey('defaultExtensionViews', true); @@ -71,7 +70,6 @@ const HasInstalledExtensionsContext = new RawContextKey('hasInstalledEx const SearchBuiltInExtensionsContext = new RawContextKey('searchBuiltInExtensions', false); const RecommendedExtensionsContext = new RawContextKey('recommendedExtensions', false); const DefaultRecommendedExtensionsContext = new RawContextKey('defaultRecommendedExtensions', false); -const SyncedExtensionsContext = new RawContextKey('syncedExtensions', false); const viewIdNameMappings: { [id: string]: string } = { 'extensions.listView': localize('marketPlace', "Marketplace"), 'extensions.enabledExtensionList': localize('enabledExtensions', "Enabled"), @@ -111,7 +109,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio viewDescriptors.push(this.createDefaultRecommendedExtensionsListViewDescriptor()); viewDescriptors.push(this.createOtherRecommendedExtensionsListViewDescriptor()); viewDescriptors.push(this.createWorkspaceRecommendedExtensionsListViewDescriptor()); - viewDescriptors.push(this.createSyncedExtensionsViewDescriptor()); if (this.extensionManagementServerService.localExtensionManagementServer) { viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.localExtensionManagementServer)); @@ -315,16 +312,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio }; } - private createSyncedExtensionsViewDescriptor(): IViewDescriptor { - const id = 'extensions.syncedExtensionsList'; - return { - id, - name: viewIdNameMappings[id], - ctorDescriptor: { ctor: SyncedExtensionsView }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has('config.userConfiguration.enableSync'), ContextKeyExpr.has('syncedExtensions')), - weight: 100 - }; - } } export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensionsViewlet { @@ -341,7 +328,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio private hasInstalledExtensionsContextKey: IContextKey; private searchBuiltInExtensionsContextKey: IContextKey; private recommendedExtensionsContextKey: IContextKey; - private syncedExtensionsContextKey: IContextKey; private defaultRecommendedExtensionsContextKey: IContextKey; private searchDelayer: Delayer; @@ -366,7 +352,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio @IWorkspaceContextService contextService: IWorkspaceContextService, @IContextKeyService contextKeyService: IContextKeyService, @IContextMenuService contextMenuService: IContextMenuService, - @IExtensionService extensionService: IExtensionService + @IExtensionService extensionService: IExtensionService, ) { super(VIEWLET_ID, `${VIEWLET_ID}.state`, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); @@ -383,7 +369,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService); this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService); this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue(ShowRecommendationsOnlyOnDemandKey)); - this.syncedExtensionsContextKey = SyncedExtensionsContext.bindTo(contextKeyService); this._register(this.viewletService.onDidViewletOpen(this.onViewletOpen, this)); this.searchViewletState = this.getMemento(StorageScope.WORKSPACE); @@ -483,7 +468,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, ShowBuiltInExtensionsAction.LABEL), this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL), this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL), - this.instantiationService.createInstance(ShowSyncedExtensionsAction, ShowSyncedExtensionsAction.ID, ShowSyncedExtensionsAction.LABEL), new Separator(), this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Sort By: Install Count"), this.onSearchChange, 'installs'), this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.rating', localize('sort by rating', "Sort By: Rating"), this.onSearchChange, 'rating'), @@ -531,7 +515,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio private doSearch(): Promise { const value = this.normalizedQuery(); - const isSyncedExtensionsQuery = ExtensionsListView.isSyncedExtensionsQuery(value); const isRecommendedExtensionsQuery = ExtensionsListView.isRecommendedExtensionsQuery(value); this.searchInstalledExtensionsContextKey.set(ExtensionsListView.isInstalledExtensionsQuery(value)); this.searchOutdatedExtensionsContextKey.set(ExtensionsListView.isOutdatedExtensionsQuery(value)); @@ -539,8 +522,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.searchDisabledExtensionsContextKey.set(ExtensionsListView.isDisabledExtensionsQuery(value)); this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value)); this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery); - this.syncedExtensionsContextKey.set(isSyncedExtensionsQuery); - this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery && !isSyncedExtensionsQuery); + this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery); this.nonEmptyWorkspaceContextKey.set(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY); this.defaultViewsContextKey.set(!value); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 11f9df53d68..9429224313b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -47,7 +47,6 @@ import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async import { IProductService } from 'vs/platform/product/common/productService'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; class ExtensionsViewState extends Disposable implements IExtensionsViewState { @@ -104,7 +103,6 @@ export class ExtensionsListView extends ViewletPanel { @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, @IProductService protected readonly productService: IProductService, @IContextKeyService contextKeyService: IContextKeyService, - @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, ) { super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title, showActionsAlways: true }, keybindingService, contextMenuService, configurationService, contextKeyService); this.server = options.server; @@ -126,7 +124,7 @@ export class ExtensionsListView extends ViewletPanel { const delegate = new Delegate(); const extensionsViewState = new ExtensionsViewState(); const renderer = this.instantiationService.createInstance(Renderer, extensionsViewState); - this.list = this.instantiationService.createInstance(WorkbenchPagedList, 'Extensions', extensionsList, delegate, [renderer], { + this.list = this.instantiationService.createInstance>(WorkbenchPagedList, 'Extensions', extensionsList, delegate, [renderer], { ariaLabel: localize('extensions', "Extensions"), multipleSelectionSupport: false, setRowLineHeight: false, @@ -441,8 +439,6 @@ export class ExtensionsListView extends ViewletPanel { return this.getAllRecommendationsModel(query, options, token); } else if (ExtensionsListView.isRecommendedExtensionsQuery(query.value)) { return this.getRecommendationsModel(query, options, token); - } else if (ExtensionsListView.isSyncedExtensionsQuery(query.value)) { - return this.getSyncedExtensionsModel(query, options, token); } if (/\bcurated:([^\s]+)\b/.test(query.value)) { @@ -623,28 +619,28 @@ export class ExtensionsListView extends ViewletPanel { } // Given all recommendations, trims and returns recommendations in the relevant order after filtering out installed extensions - private getTrimmedRecommendations(installedExtensions: IExtension[], value: string, fileBasedRecommendations: IExtensionRecommendation[], otherRecommendations: IExtensionRecommendation[], workpsaceRecommendations: IExtensionRecommendation[]): string[] { + private getTrimmedRecommendations(installedExtensions: IExtension[], value: string, fileBasedRecommendations: IExtensionRecommendation[], otherRecommendations: IExtensionRecommendation[], workspaceRecommendations: IExtensionRecommendation[]): string[] { const totalCount = 8; - workpsaceRecommendations = workpsaceRecommendations + workspaceRecommendations = workspaceRecommendations .filter(recommendation => { return !this.isRecommendationInstalled(recommendation, installedExtensions) && recommendation.extensionId.toLowerCase().indexOf(value) > -1; }); fileBasedRecommendations = fileBasedRecommendations.filter(recommendation => { return !this.isRecommendationInstalled(recommendation, installedExtensions) - && workpsaceRecommendations.every(workspaceRecommendation => workspaceRecommendation.extensionId !== recommendation.extensionId) + && workspaceRecommendations.every(workspaceRecommendation => workspaceRecommendation.extensionId !== recommendation.extensionId) && recommendation.extensionId.toLowerCase().indexOf(value) > -1; }); otherRecommendations = otherRecommendations.filter(recommendation => { return !this.isRecommendationInstalled(recommendation, installedExtensions) && fileBasedRecommendations.every(fileBasedRecommendation => fileBasedRecommendation.extensionId !== recommendation.extensionId) - && workpsaceRecommendations.every(workspaceRecommendation => workspaceRecommendation.extensionId !== recommendation.extensionId) + && workspaceRecommendations.every(workspaceRecommendation => workspaceRecommendation.extensionId !== recommendation.extensionId) && recommendation.extensionId.toLowerCase().indexOf(value) > -1; }); const otherCount = Math.min(2, otherRecommendations.length); - const fileBasedCount = Math.min(fileBasedRecommendations.length, totalCount - workpsaceRecommendations.length - otherCount); - const recommendations = workpsaceRecommendations; + const fileBasedCount = Math.min(fileBasedRecommendations.length, totalCount - workspaceRecommendations.length - otherCount); + const recommendations = workspaceRecommendations; recommendations.push(...fileBasedRecommendations.splice(0, fileBasedCount)); recommendations.push(...otherRecommendations.splice(0, otherCount)); @@ -689,23 +685,6 @@ export class ExtensionsListView extends ViewletPanel { .then(result => this.getPagedModel(result)); } - private async getSyncedExtensionsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise> { - const syncedExtensions = await this.userDataSyncService.getRemoteExtensions(); - if (!syncedExtensions.length) { - return this.showEmptyModel(); - } - const ids: string[] = [], names: string[] = []; - for (const installed of syncedExtensions) { - if (installed.identifier.uuid) { - ids.push(installed.identifier.uuid); - } else { - names.push(installed.identifier.id); - } - } - const pager = await this.extensionsWorkbenchService.queryGallery({ ids, names, pageSize: ids.length }, token); - return this.getPagedModel(pager || []); - } - // Sorts the firstPage of the pager in the same order as given array of extension ids private sortFirstPage(pager: IPager, ids: string[]) { ids = ids.map(x => x.toLowerCase()); @@ -729,10 +708,10 @@ export class ExtensionsListView extends ViewletPanel { if (count === 0 && this.isBodyVisible()) { if (error) { if (error instanceof ExtensionListViewWarning) { - this.bodyTemplate.messageSeverityIcon.className = SeverityIcon.className(Severity.Warning); + this.bodyTemplate.messageSeverityIcon.className = `codicon ${SeverityIcon.className(Severity.Warning)}`; this.bodyTemplate.messageBox.textContent = getErrorMessage(error); } else { - this.bodyTemplate.messageSeverityIcon.className = SeverityIcon.className(Severity.Error); + this.bodyTemplate.messageSeverityIcon.className = `codicon ${SeverityIcon.className(Severity.Error)}`; this.bodyTemplate.messageBox.textContent = localize('error', "Error while loading extensions. {0}", getErrorMessage(error)); } } else { @@ -845,10 +824,6 @@ export class ExtensionsListView extends ViewletPanel { return /@recommended:keymaps/i.test(query); } - static isSyncedExtensionsQuery(query: string): boolean { - return /@myaccount/i.test(query); - } - focus(): void { super.focus(); if (!this.list) { @@ -884,11 +859,10 @@ export class ServerExtensionsView extends ExtensionsListView { @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService, @IProductService productService: IProductService, - @IContextKeyService contextKeyService: IContextKeyService, - @IUserDataSyncService userDataSyncService: IUserDataSyncService + @IContextKeyService contextKeyService: IContextKeyService ) { options.server = server; - super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService, productService, contextKeyService, userDataSyncService); + super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService, productService, contextKeyService); this._register(onDidChangeTitle(title => this.updateTitle(title))); } @@ -903,7 +877,7 @@ export class ServerExtensionsView extends ExtensionsListView { getActions(): IAction[] { if (this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManagementServerService.localExtensionManagementServer === this.server) { const installLocalExtensionsInRemoteAction = this._register(this.instantiationService.createInstance(InstallLocalExtensionsInRemoteAction)); - installLocalExtensionsInRemoteAction.class = 'octicon octicon-cloud-download'; + installLocalExtensionsInRemoteAction.class = 'codicon codicon-cloud-download'; return [installLocalExtensionsInRemoteAction]; } return []; @@ -944,14 +918,6 @@ export class BuiltInBasicsExtensionsView extends ExtensionsListView { } } -export class SyncedExtensionsView extends ExtensionsListView { - - async show(query: string): Promise> { - query = query || '@myaccount'; - return ExtensionsListView.isSyncedExtensionsQuery(query) ? super.show(query) : this.showEmptyModel(); - } -} - export class DefaultRecommendedExtensionsView extends ExtensionsListView { private readonly recommendedExtensionsQuery = '@recommended:all'; @@ -1008,11 +974,11 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView { getActions(): IAction[] { if (!this.installAllAction) { this.installAllAction = this._register(this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, InstallWorkspaceRecommendedExtensionsAction.LABEL, [])); - this.installAllAction.class = 'octicon octicon-cloud-download'; + this.installAllAction.class = 'codicon codicon-cloud-download'; } const configureWorkspaceFolderAction = this._register(this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL)); - configureWorkspaceFolderAction.class = 'octicon octicon-pencil'; + configureWorkspaceFolderAction.class = 'codicon codicon-pencil'; return [this.installAllAction, configureWorkspaceFolderAction]; } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts index 553c40fbd50..4129bb1849b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts @@ -81,7 +81,7 @@ export class InstallCountWidget extends ExtensionWidget { installLabel = installCount.toLocaleString(platform.locale); } - append(this.container, $('span.octicon.octicon-cloud-download')); + append(this.container, $('span.codicon.codicon-cloud-download')); const count = append(this.container, $('span.count')); count.textContent = installLabel; } @@ -224,7 +224,7 @@ export class RecommendationWidget extends ExtensionWidget { if (extRecommendations[this.extension.identifier.id.toLowerCase()]) { this.element = append(this.parent, $('div.bookmark')); const recommendation = append(this.element, $('.recommendation')); - append(recommendation, $('span.octicon.octicon-star')); + append(recommendation, $('span.codicon.codicon-star')); const applyBookmarkStyle = (theme: ITheme) => { const bgColor = theme.getColor(extensionButtonProminentBackground); const fgColor = theme.getColor(extensionButtonProminentForeground); @@ -290,7 +290,7 @@ class RemoteBadge extends Disposable { } private render(): void { - append(this.element, $('span.octicon.octicon-remote')); + append(this.element, $('span.codicon.codicon-remote')); const applyBadgeStyle = () => { if (!this.element) { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 0cb59589bca..88e34919e32 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -14,7 +14,7 @@ import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, - InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionIdentifier + InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionIdentifier, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -24,7 +24,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { URI } from 'vs/base/common/uri'; import { IExtension, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey, AutoCheckUpdatesConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; +import { IURLService, IURLHandler, IOpenURLOptions } from 'vs/platform/url/common/url'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ILogService } from 'vs/platform/log/common/log'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; @@ -308,8 +308,8 @@ ${this.description} class Extensions extends Disposable { - private readonly _onChange: Emitter = new Emitter(); - get onChange(): Event { return this._onChange.event; } + private readonly _onChange: Emitter<{ extension: Extension, operation?: InstallOperation } | undefined> = this._register(new Emitter<{ extension: Extension, operation?: InstallOperation } | undefined>()); + get onChange(): Event<{ extension: Extension, operation?: InstallOperation } | undefined> { return this._onChange.event; } private installing: Extension[] = []; private uninstalling: Extension[] = []; @@ -370,7 +370,7 @@ class Extensions extends Disposable { const local = extension.local.metadata ? extension.local : await this.server.extensionManagementService.updateMetadata(extension.local, { id: compatible.identifier.uuid, publisherDisplayName: compatible.publisherDisplayName, publisherId: compatible.publisherId }); extension.local = local; extension.gallery = compatible; - this._onChange.fire(extension); + this._onChange.fire({ extension }); return true; } return false; @@ -397,7 +397,7 @@ class Extensions extends Disposable { const extension = this.installed.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0] || this.instantiationService.createInstance(Extension, this.stateProvider, this.server, undefined, gallery); this.installing.push(extension); - this._onChange.fire(extension); + this._onChange.fire({ extension }); } } @@ -421,9 +421,10 @@ class Extensions extends Disposable { if (!extension.gallery) { extension.gallery = gallery; } + extension.enablementState = this.extensionEnablementService.getEnablementState(local); } } - this._onChange.fire(error ? undefined : extension); + this._onChange.fire(error || !extension ? undefined : { extension, operation: event.operation }); } private onUninstallExtension(identifier: IExtensionIdentifier): void { @@ -431,7 +432,7 @@ class Extensions extends Disposable { if (extension) { const uninstalling = this.uninstalling.filter(e => areSameExtensions(e.identifier, identifier))[0] || extension; this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => !areSameExtensions(e.identifier, identifier))]; - this._onChange.fire(uninstalling); + this._onChange.fire(uninstalling ? { extension: uninstalling } : undefined); } } @@ -442,18 +443,18 @@ class Extensions extends Disposable { const uninstalling = this.uninstalling.filter(e => areSameExtensions(e.identifier, identifier))[0]; this.uninstalling = this.uninstalling.filter(e => !areSameExtensions(e.identifier, identifier)); if (uninstalling) { - this._onChange.fire(uninstalling); + this._onChange.fire({ extension: uninstalling }); } } - private onEnablementChanged(platformExtensions: IPlatformExtension[]) { + private onEnablementChanged(platformExtensions: readonly IPlatformExtension[]) { const extensions = this.local.filter(e => platformExtensions.some(p => areSameExtensions(e.identifier, p.identifier))); for (const extension of extensions) { if (extension.local) { const enablementState = this.extensionEnablementService.getEnablementState(extension.local); if (enablementState !== extension.enablementState) { (extension as Extension).enablementState = enablementState; - this._onChange.fire(extension as Extension); + this._onChange.fire({ extension: extension as Extension }); } } } @@ -504,13 +505,15 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension @IProductService private readonly productService: IProductService ) { super(); - if (this.extensionManagementServerService.localExtensionManagementServer) { + if (extensionManagementServerService.localExtensionManagementServer) { this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer, ext => this.getExtensionState(ext))); - this._register(this.localExtensions.onChange(e => this._onChange.fire(e))); + this._register(this.localExtensions.onChange(e => this._onChange.fire(e ? e.extension : undefined))); + this._register(Event.filter(this.localExtensions.onChange, e => !!e && e.operation === InstallOperation.Install)(e => this.onDidInstallExtension(e!.extension))); } - if (this.extensionManagementServerService.remoteExtensionManagementServer) { + if (extensionManagementServerService.remoteExtensionManagementServer) { this.remoteExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.remoteExtensionManagementServer, ext => this.getExtensionState(ext))); - this._register(this.remoteExtensions.onChange(e => this._onChange.fire(e))); + this._register(this.remoteExtensions.onChange(e => this._onChange.fire(e ? e.extension : undefined))); + this._register(Event.filter(this.remoteExtensions.onChange, e => !!e && e.operation === InstallOperation.Install)(e => this.onDidInstallExtension(e!.extension))); } this.syncDelayer = new ThrottledDelayer(ExtensionsWorkbenchService.SyncPeriod); @@ -784,7 +787,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension if (extension instanceof URI) { return this.installWithProgress(async () => { const { identifier } = await this.extensionService.install(extension); - this.checkAndEnableDisabledDependencies(identifier); return this.local.filter(local => areSameExtensions(local.identifier, identifier))[0]; }); } @@ -801,7 +803,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension return this.installWithProgress(async () => { await this.installFromGallery(extension, gallery); - this.checkAndEnableDisabledDependencies(gallery.identifier); return this.local.filter(local => areSameExtensions(local.identifier, gallery.identifier))[0]; }, gallery.displayName); } @@ -887,15 +888,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension } } - private checkAndEnableDisabledDependencies(extensionIdentifier: IExtensionIdentifier): Promise { - const extension = this.local.filter(e => (e.local || e.gallery) && areSameExtensions(extensionIdentifier, e.identifier))[0]; - if (extension) { - const disabledDepencies = this.getExtensionsRecursively([extension], this.local, EnablementState.EnabledGlobally, { dependencies: true, pack: false }); - if (disabledDepencies.length) { - return this.setEnablement(disabledDepencies, EnablementState.EnabledGlobally); - } - } - return Promise.resolve(); + private onDidInstallExtension(extension: IExtension): void { + this.setEnablement(extension, EnablementState.EnabledGlobally); } private promptAndSetEnablement(extensions: IExtension[], enablementState: EnablementState): Promise { @@ -1048,7 +1042,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension this.notificationService.error(err); } - handleURL(uri: URI): Promise { + handleURL(uri: URI, options?: IOpenURLOptions): Promise { if (!/^extension/.test(uri.path)) { return Promise.resolve(false); } diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css b/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css index 5fe20b2b03a..b5f3dd73b7c 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css @@ -46,7 +46,7 @@ justify-content: center; } -.extension-editor > .header > .icon-container .extension-remote-badge .octicon { +.extension-editor > .header > .icon-container .extension-remote-badge .codicon { font-size: 28px; } @@ -54,6 +54,7 @@ padding-left: 20px; overflow: hidden; user-select: text; + -webkit-user-select: text; } .extension-editor > .header > .details > .title { @@ -77,6 +78,7 @@ padding: 0px 4px; border-radius: 4px; user-select: text; + -webkit-user-select: text; white-space: nowrap; } @@ -98,6 +100,7 @@ padding: 0px 4px; border-radius: 4px; user-select: none; + -webkit-user-select: none; } .extension-editor > .header > .details > .subtitle { @@ -219,6 +222,7 @@ position: relative; overflow: hidden; user-select: text; + -webkit-user-select: text; } .extension-editor > .body > .content.loading { diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensions-activity-bar.svg b/src/vs/workbench/contrib/extensions/browser/media/extensions-activity-bar.svg deleted file mode 100644 index 93e4b554dab..00000000000 --- a/src/vs/workbench/contrib/extensions/browser/media/extensions-activity-bar.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensions.css b/src/vs/workbench/contrib/extensions/browser/media/extensions.css deleted file mode 100644 index ad1858f6f05..00000000000 --- a/src/vs/workbench/contrib/extensions/browser/media/extensions.css +++ /dev/null @@ -1,8 +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 .activitybar > .content .monaco-action-bar .action-label.extensions { - -webkit-mask: url('extensions-activity-bar.svg') no-repeat 50% 50%; -} diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css index 2a7cd6a497e..6adb8df7fcc 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css @@ -8,9 +8,9 @@ } .extensions-viewlet > .header { - height: 38px; + height: 41px; box-sizing: border-box; - padding: 5px 9px 5px 16px; + padding: 5px 12px 6px 16px; } .extensions-viewlet > .header > .search-box { @@ -21,6 +21,7 @@ padding: 4px; border: 1px solid transparent; -webkit-appearance: textfield; + -moz-appearance: textfield; } .extensions-viewlet > .extensions { @@ -31,7 +32,7 @@ margin-right: 4px; } -.extensions-viewlet > .extensions .extension-view-header .monaco-action-bar .action-item > .action-label.icon.octicon { +.extensions-viewlet > .extensions .extension-view-header .monaco-action-bar .action-item > .action-label.icon.codicon { vertical-align: middle; line-height: 22px; } @@ -47,13 +48,17 @@ } .extensions-viewlet > .extensions .panel-header { - padding-right: 6px; + padding-right: 12px; } .extensions-viewlet > .extensions .panel-header > .title { flex: 1; } +.extensions-viewlet > .extensions .panel-header > .actions.show { + flex: inherit; +} + .extensions-viewlet > .extensions .message-container { padding: 5px 9px 5px 16px; cursor: default; @@ -80,10 +85,11 @@ box-sizing: border-box; } -.extensions-viewlet > .extensions .monaco-list-row > .bookmark > .recommendation > .octicon { +.extensions-viewlet > .extensions .monaco-list-row > .bookmark > .recommendation > .codicon { position: absolute; top: 1px; left: 1px; + color: inherit; font-size: 90%; } @@ -142,7 +148,7 @@ justify-content: center; } -.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header .extension-remote-badge > .octicon { +.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header .extension-remote-badge > .codicon { font-size: 12px; } @@ -185,6 +191,7 @@ font-size: 80%; padding-left: 6px; min-width: fit-content; + min-width: -moz-fit-content; } .extensions-viewlet:not(.narrow) > .extensions .extension > .details > .header-container > .header > .version { @@ -196,7 +203,7 @@ margin: 0 6px; } -.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count > .octicon { +.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count > .codicon { font-size: 120%; margin-right: 2px; } diff --git a/src/vs/workbench/contrib/extensions/browser/media/language-icon.svg b/src/vs/workbench/contrib/extensions/browser/media/language-icon.svg old mode 100755 new mode 100644 diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts index 6a2048ac72c..97d9f9f5839 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts @@ -9,7 +9,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IElectronService } from 'vs/platform/electron/node/electron'; @@ -81,7 +81,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio if (visible) { const indicator: IStatusbarEntry = { - text: nls.localize('profilingExtensionHost', "$(sync~spin) Profiling Extension Host"), + text: '$(sync~spin) ' + nls.localize('profilingExtensionHost', "Profiling Extension Host"), tooltip: nls.localize('selectAndStartDebug', "Click to stop profiling."), command: 'workbench.action.extensionHostProfilder.stop' }; @@ -89,7 +89,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio const timeStarted = Date.now(); const handle = setInterval(() => { if (this.profilingStatusBarIndicator) { - this.profilingStatusBarIndicator.update({ ...indicator, text: nls.localize('profilingExtensionHostTime', "$(sync~spin) Profiling Extension Host ({0} sec)", Math.round((new Date().getTime() - timeStarted) / 1000)), }); + this.profilingStatusBarIndicator.update({ ...indicator, text: '$(sync~spin) ' + nls.localize('profilingExtensionHostTime', "Profiling Extension Host ({0} sec)", Math.round((new Date().getTime() - timeStarted) / 1000)), }); } }, 1000); this.profilingStatusBarIndicatorLabelUpdater.value = toDisposable(() => clearInterval(handle)); @@ -107,12 +107,12 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio } } - public startProfiling(): Promise | null { + public async startProfiling(): Promise { if (this._state !== ProfileSessionState.None) { return null; } - const inspectPort = this._extensionService.getInspectPort(); + const inspectPort = await this._extensionService.getInspectPort(false); if (!inspectPort) { return this._dialogService.confirm({ type: 'info', diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index b4185a6614f..871122fd967 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -14,7 +14,7 @@ import { Schemas } from 'vs/base/common/network'; export class OpenExtensionsFolderAction extends Action { static readonly ID = 'workbench.extensions.action.openExtensionsFolder'; - static LABEL = localize('openExtensionsFolder', "Open Extensions Folder"); + static readonly LABEL = localize('openExtensionsFolder', "Open Extensions Folder"); constructor( id: string, diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts index 56fe69484cd..c5b6f8b87a1 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts @@ -43,7 +43,7 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont private async _onDidChangeResponsiveChange(event: IResponsiveStateChangeEvent): Promise { - const port = this._extensionService.getInspectPort(); + const port = await this._extensionService.getInspectPort(true); if (!port) { return; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts index a573113e293..fd2aded4b93 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts @@ -134,7 +134,7 @@ class ReportExtensionSlowAction extends Action { // build issue const title = encodeURIComponent('Extension causes high cpu load'); const osVersion = `${os.type()} ${os.arch()} ${os.release()}`; - const message = `:warning: Make sure to **attach** this file from your *home*-directory:\n:warning:\`${path}\`\n\nFind more details here: https://github.com/Microsoft/vscode/wiki/Explain:-extension-causes-high-cpu-load`; + const message = `:warning: Make sure to **attach** this file from your *home*-directory:\n:warning:\`${path}\`\n\nFind more details here: https://github.com/microsoft/vscode/wiki/Explain-extension-causes-high-cpu-load`; const body = encodeURIComponent(`- Issue Type: \`Performance\` - Extension Name: \`${this.extension.name}\` - Extension Version: \`${this.extension.version}\` diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index 7039bdfa6db..091b159cad2 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -38,7 +38,7 @@ import { randomPort } from 'vs/base/node/ports'; import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ILabelService } from 'vs/platform/label/common/label'; -import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; +import { renderCodicons } from 'vs/base/browser/ui/codiconLabel/codiconLabel'; import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { SlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions'; @@ -364,31 +364,31 @@ export class RuntimeExtensionsEditor extends BaseEditor { if (this._extensionHostProfileService.getUnresponsiveProfile(element.description.identifier)) { const el = $('span'); - el.innerHTML = renderOcticons(` $(alert) Unresponsive`); + el.innerHTML = renderCodicons(` $(alert) Unresponsive`); el.title = nls.localize('unresponsive.title', "Extension has caused the extension host to freeze."); data.msgContainer.appendChild(el); } if (isNonEmptyArray(element.status.runtimeErrors)) { const el = $('span'); - el.innerHTML = renderOcticons(`$(bug) ${nls.localize('errors', "{0} uncaught errors", element.status.runtimeErrors.length)}`); + el.innerHTML = renderCodicons(`$(bug) ${nls.localize('errors', "{0} uncaught errors", element.status.runtimeErrors.length)}`); data.msgContainer.appendChild(el); } if (element.status.messages && element.status.messages.length > 0) { const el = $('span'); - el.innerHTML = renderOcticons(`$(alert) ${element.status.messages[0].message}`); + el.innerHTML = renderCodicons(`$(alert) ${element.status.messages[0].message}`); data.msgContainer.appendChild(el); } if (element.description.extensionLocation.scheme !== 'file') { const el = $('span'); - el.innerHTML = renderOcticons(`$(remote) ${element.description.extensionLocation.authority}`); + el.innerHTML = renderCodicons(`$(remote) ${element.description.extensionLocation.authority}`); data.msgContainer.appendChild(el); const hostLabel = this._labelService.getHostLabel(REMOTE_HOST_SCHEME, this._environmentService.configuration.remoteAuthority); if (hostLabel) { - el.innerHTML = renderOcticons(`$(remote) ${hostLabel}`); + el.innerHTML = renderCodicons(`$(remote) ${hostLabel}`); } } @@ -405,7 +405,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { } }; - this._list = this._instantiationService.createInstance(WorkbenchList, + this._list = this._instantiationService.createInstance>(WorkbenchList, 'RuntimeExtensions', parent, delegate, [renderer], { multipleSelectionSupport: false, @@ -459,7 +459,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { export class ShowRuntimeExtensionsAction extends Action { static readonly ID = 'workbench.action.showRuntimeExtensions'; - static LABEL = nls.localize('showRuntimeExtensions', "Show Running Extensions"); + static readonly LABEL = nls.localize('showRuntimeExtensions', "Show Running Extensions"); constructor( id: string, label: string, @@ -477,7 +477,7 @@ export class ShowRuntimeExtensionsAction extends Action { export class ReportExtensionIssueAction extends Action { private static readonly _id = 'workbench.extensions.action.reportExtensionIssue'; - private static _label = nls.localize('reportExtensionIssue', "Report Issue"); + private static readonly _label = nls.localize('reportExtensionIssue', "Report Issue"); private readonly _url: string; @@ -533,8 +533,8 @@ export class ReportExtensionIssueAction extends Action { export class DebugExtensionHostAction extends Action { static readonly ID = 'workbench.extensions.action.debugExtensionHost'; - static LABEL = nls.localize('debugExtensionHost', "Start Debugging Extension Host"); - static CSS_CLASS = 'debug-extension-host'; + static readonly LABEL = nls.localize('debugExtensionHost', "Start Debugging Extension Host"); + static readonly CSS_CLASS = 'debug-extension-host'; constructor( @IDebugService private readonly _debugService: IDebugService, @@ -547,7 +547,7 @@ export class DebugExtensionHostAction extends Action { async run(): Promise { - const inspectPort = this._extensionService.getInspectPort(); + const inspectPort = await this._extensionService.getInspectPort(false); if (!inspectPort) { const res = await this._dialogService.confirm({ type: 'info', @@ -557,8 +557,10 @@ export class DebugExtensionHostAction extends Action { secondaryButton: nls.localize('cancel', "Cancel") }); if (res.confirmed) { - this._electronService.relaunch({ addArgs: [`--inspect-extensions=${randomPort()}`] }); + await this._electronService.relaunch({ addArgs: [`--inspect-extensions=${randomPort()}`] }); } + + return; } return this._debugService.startDebugging(undefined, { @@ -572,7 +574,7 @@ export class DebugExtensionHostAction extends Action { export class StartExtensionHostProfileAction extends Action { static readonly ID = 'workbench.extensions.action.extensionHostProfile'; - static LABEL = nls.localize('extensionHostProfileStart', "Start Extension Host Profile"); + static readonly LABEL = nls.localize('extensionHostProfileStart', "Start Extension Host Profile"); constructor( id: string = StartExtensionHostProfileAction.ID, label: string = StartExtensionHostProfileAction.LABEL, @@ -589,7 +591,7 @@ export class StartExtensionHostProfileAction extends Action { export class StopExtensionHostProfileAction extends Action { static readonly ID = 'workbench.extensions.action.stopExtensionHostProfile'; - static LABEL = nls.localize('stopExtensionHostProfileStart', "Stop Extension Host Profile"); + static readonly LABEL = nls.localize('stopExtensionHostProfileStart', "Stop Extension Host Profile"); constructor( id: string = StartExtensionHostProfileAction.ID, label: string = StartExtensionHostProfileAction.LABEL, @@ -606,7 +608,7 @@ export class StopExtensionHostProfileAction extends Action { export class SaveExtensionHostProfileAction extends Action { - static LABEL = nls.localize('saveExtensionHostProfile', "Save Extension Host Profile"); + static readonly LABEL = nls.localize('saveExtensionHostProfile', "Save Extension Host Profile"); static readonly ID = 'workbench.extensions.action.saveExtensionHostProfile'; constructor( diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 95a0356950b..2f807353e8b 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -27,10 +27,9 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { TestContextService, TestWindowService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices'; +import { TestContextService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { URLService } from 'vs/platform/url/node/urlService'; import { URI } from 'vs/base/common/uri'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -67,7 +66,6 @@ suite('ExtensionsActions Test', () => { instantiationService = new TestInstantiationService(); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(ILogService, NullLogService); - instantiationService.stub(IWindowService, TestWindowService); instantiationService.stub(IWorkspaceContextService, new TestContextService()); instantiationService.stub(IConfigurationService, new TestConfigurationService()); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts index 6114055f8ec..6a381ae5127 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts @@ -305,7 +305,6 @@ suite('ExtensionsTipsService Test', () => { function testNoPromptOrRecommendationsForValidRecommendations(recommendations: string[]) { return setUpFolderWorkspace('myFolder', mockTestData.validRecommendedExtensions).then(() => { testObject = instantiationService.createInstance(ExtensionTipsService); - assert.equal(!testObject.loadWorkspaceConfigPromise, true); assert.ok(!prompted); return testObject.getWorkspaceRecommendations().then(() => { diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index d7b65b2c943..df34fc18de0 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -27,10 +27,9 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { TestContextService, TestWindowService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices'; +import { TestContextService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { URLService } from 'vs/platform/url/node/urlService'; import { URI } from 'vs/base/common/uri'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -79,7 +78,6 @@ suite('ExtensionsListView Tests', () => { instantiationService = new TestInstantiationService(); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(ILogService, NullLogService); - instantiationService.stub(IWindowService, TestWindowService); instantiationService.stub(IWorkspaceContextService, new TestContextService()); instantiationService.stub(IConfigurationService, new TestConfigurationService()); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 1edf1c907d0..d3568cdb3af 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -27,10 +27,9 @@ import { IPager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { TestContextService, TestWindowService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices'; +import { TestContextService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { ProgressService } from 'vs/workbench/services/progress/browser/progressService'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -61,7 +60,6 @@ suite('ExtensionsWorkbenchServiceTest', () => { instantiationService = new TestInstantiationService(); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(ILogService, NullLogService); - instantiationService.stub(IWindowService, TestWindowService); instantiationService.stub(IProgressService, ProgressService); instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); @@ -944,6 +942,46 @@ suite('ExtensionsWorkbenchServiceTest', () => { }); }); + test('test installing an extension re-eanbles it when disabled globally', async () => { + testObject = await aWorkbenchService(); + const local = aLocalExtension('pub.a'); + await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); + didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const actual = await testObject.queryLocal(); + assert.equal(actual[0].enablementState, EnablementState.EnabledGlobally); + }); + + test('test updating an extension does not re-eanbles it when disabled globally', async () => { + testObject = await aWorkbenchService(); + const local = aLocalExtension('pub.a'); + await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally); + didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const actual = await testObject.queryLocal(); + assert.equal(actual[0].enablementState, EnablementState.DisabledGlobally); + }); + + test('test installing an extension re-eanbles it when workspace disabled', async () => { + testObject = await aWorkbenchService(); + const local = aLocalExtension('pub.a'); + await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace); + didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const actual = await testObject.queryLocal(); + assert.equal(actual[0].enablementState, EnablementState.EnabledGlobally); + }); + + test('test updating an extension does not re-eanbles it when workspace disabled', async () => { + testObject = await aWorkbenchService(); + const local = aLocalExtension('pub.a'); + await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledWorkspace); + didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const actual = await testObject.queryLocal(); + assert.equal(actual[0].enablementState, EnablementState.DisabledWorkspace); + }); + async function aWorkbenchService(): Promise { const workbenchService: ExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); await workbenchService.queryLocal(); diff --git a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts index 495ec6e264a..e4a7454fb10 100644 --- a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts @@ -130,7 +130,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: OPEN_NATIVE_CONSOLE_COMMAND_ID, - title: { value: nls.localize('globalConsoleAction', "Open New Terminal"), original: 'Open New Terminal' } + title: { value: nls.localize('globalConsoleAction', "Open New External Terminal"), original: 'Open New External Terminal' } } }); diff --git a/src/vs/workbench/contrib/feedback/browser/feedback.ts b/src/vs/workbench/contrib/feedback/browser/feedback.ts index f54278a96da..ae6f9bcbbd7 100644 --- a/src/vs/workbench/contrib/feedback/browser/feedback.ts +++ b/src/vs/workbench/contrib/feedback/browser/feedback.ts @@ -18,7 +18,7 @@ import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { Button } from 'vs/base/browser/ui/button/button'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; -import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarService } from 'vs/workbench/services/statusbar/common/statusbar'; import { IProductService } from 'vs/platform/product/common/productService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -142,7 +142,7 @@ export class FeedbackDropdown extends Dropdown { })); disposables.add(dom.addDisposableListener(closeBtn, dom.EventType.MOUSE_OUT, () => { - closeBtn.style.backgroundColor = null; + closeBtn.style.backgroundColor = ''; })); this.invoke(closeBtn, disposables, () => this.hide()); @@ -276,17 +276,17 @@ export class FeedbackDropdown extends Dropdown { disposables.add(attachStylerCallback(this.themeService, { widgetShadow, editorWidgetBackground, editorWidgetForeground, inputBackground, inputForeground, inputBorder, editorBackground, contrastBorder }, colors => { if (this.feedbackForm) { - this.feedbackForm.style.backgroundColor = colors.editorWidgetBackground ? colors.editorWidgetBackground.toString() : null; + this.feedbackForm.style.backgroundColor = colors.editorWidgetBackground ? colors.editorWidgetBackground.toString() : ''; this.feedbackForm.style.color = colors.editorWidgetForeground ? colors.editorWidgetForeground.toString() : null; - this.feedbackForm.style.boxShadow = colors.widgetShadow ? `0 0 8px ${colors.widgetShadow}` : null; + this.feedbackForm.style.boxShadow = colors.widgetShadow ? `0 0 8px ${colors.widgetShadow}` : ''; } if (this.feedbackDescriptionInput) { - this.feedbackDescriptionInput.style.backgroundColor = colors.inputBackground ? colors.inputBackground.toString() : null; + this.feedbackDescriptionInput.style.backgroundColor = colors.inputBackground ? colors.inputBackground.toString() : ''; this.feedbackDescriptionInput.style.color = colors.inputForeground ? colors.inputForeground.toString() : null; this.feedbackDescriptionInput.style.border = `1px solid ${colors.inputBorder || 'transparent'}`; } - contactUsContainer.style.backgroundColor = colors.editorBackground ? colors.editorBackground.toString() : null; + contactUsContainer.style.backgroundColor = colors.editorBackground ? colors.editorBackground.toString() : ''; contactUsContainer.style.border = `1px solid ${colors.contrastBorder || 'transparent'}`; })); diff --git a/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts b/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts index 10047c28819..e8421c16dae 100644 --- a/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts +++ b/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts @@ -9,7 +9,7 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProductService } from 'vs/platform/product/common/productService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IStatusbarService, StatusbarAlignment, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarService, StatusbarAlignment, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/common/statusbar'; import { localize } from 'vs/nls'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -71,7 +71,11 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben if (!this.dropdown) { const statusContainr = document.getElementById('status.feedback'); if (statusContainr) { - this.dropdown = this._register(this.instantiationService.createInstance(FeedbackDropdown, statusContainr.getElementsByClassName('octicon').item(0), { + const icon = statusContainr.getElementsByClassName('codicon').item(0) as HTMLElement | null; + if (!icon) { + throw new Error('Could not find icon'); + } + this.dropdown = this._register(this.instantiationService.createInstance(FeedbackDropdown, icon, { contextViewProvider: this.contextViewService, feedbackService: this.instantiationService.createInstance(TwitterFeedbackService), onFeedbackVisibilityChange: visible => this.entry!.update(this.getStatusEntry(visible)) diff --git a/src/vs/workbench/contrib/feedback/browser/media/twitter.svg b/src/vs/workbench/contrib/feedback/browser/media/twitter.svg old mode 100755 new mode 100644 diff --git a/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts index 8a9bb08108a..e3229c3f613 100644 --- a/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts @@ -13,8 +13,6 @@ import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; /** @@ -30,9 +28,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { @IOpenerService private readonly openerService: IOpenerService, @IEditorService private readonly editorService: IEditorService, @IStorageService storageService: IStorageService, - @IFileService fileService: IFileService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IInstantiationService instantiationService: IInstantiationService, ) { super( BinaryFileEditor.ID, @@ -42,10 +38,8 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { }, telemetryService, themeService, - fileService, environmentService, storageService, - instantiationService, ); } diff --git a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts index eac306be109..ddc030e106f 100644 --- a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts @@ -20,7 +20,7 @@ import { ResourceMap } from 'vs/base/common/map'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -44,7 +44,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut @IEnvironmentService private readonly environmentService: IEnvironmentService, @IConfigurationService private readonly configurationService: IConfigurationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IWindowService private readonly windowService: IWindowService + @IHostService private readonly hostService: IHostService ) { super(); @@ -65,7 +65,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut this._register(this.editorService.onDidVisibleEditorsChange(() => this.handleOutOfWorkspaceWatchers())); // Update visible editors when focus is gained - this._register(this.windowService.onDidChangeFocus(e => this.onWindowFocusChange(e))); + this._register(this.hostService.onDidChangeFocus(e => this.onWindowFocusChange(e))); // Lifecycle this.lifecycleService.onShutdown(this.dispose, this); @@ -75,7 +75,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut } private onConfigurationUpdated(configuration: IWorkbenchEditorConfiguration): void { - if (configuration.workbench && configuration.workbench.editor && typeof configuration.workbench.editor.closeOnFileDelete === 'boolean') { + if (typeof configuration.workbench?.editor?.closeOnFileDelete === 'boolean') { this.closeOnFileDelete = configuration.workbench.editor.closeOnFileDelete; } else { this.closeOnFileDelete = false; // default @@ -265,7 +265,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut const editors = this.editorService.visibleControls; for (const editor of editors) { - if (editor && editor.input && editor.group === group) { + if (editor?.input && editor.group === group) { const editorResource = editor.input.getResource(); if (editorResource && resource.toString() === editorResource.toString()) { const control = editor.getControl(); @@ -307,7 +307,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut // to have a size of 2 (1 running load and 1 queued load). const queue = this.modelLoadQueue.queueFor(model.getResource()); if (queue.size <= 1) { - queue.queue(() => model.load().then(undefined, onUnexpectedError)); + queue.queue(() => model.load().then(undefined, onUnexpectedError)); } } @@ -320,7 +320,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut let isBinaryEditor = false; if (editor instanceof SideBySideEditor) { const masterEditor = editor.getMasterEditor(); - isBinaryEditor = !!masterEditor && masterEditor.getId() === BINARY_FILE_EDITOR_ID; + isBinaryEditor = masterEditor?.getId() === BINARY_FILE_EDITOR_ID; } else { isBinaryEditor = editor.getId() === BINARY_FILE_EDITOR_ID; } diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index 7174fe0929b..92253252003 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { isFunction } from 'vs/base/common/types'; +import { isFunction, assertIsDefined } from 'vs/base/common/types'; import { isValidBasename } from 'vs/base/common/extpath'; import { basename } from 'vs/base/common/resources'; import { Action } from 'vs/base/common/actions'; @@ -24,7 +24,7 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ScrollType } from 'vs/editor/common/editorCommon'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -55,10 +55,10 @@ export class TextFileEditor extends BaseTextEditor { @IThemeService themeService: IThemeService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, - @IWindowService windowService: IWindowService, + @IHostService hostService: IHostService, @IExplorerService private readonly explorerService: IExplorerService ) { - super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService); + super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); this.updateRestoreViewStateConfiguration(); @@ -68,7 +68,7 @@ export class TextFileEditor extends BaseTextEditor { private onFilesChanged(e: FileChangesEvent): void { const deleted = e.getDeleted(); - if (deleted && deleted.length) { + if (deleted?.length) { this.clearTextEditorViewState(deleted.map(d => d.resource)); } } @@ -118,7 +118,8 @@ export class TextFileEditor extends BaseTextEditor { setOptions(options: EditorOptions | undefined): void { const textOptions = options as TextEditorOptions; if (textOptions && isFunction(textOptions.apply)) { - textOptions.apply(this.getControl(), ScrollType.Smooth); + const textEditor = assertIsDefined(this.getControl()); + textOptions.apply(textEditor, ScrollType.Smooth); } } @@ -147,7 +148,7 @@ export class TextFileEditor extends BaseTextEditor { const textFileModel = resolvedModel; // Editor - const textEditor = this.getControl(); + const textEditor = assertIsDefined(this.getControl()); textEditor.setModel(textFileModel.textEditorModel); // Always restore View State if any associated @@ -241,7 +242,7 @@ export class TextFileEditor extends BaseTextEditor { protected getAriaLabel(): string { const input = this.input; - const inputName = input && input.getName(); + const inputName = input?.getName(); let ariaLabel: string; if (inputName) { @@ -259,7 +260,10 @@ export class TextFileEditor extends BaseTextEditor { this.doSaveOrClearTextEditorViewState(this.input); // Clear Model - this.getControl().setModel(null); + const textEditor = this.getControl(); + if (textEditor) { + textEditor.setModel(null); + } // Pass to super super.clearInput(); diff --git a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts index b8a1ac6b73e..85cecc75dfa 100644 --- a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts @@ -241,7 +241,7 @@ export class ExplorerViewlet extends ViewContainerViewlet { focus(): void { const explorerView = this.getView(ExplorerView.ID); - if (explorerView && explorerView.isExpanded()) { + if (explorerView?.isExpanded()) { explorerView.focus(); } else { super.focus(); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 47c9912e899..3460f9fb6bc 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ToggleAutoSaveAction, GlobalNewUntitledFileAction, ShowOpenedFileInNewWindow, FocusFilesExplorer, GlobalCompareResourcesAction, SaveAllAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, openFilePreserveFocusHandler } from 'vs/workbench/contrib/files/browser/fileActions'; +import { ToggleAutoSaveAction, GlobalNewUntitledFileAction, FocusFilesExplorer, GlobalCompareResourcesAction, SaveAllAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, openFilePreserveFocusHandler, DOWNLOAD_LABEL } from 'vs/workbench/contrib/files/browser/fileActions'; import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTION_CONTEXT } from 'vs/workbench/contrib/files/browser/saveErrorHandler'; import { SyncActionDescriptor, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; @@ -23,7 +23,7 @@ import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; -import { SupportsWorkspacesContext, IsWebContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; +import { WorkspaceFolderCountContext, IsWebContext } from 'vs/workbench/browser/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { OpenFileFolderAction, OpenFileAction, OpenFolderAction, OpenWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions'; import { ActiveEditorIsSaveableContext } from 'vs/workbench/common/editor'; @@ -41,7 +41,6 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ShowActiveFileInExplor registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL), 'File: Collapse Folders in Explorer', category.value); registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL), 'File: Refresh Explorer', category.value); registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewUntitledFileAction, GlobalNewUntitledFileAction.ID, GlobalNewUntitledFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_N }), 'File: New Untitled File', category.value); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'File: Open Active File in New Window', category.value); registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithClipboardAction, CompareWithClipboardAction.ID, CompareWithClipboardAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_C) }), 'File: Compare Active File with Clipboard', category.value); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleAutoSaveAction, ToggleAutoSaveAction.ID, ToggleAutoSaveAction.LABEL), 'File: Toggle Auto Save', category.value); @@ -219,7 +218,6 @@ export function appendToCommandPalette(id: string, title: ILocalizedString, cate }); } -const downloadLabel = nls.localize('download', "Download"); appendToCommandPalette(COPY_PATH_COMMAND_ID, { value: nls.localize('copyPathOfActive', "Copy Path of Active File"), original: 'Copy Path of Active File' }, category); appendToCommandPalette(COPY_RELATIVE_PATH_COMMAND_ID, { value: nls.localize('copyRelativePathOfActive', "Copy Relative Path of Active File"), original: 'Copy Relative Path of Active File' }, category); appendToCommandPalette(SAVE_FILE_COMMAND_ID, { value: SAVE_FILE_LABEL, original: 'Save' }, category); @@ -232,7 +230,7 @@ appendToCommandPalette(SAVE_FILE_AS_COMMAND_ID, { value: SAVE_FILE_AS_LABEL, ori appendToCommandPalette(CLOSE_EDITOR_COMMAND_ID, { value: nls.localize('closeEditor', "Close Editor"), original: 'Close Editor' }, { value: nls.localize('view', "View"), original: 'View' }); appendToCommandPalette(NEW_FILE_COMMAND_ID, { value: NEW_FILE_LABEL, original: 'New File' }, category, WorkspaceFolderCountContext.notEqualsTo('0')); appendToCommandPalette(NEW_FOLDER_COMMAND_ID, { value: NEW_FOLDER_LABEL, original: 'New Folder' }, category, WorkspaceFolderCountContext.notEqualsTo('0')); -appendToCommandPalette(DOWNLOAD_COMMAND_ID, { value: downloadLabel, original: 'Download' }, category, ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.notEqualsTo(Schemas.file))); +appendToCommandPalette(DOWNLOAD_COMMAND_ID, { value: DOWNLOAD_LABEL, original: 'Download' }, category, ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file))); // Menu registration - open editors @@ -466,15 +464,15 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { when: ExplorerFolderContext }); -MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { +MenuRegistry.appendMenuItem(MenuId.ExplorerContext, ({ group: '5_cutcopypaste', order: 30, command: { id: DOWNLOAD_COMMAND_ID, - title: downloadLabel, + title: DOWNLOAD_LABEL, }, - when: ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.notEqualsTo(Schemas.file)) -}); + when: ContextKeyExpr.or(ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), IsWebContext.toNegated()), ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), ExplorerFolderContext.toNegated())) +})); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { group: '6_copypath', @@ -497,7 +495,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { id: ADD_ROOT_FOLDER_COMMAND_ID, title: ADD_ROOT_FOLDER_LABEL }, - when: ContextKeyExpr.and(ExplorerRootContext, SupportsWorkspacesContext) + when: ContextKeyExpr.and(ExplorerRootContext) }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { @@ -507,7 +505,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { id: REMOVE_ROOT_FOLDER_COMMAND_ID, title: REMOVE_ROOT_FOLDER_LABEL }, - when: ContextKeyExpr.and(ExplorerRootContext, ExplorerFolderContext, SupportsWorkspacesContext) + when: ContextKeyExpr.and(ExplorerRootContext, ExplorerFolderContext) }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index 1a0057d0e42..cc1be00aadd 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/fileactions'; import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; -import { isWindows } from 'vs/base/common/platform'; +import { isWindows, isWeb } from 'vs/base/common/platform'; import * as extpath from 'vs/base/common/extpath'; import { extname, basename } from 'vs/base/common/path'; import * as resources from 'vs/base/common/resources'; @@ -36,15 +36,17 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c import { IListService, ListWidget } from 'vs/platform/list/browser/listService'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Schemas } from 'vs/base/common/network'; -import { IDialogService, IConfirmationResult, getConfirmMessage } from 'vs/platform/dialogs/common/dialogs'; +import { IDialogService, IConfirmationResult, getConfirmMessage, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { Constants } from 'vs/editor/common/core/uint'; +import { Constants } from 'vs/base/common/uint'; import { CLOSE_EDITORS_AND_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; import { coalesce } from 'vs/base/common/arrays'; import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { onUnexpectedError, getErrorMessage } from 'vs/base/common/errors'; +import { asDomUri, triggerDownload } from 'vs/base/browser/dom'; +import { mnemonicButtonLabel } from 'vs/base/common/labels'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -62,6 +64,8 @@ export const PASTE_FILE_LABEL = nls.localize('pasteFile', "Paste"); export const FileCopiedContext = new RawContextKey('fileCopied', false); +export const DOWNLOAD_LABEL = nls.localize('download', "Download"); + const CONFIRM_DELETE_SETTING_KEY = 'explorer.confirmDelete'; function onError(notificationService: INotificationService, error: any): void { @@ -125,8 +129,8 @@ export class NewFolderAction extends Action { /* Create new file from anywhere: Open untitled */ export class GlobalNewUntitledFileAction extends Action { - public static readonly ID = 'workbench.action.files.newUntitledFile'; - public static readonly LABEL = nls.localize('newUntitledFile', "New Untitled File"); + static readonly ID = 'workbench.action.files.newUntitledFile'; + static readonly LABEL = nls.localize('newUntitledFile', "New Untitled File"); constructor( id: string, @@ -136,12 +140,12 @@ export class GlobalNewUntitledFileAction extends Action { super(id, label); } - public run(): Promise { + run(): Promise { return this.editorService.openEditor({ options: { pinned: true } }); // untitled are always pinned } } -function deleteFiles(textFileService: ITextFileService, dialogService: IDialogService, configurationService: IConfigurationService, fileService: IFileService, elements: ExplorerItem[], useTrash: boolean, skipConfirm = false): Promise { +async function deleteFiles(textFileService: ITextFileService, dialogService: IDialogService, configurationService: IConfigurationService, fileService: IFileService, elements: ExplorerItem[], useTrash: boolean, skipConfirm = false): Promise { let primaryButton: string; if (useTrash) { primaryButton = isWindows ? nls.localize('deleteButtonLabelRecycleBin', "&&Move to Recycle Bin") : nls.localize({ key: 'deleteButtonLabelTrash', comment: ['&& denotes a mnemonic'] }, "&&Move to Trash"); @@ -152,7 +156,7 @@ function deleteFiles(textFileService: ITextFileService, dialogService: IDialogSe const distinctElements = resources.distinctParents(elements, e => e.resource); // Handle dirty - let confirmDirtyPromise: Promise = Promise.resolve(true); + let confirmed = true; const dirty = textFileService.getDirty().filter(d => distinctElements.some(e => resources.isEqualOrParent(d, e.resource))); if (dirty.length) { let message: string; @@ -168,114 +172,112 @@ function deleteFiles(textFileService: ITextFileService, dialogService: IDialogSe message = nls.localize('dirtyMessageFileDelete', "You are deleting a file with unsaved changes. Do you want to continue?"); } - confirmDirtyPromise = dialogService.confirm({ + const response = await dialogService.confirm({ message, type: 'warning', detail: nls.localize('dirtyWarning', "Your changes will be lost if you don't save them."), primaryButton - }).then(res => { - if (!res.confirmed) { - return false; - } - - skipConfirm = true; // since we already asked for confirmation - return textFileService.revertAll(dirty).then(() => true); }); + + if (!response.confirmed) { + confirmed = false; + } else { + skipConfirm = true; + await textFileService.revertAll(dirty); + } } // Check if file is dirty in editor and save it to avoid data loss - return confirmDirtyPromise.then(confirmed => { - if (!confirmed) { - return undefined; + if (!confirmed) { + return; + } + + let confirmDeletePromise: Promise; + + // Check if we need to ask for confirmation at all + if (skipConfirm || (useTrash && configurationService.getValue(CONFIRM_DELETE_SETTING_KEY) === false)) { + confirmDeletePromise = Promise.resolve({ confirmed: true }); + } + + // Confirm for moving to trash + else if (useTrash) { + const message = getMoveToTrashMessage(distinctElements); + + confirmDeletePromise = dialogService.confirm({ + message, + detail: isWindows ? nls.localize('undoBin', "You can restore from the Recycle Bin.") : nls.localize('undoTrash', "You can restore from the Trash."), + primaryButton, + checkbox: { + label: nls.localize('doNotAskAgain', "Do not ask me again") + }, + type: 'question' + }); + } + + // Confirm for deleting permanently + else { + const message = getDeleteMessage(distinctElements); + confirmDeletePromise = dialogService.confirm({ + message, + detail: nls.localize('irreversible', "This action is irreversible!"), + primaryButton, + type: 'warning' + }); + } + + return confirmDeletePromise.then(confirmation => { + + // Check for confirmation checkbox + let updateConfirmSettingsPromise: Promise = Promise.resolve(undefined); + if (confirmation.confirmed && confirmation.checkboxChecked === true) { + updateConfirmSettingsPromise = configurationService.updateValue(CONFIRM_DELETE_SETTING_KEY, false, ConfigurationTarget.USER); } - let confirmDeletePromise: Promise; + return updateConfirmSettingsPromise.then(() => { - // Check if we need to ask for confirmation at all - if (skipConfirm || (useTrash && configurationService.getValue(CONFIRM_DELETE_SETTING_KEY) === false)) { - confirmDeletePromise = Promise.resolve({ confirmed: true }); - } - - // Confirm for moving to trash - else if (useTrash) { - const message = getMoveToTrashMessage(distinctElements); - - confirmDeletePromise = dialogService.confirm({ - message, - detail: isWindows ? nls.localize('undoBin', "You can restore from the Recycle Bin.") : nls.localize('undoTrash', "You can restore from the Trash."), - primaryButton, - checkbox: { - label: nls.localize('doNotAskAgain', "Do not ask me again") - }, - type: 'question' - }); - } - - // Confirm for deleting permanently - else { - const message = getDeleteMessage(distinctElements); - confirmDeletePromise = dialogService.confirm({ - message, - detail: nls.localize('irreversible', "This action is irreversible!"), - primaryButton, - type: 'warning' - }); - } - - return confirmDeletePromise.then(confirmation => { - - // Check for confirmation checkbox - let updateConfirmSettingsPromise: Promise = Promise.resolve(undefined); - if (confirmation.confirmed && confirmation.checkboxChecked === true) { - updateConfirmSettingsPromise = configurationService.updateValue(CONFIRM_DELETE_SETTING_KEY, false, ConfigurationTarget.USER); + // Check for confirmation + if (!confirmation.confirmed) { + return Promise.resolve(undefined); } - return updateConfirmSettingsPromise.then(() => { + // Call function + const servicePromise = Promise.all(distinctElements.map(e => fileService.del(e.resource, { useTrash: useTrash, recursive: true }))) + .then(undefined, (error: any) => { + // Handle error to delete file(s) from a modal confirmation dialog + let errorMessage: string; + let detailMessage: string | undefined; + let primaryButton: string; + if (useTrash) { + errorMessage = isWindows ? nls.localize('binFailed', "Failed to delete using the Recycle Bin. Do you want to permanently delete instead?") : nls.localize('trashFailed', "Failed to delete using the Trash. Do you want to permanently delete instead?"); + detailMessage = nls.localize('irreversible', "This action is irreversible!"); + primaryButton = nls.localize({ key: 'deletePermanentlyButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Delete Permanently"); + } else { + errorMessage = toErrorMessage(error, false); + primaryButton = nls.localize({ key: 'retryButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Retry"); + } - // Check for confirmation - if (!confirmation.confirmed) { - return Promise.resolve(undefined); - } + return dialogService.confirm({ + message: errorMessage, + detail: detailMessage, + type: 'warning', + primaryButton + }).then(res => { - // Call function - const servicePromise = Promise.all(distinctElements.map(e => fileService.del(e.resource, { useTrash: useTrash, recursive: true }))) - .then(undefined, (error: any) => { - // Handle error to delete file(s) from a modal confirmation dialog - let errorMessage: string; - let detailMessage: string | undefined; - let primaryButton: string; - if (useTrash) { - errorMessage = isWindows ? nls.localize('binFailed', "Failed to delete using the Recycle Bin. Do you want to permanently delete instead?") : nls.localize('trashFailed', "Failed to delete using the Trash. Do you want to permanently delete instead?"); - detailMessage = nls.localize('irreversible', "This action is irreversible!"); - primaryButton = nls.localize({ key: 'deletePermanentlyButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Delete Permanently"); - } else { - errorMessage = toErrorMessage(error, false); - primaryButton = nls.localize({ key: 'retryButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Retry"); - } - - return dialogService.confirm({ - message: errorMessage, - detail: detailMessage, - type: 'warning', - primaryButton - }).then(res => { - - if (res.confirmed) { - if (useTrash) { - useTrash = false; // Delete Permanently - } - - skipConfirm = true; - - return deleteFiles(textFileService, dialogService, configurationService, fileService, elements, useTrash, skipConfirm); + if (res.confirmed) { + if (useTrash) { + useTrash = false; // Delete Permanently } - return Promise.resolve(); - }); - }); + skipConfirm = true; - return servicePromise; - }); + return deleteFiles(textFileService, dialogService, configurationService, fileService, elements, useTrash, skipConfirm); + } + + return Promise.resolve(); + }); + }); + + return servicePromise; }); }); } @@ -440,8 +442,8 @@ export function incrementFileName(name: string, isFolder: boolean, incrementalNa // Global Compare with export class GlobalCompareResourcesAction extends Action { - public static readonly ID = 'workbench.files.action.compareFileWith'; - public static readonly LABEL = nls.localize('globalCompareFile', "Compare Active File With..."); + static readonly ID = 'workbench.files.action.compareFileWith'; + static readonly LABEL = nls.localize('globalCompareFile', "Compare Active File With..."); constructor( id: string, @@ -453,7 +455,7 @@ export class GlobalCompareResourcesAction extends Action { super(id, label); } - public run(): Promise { + async run(): Promise { const activeInput = this.editorService.activeEditor; const activeResource = activeInput ? activeInput.getResource() : undefined; if (activeResource) { @@ -471,7 +473,7 @@ export class GlobalCompareResourcesAction extends Action { override: this.editorService.openEditor({ leftResource: activeResource, rightResource: resource - }).then(() => undefined) + }) }; } @@ -479,20 +481,17 @@ export class GlobalCompareResourcesAction extends Action { }); // Bring up quick open - this.quickOpenService.show('', { autoFocus: { autoFocusSecondEntry: true } }).then(() => { - toDispose.dispose(); // make sure to unbind if quick open is closing - }); + await this.quickOpenService.show('', { autoFocus: { autoFocusSecondEntry: true } }); + toDispose.dispose(); // make sure to unbind if quick open is closing } else { this.notificationService.info(nls.localize('openFileToCompare', "Open a file first to compare it with another file.")); } - - return Promise.resolve(true); } } export class ToggleAutoSaveAction extends Action { - public static readonly ID = 'workbench.action.toggleAutoSave'; - public static readonly LABEL = nls.localize('toggleAutoSave', "Toggle Auto Save"); + static readonly ID = 'workbench.action.toggleAutoSave'; + static readonly LABEL = nls.localize('toggleAutoSave', "Toggle Auto Save"); constructor( id: string, @@ -502,7 +501,7 @@ export class ToggleAutoSaveAction extends Action { super(id, label); } - public run(): Promise { + run(): Promise { const setting = this.configurationService.inspect('files.autoSave'); let userAutoSaveConfig = setting.user; if (types.isUndefinedOrNull(userAutoSaveConfig)) { @@ -562,20 +561,21 @@ export abstract class BaseSaveAllAction extends Action { } } - public run(context?: any): Promise { - return this.doRun(context).then(() => true, error => { + async run(context?: any): Promise { + try { + await this.doRun(context); + } catch (error) { onError(this.notificationService, error); - return false; - }); + } } } export class SaveAllAction extends BaseSaveAllAction { - public static readonly ID = 'workbench.action.files.saveAll'; - public static readonly LABEL = SAVE_ALL_LABEL; + static readonly ID = 'workbench.action.files.saveAll'; + static readonly LABEL = SAVE_ALL_LABEL; - public get class(): string { + get class(): string { return 'explorer-action codicon-save-all'; } @@ -590,10 +590,10 @@ export class SaveAllAction extends BaseSaveAllAction { export class SaveAllInGroupAction extends BaseSaveAllAction { - public static readonly ID = 'workbench.files.action.saveAllInGroup'; - public static readonly LABEL = nls.localize('saveAllInGroup', "Save All in Group"); + static readonly ID = 'workbench.files.action.saveAllInGroup'; + static readonly LABEL = nls.localize('saveAllInGroup', "Save All in Group"); - public get class(): string { + get class(): string { return 'explorer-action codicon-save-all'; } @@ -608,22 +608,22 @@ export class SaveAllInGroupAction extends BaseSaveAllAction { export class CloseGroupAction extends Action { - public static readonly ID = 'workbench.files.action.closeGroup'; - public static readonly LABEL = nls.localize('closeGroup', "Close Group"); + static readonly ID = 'workbench.files.action.closeGroup'; + static readonly LABEL = nls.localize('closeGroup', "Close Group"); constructor(id: string, label: string, @ICommandService private readonly commandService: ICommandService) { super(id, label, 'codicon-close-all'); } - public run(context?: any): Promise { + run(context?: any): Promise { return this.commandService.executeCommand(CLOSE_EDITORS_AND_GROUP_COMMAND_ID, {}, context); } } export class FocusFilesExplorer extends Action { - public static readonly ID = 'workbench.files.action.focusFilesExplorer'; - public static readonly LABEL = nls.localize('focusFilesExplorer', "Focus on Files Explorer"); + static readonly ID = 'workbench.files.action.focusFilesExplorer'; + static readonly LABEL = nls.localize('focusFilesExplorer', "Focus on Files Explorer"); constructor( id: string, @@ -633,15 +633,15 @@ export class FocusFilesExplorer extends Action { super(id, label); } - public run(): Promise { + run(): Promise { return this.viewletService.openViewlet(VIEWLET_ID, true); } } export class ShowActiveFileInExplorer extends Action { - public static readonly ID = 'workbench.files.action.showActiveFileInExplorer'; - public static readonly LABEL = nls.localize('showInExplorer', "Reveal Active File in Side Bar"); + static readonly ID = 'workbench.files.action.showActiveFileInExplorer'; + static readonly LABEL = nls.localize('showInExplorer', "Reveal Active File in Side Bar"); constructor( id: string, @@ -653,7 +653,7 @@ export class ShowActiveFileInExplorer extends Action { super(id, label); } - public run(): Promise { + run(): Promise { const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }); if (resource) { this.commandService.executeCommand(REVEAL_IN_EXPLORER_COMMAND_ID, resource); @@ -667,8 +667,8 @@ export class ShowActiveFileInExplorer extends Action { export class CollapseExplorerView extends Action { - public static readonly ID = 'workbench.files.action.collapseExplorerFolders'; - public static readonly LABEL = nls.localize('collapseExplorerFolders', "Collapse Folders in Explorer"); + static readonly ID = 'workbench.files.action.collapseExplorerFolders'; + static readonly LABEL = nls.localize('collapseExplorerFolders', "Collapse Folders in Explorer"); constructor(id: string, label: string, @@ -682,20 +682,19 @@ export class CollapseExplorerView extends Action { })); } - run(): Promise { - return this.viewletService.openViewlet(VIEWLET_ID).then((viewlet: ExplorerViewlet) => { - const explorerView = viewlet.getExplorerView(); - if (explorerView) { - explorerView.collapseAll(); - } - }); + async run(): Promise { + const explorerViewlet = await this.viewletService.openViewlet(VIEWLET_ID) as ExplorerViewlet; + const explorerView = explorerViewlet.getExplorerView(); + if (explorerView) { + explorerView.collapseAll(); + } } } export class RefreshExplorerView extends Action { - public static readonly ID = 'workbench.files.action.refreshFilesExplorer'; - public static readonly LABEL = nls.localize('refreshExplorer', "Refresh Explorer"); + static readonly ID = 'workbench.files.action.refreshFilesExplorer'; + static readonly LABEL = nls.localize('refreshExplorer', "Refresh Explorer"); constructor( @@ -710,17 +709,16 @@ export class RefreshExplorerView extends Action { })); } - public run(): Promise { - return this.viewletService.openViewlet(VIEWLET_ID).then(() => - this.explorerService.refresh() - ); + async run(): Promise { + await this.viewletService.openViewlet(VIEWLET_ID); + this.explorerService.refresh(); } } export class ShowOpenedFileInNewWindow extends Action { - public static readonly ID = 'workbench.action.files.showOpenedFileInNewWindow'; - public static readonly LABEL = nls.localize('openFileInNewWindow', "Open Active File in New Window"); + static readonly ID = 'workbench.action.files.showOpenedFileInNewWindow'; + static readonly LABEL = nls.localize('openFileInNewWindow', "Open Active File in New Window"); constructor( id: string, @@ -733,11 +731,11 @@ export class ShowOpenedFileInNewWindow extends Action { super(id, label); } - public run(): Promise { + run(): Promise { const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }); if (fileResource) { if (this.fileService.canHandleResource(fileResource)) { - this.hostService.openInWindow([{ fileUri: fileResource }], { forceNewWindow: true }); + this.hostService.openWindow([{ fileUri: fileResource }], { forceNewWindow: true }); } else { this.notificationService.info(nls.localize('openFileToShowInNewWindow.unsupportedschema', "The active editor must contain an openable resource.")); } @@ -768,14 +766,15 @@ export function validateFileName(item: ExplorerItem, name: string): string | nul if (name !== item.name) { // Do not allow to overwrite existing file - const child = parent && parent.getChild(name); + const child = parent?.getChild(name); if (child && child !== item) { return nls.localize('fileNameExistsError', "A file or folder **{0}** already exists at this location. Please choose a different name.", name); } } // Invalid File name - if (names.some((folderName) => !extpath.isValidBasename(folderName))) { + const windowsBasenameValidity = item.resource.scheme === Schemas.file && isWindows; + if (names.some((folderName) => !extpath.isValidBasename(folderName, windowsBasenameValidity))) { return nls.localize('invalidFileNameError', "The name **{0}** is not valid as a file or folder name. Please choose a different name.", trimLongName(name)); } @@ -783,7 +782,7 @@ export function validateFileName(item: ExplorerItem, name: string): string | nul } function trimLongName(name: string): string { - if (name && name.length > 255) { + if (name?.length > 255) { return `${name.substr(0, 255)}...`; } @@ -808,8 +807,8 @@ export function getWellFormedFileName(filename: string): string { export class CompareWithClipboardAction extends Action { - public static readonly ID = 'workbench.files.action.compareWithClipboard'; - public static readonly LABEL = nls.localize('compareWithClipboard', "Compare Active File with Clipboard"); + static readonly ID = 'workbench.files.action.compareWithClipboard'; + static readonly LABEL = nls.localize('compareWithClipboard', "Compare Active File with Clipboard"); private static readonly SCHEME = 'clipboardCompare'; @@ -828,7 +827,7 @@ export class CompareWithClipboardAction extends Action { this.enabled = true; } - public run(): Promise { + run(): Promise { const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }); if (resource && (this.fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled)) { if (!this.registrationDisposal) { @@ -848,7 +847,7 @@ export class CompareWithClipboardAction extends Action { return Promise.resolve(true); } - public dispose(): void { + dispose(): void { super.dispose(); dispose(this.registrationDisposal); @@ -951,15 +950,15 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole CommandsRegistry.registerCommand({ id: NEW_FILE_COMMAND_ID, - handler: (accessor) => { - openExplorerAndCreate(accessor, false).then(undefined, onUnexpectedError); + handler: async (accessor) => { + await openExplorerAndCreate(accessor, false); } }); CommandsRegistry.registerCommand({ id: NEW_FOLDER_COMMAND_ID, - handler: (accessor) => { - openExplorerAndCreate(accessor, true).then(undefined, onUnexpectedError); + handler: async (accessor) => { + await openExplorerAndCreate(accessor, true); } }); @@ -1049,12 +1048,32 @@ const downloadFileHandler = (accessor: ServicesAccessor) => { return; } const explorerContext = getContext(listService.lastFocusedList); - const textFileService = accessor.get(ITextFileService); + const fileService = accessor.get(IFileService); + const fileDialogService = accessor.get(IFileDialogService); if (explorerContext.stat) { const stats = explorerContext.selection.length > 1 ? explorerContext.selection : [explorerContext.stat]; stats.forEach(async s => { - await textFileService.saveAs(s.resource, undefined, { availableFileSystems: [Schemas.file] }); + if (isWeb) { + if (!s.isDirectory) { + triggerDownload(asDomUri(s.resource), s.name); + } + } else { + let defaultUri = s.isDirectory ? fileDialogService.defaultFolderPath() : fileDialogService.defaultFilePath(); + if (defaultUri && !s.isDirectory) { + defaultUri = resources.joinPath(defaultUri, s.name); + } + + const destination = await fileDialogService.showSaveDialog({ + availableFileSystems: [Schemas.file], + saveLabel: mnemonicButtonLabel(nls.localize('download', "Download")), + title: s.isDirectory ? nls.localize('downloadFolder', "Download Folder") : nls.localize('downloadFile', "Download File"), + defaultUri + }); + if (destination) { + await fileService.copy(s.resource, destination); + } + } }); } }; diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index c17b9ce80db..53b68253a86 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import { toResource, IEditorCommandsContext, SideBySideEditor } from 'vs/workbench/common/editor'; -import { IWindowOpenable, IOpenInWindowOptions, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable, IOpenWindowOptions, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -29,7 +29,7 @@ import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { isWindows } from 'vs/base/common/platform'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { getResourceForCommand, getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { getMultiSelectedEditorContexts } from 'vs/workbench/browser/parts/editor/editorCommands'; import { Schemas } from 'vs/base/common/network'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -37,12 +37,12 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ILabelService } from 'vs/platform/label/common/label'; -import { basename, toLocalResource, joinPath } from 'vs/base/common/resources'; +import { basename, toLocalResource, joinPath, isEqual } from 'vs/base/common/resources'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { UNTITLED_WORKSPACE_NAME } from 'vs/platform/workspaces/common/workspaces'; -import { withUndefinedAsNull } from 'vs/base/common/types'; +import { withUndefinedAsNull, withNullAsUndefined } from 'vs/base/common/types'; // Commands @@ -78,7 +78,7 @@ export const ResourceSelectedForCompareContext = new RawContextKey('res export const REMOVE_ROOT_FOLDER_COMMAND_ID = 'removeRootFolder'; export const REMOVE_ROOT_FOLDER_LABEL = nls.localize('removeFolderFromWorkspace', "Remove Folder from Workspace"); -export const openWindowCommand = (accessor: ServicesAccessor, toOpen: IWindowOpenable[], options?: IOpenInWindowOptions) => { +export const openWindowCommand = (accessor: ServicesAccessor, toOpen: IWindowOpenable[], options?: IOpenWindowOptions) => { if (Array.isArray(toOpen)) { const hostService = accessor.get(IHostService); const environmentService = accessor.get(IEnvironmentService); @@ -94,13 +94,13 @@ export const openWindowCommand = (accessor: ServicesAccessor, toOpen: IWindowOpe return openable; }); - hostService.openInWindow(toOpen, options); + hostService.openWindow(toOpen, options); } }; export const newWindowCommand = (accessor: ServicesAccessor, options?: IOpenEmptyWindowOptions) => { const hostService = accessor.get(IHostService); - hostService.openEmptyWindow(options); + hostService.openWindow(options); }; async function save( @@ -138,12 +138,12 @@ async function doSaveAs( editorGroupService: IEditorGroupsService, environmentService: IWorkbenchEnvironmentService ): Promise { - let viewStateOfSource: IEditorViewState | null = null; + let viewStateOfSource: IEditorViewState | undefined = undefined; const activeTextEditorWidget = getCodeEditor(editorService.activeTextEditorWidget); if (activeTextEditorWidget) { const activeResource = toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }); - if (activeResource && (fileService.canHandleResource(activeResource) || resource.scheme === Schemas.untitled) && activeResource.toString() === resource.toString()) { - viewStateOfSource = activeTextEditorWidget.saveViewState(); + if (activeResource && (fileService.canHandleResource(activeResource) || resource.scheme === Schemas.untitled) && isEqual(activeResource, resource)) { + viewStateOfSource = withNullAsUndefined(activeTextEditorWidget.saveViewState()); } } @@ -166,7 +166,7 @@ async function doSaveAs( target = await textFileService.saveAs(resource, undefined, options); } - if (!target || target.toString() === resource.toString()) { + if (!target || isEqual(target, resource)) { return false; // save canceled or same resource used } @@ -174,7 +174,7 @@ async function doSaveAs( resource: target, options: { pinned: true, - viewState: viewStateOfSource || undefined + viewState: viewStateOfSource } }; @@ -196,8 +196,8 @@ async function doSave( // Pin the active editor if we are saving it const activeControl = editorService.activeControl; - const activeEditorResource = activeControl && activeControl.input && activeControl.input.getResource(); - if (activeControl && activeEditorResource && activeEditorResource.toString() === resource.toString()) { + const activeEditorResource = activeControl?.input?.getResource(); + if (activeControl && activeEditorResource && isEqual(activeEditorResource, resource)) { activeControl.group.pinEditor(activeControl.input); } @@ -236,7 +236,7 @@ async function saveAll(saveAllArguments: any, editorService: IEditorService, unt encoding: untitledEditorService.getEncoding(resource), resource, options: { - inactive: activeEditorResource ? activeEditorResource.toString() !== resource.toString() : true, + inactive: activeEditorResource ? !isEqual(activeEditorResource, resource) : true, pinned: true, preserveFocus: true, index: group.getIndexOfEditor(e) @@ -252,8 +252,8 @@ async function saveAll(saveAllArguments: any, editorService: IEditorService, unt // Update untitled resources to the saved ones, so we open the proper files groupIdToUntitledResourceInput.forEach((inputs, groupId) => { inputs.forEach(i => { - const targetResult = result.results.filter(r => r.success && r.source.toString() === i.resource.toString()).pop(); - if (targetResult && targetResult.target) { + const targetResult = result.results.filter(r => r.success && isEqual(r.source, i.resource)).pop(); + if (targetResult?.target) { i.resource = targetResult.target; } }); @@ -315,7 +315,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: undefined, weight: KeybindingWeight.WorkbenchContrib, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_D), - handler: (accessor, resource: URI | object) => { + handler: async (accessor, resource: URI | object) => { const instantiationService = accessor.get(IInstantiationService); const textModelService = accessor.get(ITextModelService); const editorService = accessor.get(IEditorService); @@ -337,8 +337,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const name = basename(uri); const editorLabel = nls.localize('modifiedLabel', "{0} (in file) ↔ {1}", name, name); - TextFileContentProvider.open(uri, COMPARE_WITH_SAVED_SCHEMA, editorLabel, editorService).then(() => { - + try { + await TextFileContentProvider.open(uri, COMPARE_WITH_SAVED_SCHEMA, editorLabel, editorService); // Dispose once no more diff editor is opened with the scheme if (registerEditorListener) { providerDisposables.push(editorService.onDidVisibleEditorsChange(() => { @@ -347,12 +347,10 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } })); } - }, error => { + } catch { providerDisposables = dispose(providerDisposables); - }); + } } - - return Promise.resolve(true); } }); @@ -588,7 +586,7 @@ CommandsRegistry.registerCommand({ const workspace = contextService.getWorkspace(); const resources = getMultiSelectedResources(resource, accessor.get(IListService), accessor.get(IEditorService)).filter(r => // Need to verify resources are workspaces since multi selection can trigger this command on some non workspace resources - workspace.folders.some(f => f.uri.toString() === r.toString()) + workspace.folders.some(f => isEqual(f.uri, r)) ); return workspaceEditingService.removeFolders(resources); diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 28e2253c870..350dd14c5f4 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -37,6 +37,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExplorerService } from 'vs/workbench/contrib/files/common/explorerService'; import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { Schemas } from 'vs/base/common/network'; +import { WorkspaceWatcher } from 'vs/workbench/contrib/files/common/workspaceWatcher'; // Viewlet Action export class OpenExplorerViewletAction extends ShowViewletAction { @@ -76,7 +77,7 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie ExplorerViewlet, VIEWLET_ID, nls.localize('explore', "Explorer"), - 'explore', + 'codicon-files', 0 )); @@ -169,6 +170,8 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Register uri display for file uris Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileUriLabelContribution, LifecyclePhase.Starting); +// Workspace Watcher +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceWatcher, LifecyclePhase.Restored); // Configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -239,17 +242,20 @@ configurationRegistry.registerConfiguration({ 'default': 'utf8', 'description': nls.localize('encoding', "The default character set encoding to use when reading and writing files. This setting can also be configured per language."), 'scope': ConfigurationScope.RESOURCE, - 'enumDescriptions': Object.keys(SUPPORTED_ENCODINGS).map(key => SUPPORTED_ENCODINGS[key].labelLong) + 'enumDescriptions': Object.keys(SUPPORTED_ENCODINGS).map(key => SUPPORTED_ENCODINGS[key].labelLong), + 'included': Object.keys(SUPPORTED_ENCODINGS).length > 1 }, 'files.autoGuessEncoding': { 'type': 'boolean', 'overridable': true, 'default': false, 'description': nls.localize('autoGuessEncoding', "When enabled, the editor will attempt to guess the character set encoding when opening files. This setting can also be configured per language."), - 'scope': ConfigurationScope.RESOURCE + 'scope': ConfigurationScope.RESOURCE, + 'included': Object.keys(SUPPORTED_ENCODINGS).length > 1 }, 'files.eol': { 'type': 'string', + 'overridable': true, 'enum': [ '\n', '\r\n', diff --git a/src/vs/workbench/contrib/files/browser/files.ts b/src/vs/workbench/contrib/files/browser/files.ts index 85147dc5a43..e666a5b1a23 100644 --- a/src/vs/workbench/contrib/files/browser/files.ts +++ b/src/vs/workbench/contrib/files/browser/files.ts @@ -20,7 +20,7 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe } let list = listService.lastFocusedList; - if (list && list.getHTMLElement() === document.activeElement) { + if (list?.getHTMLElement() === document.activeElement) { let focus: unknown; if (list instanceof List) { const focused = list.getFocusedElements(); @@ -46,7 +46,7 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): Array { const list = listService.lastFocusedList; - if (list && list.getHTMLElement() === document.activeElement) { + if (list?.getHTMLElement() === document.activeElement) { // Explorer if (list instanceof WorkbenchAsyncDataTree) { const selection = list.getSelection().map((fs: ExplorerItem) => fs.resource); diff --git a/src/vs/workbench/contrib/debug/browser/media/close-all-dark.svg b/src/vs/workbench/contrib/files/browser/media/collapse-all-dark.svg similarity index 50% rename from src/vs/workbench/contrib/debug/browser/media/close-all-dark.svg rename to src/vs/workbench/contrib/files/browser/media/collapse-all-dark.svg index 35e5fb44226..4862c55dbeb 100644 --- a/src/vs/workbench/contrib/debug/browser/media/close-all-dark.svg +++ b/src/vs/workbench/contrib/files/browser/media/collapse-all-dark.svg @@ -1,4 +1,4 @@ - + diff --git a/src/vs/workbench/contrib/debug/browser/media/close-all-hc.svg b/src/vs/workbench/contrib/files/browser/media/collapse-all-hc.svg similarity index 50% rename from src/vs/workbench/contrib/debug/browser/media/close-all-hc.svg rename to src/vs/workbench/contrib/files/browser/media/collapse-all-hc.svg index def744d1ab9..05f920b29b6 100644 --- a/src/vs/workbench/contrib/debug/browser/media/close-all-hc.svg +++ b/src/vs/workbench/contrib/files/browser/media/collapse-all-hc.svg @@ -1,4 +1,4 @@ - + diff --git a/src/vs/workbench/contrib/debug/browser/media/close-all-light.svg b/src/vs/workbench/contrib/files/browser/media/collapse-all-light.svg similarity index 50% rename from src/vs/workbench/contrib/debug/browser/media/close-all-light.svg rename to src/vs/workbench/contrib/files/browser/media/collapse-all-light.svg index 6c7cec7461c..6359b42e623 100644 --- a/src/vs/workbench/contrib/debug/browser/media/close-all-light.svg +++ b/src/vs/workbench/contrib/files/browser/media/collapse-all-light.svg @@ -1,4 +1,4 @@ - + diff --git a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css index 5a6a61eb7c8..83871571794 100644 --- a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css @@ -3,11 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/* Activity Bar */ -.monaco-workbench .activitybar .monaco-action-bar .action-label.explore { - -webkit-mask: url('files-activity-bar.svg') no-repeat 50% 50%; -} - /* --- Explorer viewlet --- */ .explorer-viewlet, .explorer-folders-view { @@ -68,6 +63,7 @@ .explorer-viewlet .panel-header .count { min-width: fit-content; + min-width: -moz-fit-content; display: flex; align-items: center; } @@ -86,6 +82,10 @@ display: block; } +.explorer-viewlet .explorer-open-editors .monaco-list .monaco-list-row > .monaco-action-bar .codicon { + color: inherit; +} + .explorer-viewlet .explorer-open-editors .monaco-list .monaco-list-row > .monaco-action-bar .codicon-close { width: 8px; height: 22px; @@ -159,3 +159,16 @@ .hc-black .monaco-workbench .explorer-viewlet .editor-group { line-height: 20px; } + +/* TODO @misolori convert these to use icon font, for the debug viewlet */ +.monaco-workbench .explorer-action.collapse-explorer { + background: url("collapse-all-light.svg") 50% no-repeat; +} + +.vs-dark .monaco-workbench .explorer-action.collapse-explorer { + background: url("collapse-all-dark.svg") 50% no-repeat; +} + +.hc-black .monaco-workbench .explorer-action.collapse-explorer { + background: url("collapse-all-hc.svg") 50% no-repeat; +} diff --git a/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg b/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg deleted file mode 100644 index c109b13c3d2..00000000000 --- a/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts index 608638b5178..847d044971b 100644 --- a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts @@ -28,7 +28,7 @@ import { INotificationService, INotificationHandle, INotificationActions, Severi import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ExecuteCommandAction } from 'vs/platform/actions/common/actions'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IProductService } from 'vs/platform/product/common/productService'; import { Event } from 'vs/base/common/event'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { isWindows } from 'vs/base/common/platform'; @@ -83,7 +83,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I const activeInput = this.editorService.activeEditor; if (activeInput instanceof DiffEditorInput && activeInput.originalInput instanceof ResourceEditorInput && activeInput.modifiedInput instanceof FileEditorInput) { const resource = activeInput.originalInput.getResource(); - if (resource && resource.scheme === CONFLICT_RESOLUTION_SCHEME) { + if (resource?.scheme === CONFLICT_RESOLUTION_SCHEME) { isActiveEditorSaveConflictResolution = true; activeConflictResolutionResource = activeInput.modifiedInput.getResource(); } @@ -141,7 +141,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I // Save Elevated if (canHandlePermissionOrReadonlyErrors && (isPermissionDenied || triedToMakeWriteable)) { - primaryActions.push(this.instantiationService.createInstance(SaveElevatedAction, model, triedToMakeWriteable)); + primaryActions.push(this.instantiationService.createInstance(SaveElevatedAction, model, !!triedToMakeWriteable)); } // Overwrite @@ -236,7 +236,7 @@ class ResolveSaveConflictAction extends Action { @IEditorService private readonly editorService: IEditorService, @INotificationService private readonly notificationService: INotificationService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IEnvironmentService private readonly environmentService: IEnvironmentService + @IProductService private readonly productService: IProductService ) { super('workbench.files.action.resolveConflict', nls.localize('compareChanges', "Compare")); } @@ -245,7 +245,7 @@ class ResolveSaveConflictAction extends Action { if (!this.model.isDisposed()) { const resource = this.model.getResource(); const name = basename(resource); - const editorLabel = nls.localize('saveConflictDiffLabel', "{0} (in file) ↔ {1} (in {2}) - Resolve save conflict", name, name, this.environmentService.appNameLong); + const editorLabel = nls.localize('saveConflictDiffLabel', "{0} (in file) ↔ {1} (in {2}) - Resolve save conflict", name, name, this.productService.nameLong); await TextFileContentProvider.open(resource, CONFLICT_RESOLUTION_SCHEME, editorLabel, this.editorService, { pinned: true }); @@ -303,7 +303,7 @@ class OverwriteReadonlyAction extends Action { } } -export const acceptLocalChangesCommand = (accessor: ServicesAccessor, resource: URI) => { +export const acceptLocalChangesCommand = async (accessor: ServicesAccessor, resource: URI) => { const editorService = accessor.get(IEditorService); const resolverService = accessor.get(ITextModelService); const modelService = accessor.get(IModelService); @@ -312,35 +312,35 @@ export const acceptLocalChangesCommand = (accessor: ServicesAccessor, resource: if (!control) { return; } + const editor = control.input; const group = control.group; - resolverService.createModelReference(resource).then(async reference => { - const model = reference.object as IResolvedTextFileEditorModel; - const localModelSnapshot = model.createSnapshot(); + const reference = await resolverService.createModelReference(resource); + const model = reference.object as IResolvedTextFileEditorModel; + const localModelSnapshot = model.createSnapshot(); - clearPendingResolveSaveConflictMessages(); // hide any previously shown message about how to use these actions + clearPendingResolveSaveConflictMessages(); // hide any previously shown message about how to use these actions - // Revert to be able to save - await model.revert(); + // Revert to be able to save + await model.revert(); - // Restore user value (without loosing undo stack) - modelService.updateModel(model.textEditorModel, createTextBufferFactoryFromSnapshot(localModelSnapshot)); + // Restore user value (without loosing undo stack) + modelService.updateModel(model.textEditorModel, createTextBufferFactoryFromSnapshot(localModelSnapshot)); - // Trigger save - await model.save(); + // Trigger save + await model.save(); - // Reopen file input - await editorService.openEditor({ resource: model.getResource() }, group); + // Reopen file input + await editorService.openEditor({ resource: model.getResource() }, group); - // Clean up - group.closeEditor(editor); - editor.dispose(); - reference.dispose(); - }); + // Clean up + group.closeEditor(editor); + editor.dispose(); + reference.dispose(); }; -export const revertLocalChangesCommand = (accessor: ServicesAccessor, resource: URI) => { +export const revertLocalChangesCommand = async (accessor: ServicesAccessor, resource: URI) => { const editorService = accessor.get(IEditorService); const resolverService = accessor.get(ITextModelService); @@ -348,23 +348,23 @@ export const revertLocalChangesCommand = (accessor: ServicesAccessor, resource: if (!control) { return; } + const editor = control.input; const group = control.group; - resolverService.createModelReference(resource).then(async reference => { - const model = reference.object as ITextFileEditorModel; + const reference = await resolverService.createModelReference(resource); + const model = reference.object as ITextFileEditorModel; - clearPendingResolveSaveConflictMessages(); // hide any previously shown message about how to use these actions + clearPendingResolveSaveConflictMessages(); // hide any previously shown message about how to use these actions - // Revert on model - await model.revert(); + // Revert on model + await model.revert(); - // Reopen file input - await editorService.openEditor({ resource: model.getResource() }, group); + // Reopen file input + await editorService.openEditor({ resource: model.getResource() }, group); - // Clean up - group.closeEditor(editor); - editor.dispose(); - reference.dispose(); - }); + // Clean up + group.closeEditor(editor); + editor.dispose(); + reference.dispose(); }; diff --git a/src/vs/workbench/contrib/files/browser/views/emptyView.ts b/src/vs/workbench/contrib/files/browser/views/emptyView.ts index e7e9ecf5f61..f24f0128c6f 100644 --- a/src/vs/workbench/contrib/files/browser/views/emptyView.ts +++ b/src/vs/workbench/contrib/files/browser/views/emptyView.ts @@ -6,7 +6,6 @@ import * as nls from 'vs/nls'; import * as errors from 'vs/base/common/errors'; import * as DOM from 'vs/base/browser/dom'; -import { IAction } from 'vs/base/common/actions'; import { Button } from 'vs/base/browser/ui/button/button'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -34,7 +33,6 @@ export class EmptyView extends ViewletPanel { private button!: Button; private messageElement!: HTMLElement; - private titleElement!: HTMLElement; constructor( options: IViewletViewOptions, @@ -53,15 +51,6 @@ export class EmptyView extends ViewletPanel { this._register(this.labelService.onDidChangeFormatters(() => this.setLabels())); } - renderHeader(container: HTMLElement): void { - const titleContainer = document.createElement('div'); - DOM.addClass(titleContainer, 'title'); - container.appendChild(titleContainer); - - this.titleElement = document.createElement('span'); - titleContainer.appendChild(this.titleElement); - } - protected renderBody(container: HTMLElement): void { DOM.addClass(container, 'explorer-empty-view'); container.tabIndex = 0; @@ -80,8 +69,9 @@ export class EmptyView extends ViewletPanel { if (!this.actionRunner) { return; } - const actionClass = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? AddRootFolderAction : OpenFolderAction; - const action = this.instantiationService.createInstance(actionClass, actionClass.ID, actionClass.LABEL); + const action = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE + ? this.instantiationService.createInstance(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL) + : this.instantiationService.createInstance(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL); this.actionRunner.run(action).then(() => { action.dispose(); }, err => { @@ -110,7 +100,9 @@ export class EmptyView extends ViewletPanel { container.style.backgroundColor = color ? color.toString() : ''; }, onDragOver: e => { - e.dataTransfer!.dropEffect = 'copy'; + if (e.dataTransfer) { + e.dataTransfer.dropEffect = 'copy'; + } } })); @@ -123,7 +115,7 @@ export class EmptyView extends ViewletPanel { if (this.button) { this.button.label = nls.localize('addFolder', "Add Folder"); } - this.titleElement.textContent = EmptyView.NAME; + this.updateTitle(EmptyView.NAME); } else { if (this.environmentService.configuration.remoteAuthority && !isWeb) { const hostLabel = this.labelService.getHostLabel(Schemas.vscodeRemote, this.environmentService.configuration.remoteAuthority); @@ -134,7 +126,7 @@ export class EmptyView extends ViewletPanel { if (this.button) { this.button.label = nls.localize('openFolder', "Open Folder"); } - this.titleElement.textContent = this.title; + this.updateTitle(this.title); } } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index fda43517833..5421df5266c 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -101,7 +101,7 @@ export class ExplorerView extends ViewletPanel { this.resourceMoveableToTrash = ExplorerResourceMoveableToTrash.bindTo(contextKeyService); const decorationProvider = new ExplorerDecorationsProvider(this.explorerService, contextService); - decorationService.registerDecorationsProvider(decorationProvider); + this._register(decorationService.registerDecorationsProvider(decorationProvider)); this._register(decorationProvider); this._register(this.resourceContext); } @@ -323,7 +323,7 @@ export class ExplorerView extends ViewletPanel { const explorerNavigator = new TreeResourceNavigator2(this.tree); this._register(explorerNavigator); // Open when selecting via keyboard - this._register(explorerNavigator.onDidOpenResource(e => { + this._register(explorerNavigator.onDidOpenResource(async e => { const selection = this.tree.getSelection(); // Do not react if the user is expanding selection via keyboard. // Check if the item was previously also selected, if yes the user is simply expanding / collapsing current selection #66589. @@ -335,8 +335,7 @@ export class ExplorerView extends ViewletPanel { return; } this.telemetryService.publicLog2('workbenchActionExecuted', { id: 'workbench.files.openFile', from: 'explorer' }); - this.editorService.openEditor({ resource: selection[0].resource, options: { preserveFocus: e.editorOptions.preserveFocus, pinned: e.editorOptions.pinned } }, e.sideBySide ? SIDE_GROUP : ACTIVE_GROUP) - .then(undefined, onUnexpectedError); + await this.editorService.openEditor({ resource: selection[0].resource, options: { preserveFocus: e.editorOptions.preserveFocus, pinned: e.editorOptions.pinned } }, e.sideBySide ? SIDE_GROUP : ACTIVE_GROUP); } })); @@ -358,7 +357,7 @@ export class ExplorerView extends ViewletPanel { // React on events private onConfigurationUpdated(configuration: IFilesConfiguration, event?: IConfigurationChangeEvent): void { - this.autoReveal = configuration && configuration.explorer && configuration.explorer.autoReveal; + this.autoReveal = configuration?.explorer?.autoReveal; // Push down config updates to components of viewer let needsRefresh = false; @@ -524,7 +523,12 @@ export class ExplorerView extends ViewletPanel { return withNullAsUndefined(toResource(input, { supportSideBySide: SideBySideEditor.MASTER })); } - private async onSelectResource(resource: URI | undefined, reveal = this.autoReveal): Promise { + private async onSelectResource(resource: URI | undefined, reveal = this.autoReveal, retry = 0): Promise { + // do no retry more than once to prevent inifinite loops in cases of inconsistent model + if (retry === 2) { + return; + } + if (!resource || !this.isBodyVisible()) { return; } @@ -535,12 +539,18 @@ export class ExplorerView extends ViewletPanel { .sort((first, second) => second.resource.path.length - first.resource.path.length)[0]; while (item && item.resource.toString() !== resource.toString()) { + if (item.isDisposed) { + return this.onSelectResource(resource, reveal, retry + 1); + } await this.tree.expand(item); item = first(values(item.children), i => isEqualOrParent(resource, i.resource)); } if (item && item.parent) { if (reveal) { + if (item.isDisposed) { + return this.onSelectResource(resource, reveal, retry + 1); + } this.tree.reveal(item, 0.5); } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 5cc46e4d90b..e451c95c123 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -30,16 +30,16 @@ import { equals, deepClone } from 'vs/base/common/objects'; import * as path from 'vs/base/common/path'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { compareFileExtensions, compareFileNames } from 'vs/base/common/comparers'; -import { fillResourceDataTransfers, CodeDataTransfers, extractResources } from 'vs/workbench/browser/dnd'; +import { fillResourceDataTransfers, CodeDataTransfers, extractResources, containsDragType } from 'vs/workbench/browser/dnd'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd'; import { Schemas } from 'vs/base/common/network'; import { DesktopDragAndDropData, ExternalElementsDragAndDropData, ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; -import { isMacintosh } from 'vs/base/common/platform'; -import { IDialogService, IConfirmationResult, IConfirmation, getConfirmMessage } from 'vs/platform/dialogs/common/dialogs'; -import { ITextFileService, ITextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; +import { isMacintosh, isWeb } from 'vs/base/common/platform'; +import { IDialogService, IConfirmation, getConfirmMessage } from 'vs/platform/dialogs/common/dialogs'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { URI } from 'vs/base/common/uri'; import { ITask, sequence } from 'vs/base/common/async'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -47,6 +47,7 @@ import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/work import { findValidPasteFileTarget } from 'vs/workbench/contrib/files/browser/fileActions'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { Emitter } from 'vs/base/common/event'; +import { VSBuffer } from 'vs/base/common/buffer'; export class ExplorerDelegate implements IListVirtualDelegate { @@ -303,7 +304,7 @@ export class FilesFilter implements ITreeFilter { let needsRefresh = false; this.contextService.getWorkspace().folders.forEach(folder => { const configuration = this.configurationService.getValue({ resource: folder.uri }); - const excludesConfig: glob.IExpression = (configuration && configuration.files && configuration.files.exclude) || Object.create(null); + const excludesConfig: glob.IExpression = configuration?.files?.exclude || Object.create(null); if (!needsRefresh) { const cached = this.hiddenExpressionPerRoot.get(folder.uri.toString()); @@ -427,6 +428,13 @@ export class FileSorter implements ITreeSorter { } } +const fileOverwriteConfirm: IConfirmation = { + message: localize('confirmOverwrite', "A file or folder with the same name already exists in the destination folder. Do you want to replace it?"), + detail: localize('irreversible', "This action is irreversible!"), + primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + type: 'warning' +}; + export class FileDragAndDrop implements ITreeDragAndDrop { private static readonly CONFIRM_DND_SETTING_KEY = 'explorer.confirmDragAndDrop'; @@ -465,14 +473,8 @@ export class FileDragAndDrop implements ITreeDragAndDrop { const effect = (fromDesktop || isCopy) ? ListDragOverEffect.Copy : ListDragOverEffect.Move; // Desktop DND - if (fromDesktop && originalEvent.dataTransfer) { - const types = originalEvent.dataTransfer.types; - const typesArray: string[] = []; - for (let i = 0; i < types.length; i++) { - typesArray.push(types[i].toLowerCase()); // somehow the types are lowercase - } - - if (typesArray.indexOf(DataTransfers.FILES.toLowerCase()) === -1 && typesArray.indexOf(CodeDataTransfers.FILES.toLowerCase()) === -1) { + if (fromDesktop) { + if (!containsDragType(originalEvent, DataTransfers.FILES, CodeDataTransfers.FILES)) { return false; } } @@ -605,6 +607,32 @@ export class FileDragAndDrop implements ITreeDragAndDrop { } private async handleExternalDrop(data: DesktopDragAndDropData, target: ExplorerItem, originalEvent: DragEvent): Promise { + if (isWeb) { + data.files.forEach(file => { + const reader = new FileReader(); + reader.readAsArrayBuffer(file); + reader.onload = async (event) => { + const name = file.name; + if (typeof name === 'string' && event.target?.result instanceof ArrayBuffer) { + if (target.getChild(name)) { + const { confirmed } = await this.dialogService.confirm(fileOverwriteConfirm); + if (!confirmed) { + return; + } + } + + const resource = joinPath(target.resource, name); + await this.fileService.writeFile(resource, VSBuffer.wrap(new Uint8Array(event.target?.result))); + if (data.files.length === 1) { + await this.editorService.openEditor({ resource, options: { pinned: true } }); + } + } + }; + }); + + return; + } + const droppedResources = extractResources(originalEvent, true); // Check for dropped external files to be folders const result = await this.fileService.resolveAll(droppedResources); @@ -644,91 +672,67 @@ export class FileDragAndDrop implements ITreeDragAndDrop { else if (target instanceof ExplorerItem) { return this.addResources(target, droppedResources.map(res => res.resource)); } - - return undefined; } - private addResources(target: ExplorerItem, resources: URI[]): Promise { + private async addResources(target: ExplorerItem, resources: URI[]): Promise { if (resources && resources.length > 0) { // Resolve target to check for name collisions and ask user - return this.fileService.resolve(target.resource).then(targetStat => { + const targetStat = await this.fileService.resolve(target.resource); - // Check for name collisions - const targetNames = new Set(); - if (targetStat.children) { - const ignoreCase = hasToIgnoreCase(target.resource); - targetStat.children.forEach(child => { - targetNames.add(ignoreCase ? child.name : child.name.toLowerCase()); - }); + // Check for name collisions + const targetNames = new Set(); + if (targetStat.children) { + const ignoreCase = hasToIgnoreCase(target.resource); + targetStat.children.forEach(child => { + targetNames.add(ignoreCase ? child.name : child.name.toLowerCase()); + }); + } + + const resourceExists = resources.some(resource => targetNames.has(!hasToIgnoreCase(resource) ? basename(resource) : basename(resource).toLowerCase())); + if (resourceExists) { + const confirmationResult = await this.dialogService.confirm(fileOverwriteConfirm); + if (!confirmationResult.confirmed) { + return; } + } - let overwritePromise: Promise = Promise.resolve({ confirmed: true }); - if (resources.some(resource => { - return targetNames.has(!hasToIgnoreCase(resource) ? basename(resource) : basename(resource).toLowerCase()); - })) { - const confirm: IConfirmation = { - message: localize('confirmOverwrite', "A file or folder with the same name already exists in the destination folder. Do you want to replace it?"), - detail: localize('irreversible', "This action is irreversible!"), - primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), - type: 'warning' - }; + // Run add in sequence + const addPromisesFactory: ITask>[] = []; + resources.forEach(resource => { + addPromisesFactory.push(async () => { + const sourceFile = resource; + const targetFile = joinPath(target.resource, basename(sourceFile)); - overwritePromise = this.dialogService.confirm(confirm); - } - - return overwritePromise.then(res => { - if (!res.confirmed) { - return []; + // if the target exists and is dirty, make sure to revert it. otherwise the dirty contents + // of the target file would replace the contents of the added file. since we already + // confirmed the overwrite before, this is OK. + if (this.textFileService.isDirty(targetFile)) { + await this.textFileService.revertAll([targetFile], { soft: true }); } - // Run add in sequence - const addPromisesFactory: ITask>[] = []; - resources.forEach(resource => { - addPromisesFactory.push(() => { - const sourceFile = resource; - const targetFile = joinPath(target.resource, basename(sourceFile)); - - // if the target exists and is dirty, make sure to revert it. otherwise the dirty contents - // of the target file would replace the contents of the added file. since we already - // confirmed the overwrite before, this is OK. - let revertPromise: Promise = Promise.resolve(null); - if (this.textFileService.isDirty(targetFile)) { - revertPromise = this.textFileService.revertAll([targetFile], { soft: true }); - } - - return revertPromise.then(() => { - const copyTarget = joinPath(target.resource, basename(sourceFile)); - return this.fileService.copy(sourceFile, copyTarget, true).then(stat => { - - // if we only add one file, just open it directly - if (resources.length === 1 && !stat.isDirectory) { - this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } }); - } - }); - }); - }); - }); - - return sequence(addPromisesFactory); + const copyTarget = joinPath(target.resource, basename(sourceFile)); + const stat = await this.fileService.copy(sourceFile, copyTarget, true); + // if we only add one file, just open it directly + if (resources.length === 1 && !stat.isDirectory) { + this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } }); + } }); }); - } - return Promise.resolve(undefined); + await sequence(addPromisesFactory); + } } - private handleExplorerDrop(data: IDragAndDropData, target: ExplorerItem, originalEvent: DragEvent): Promise { + private async handleExplorerDrop(data: IDragAndDropData, target: ExplorerItem, originalEvent: DragEvent): Promise { const elementsData = (data as ElementsDragAndDropData).elements; const items = distinctParents(elementsData, s => s.resource); const isCopy = (originalEvent.ctrlKey && !isMacintosh) || (originalEvent.altKey && isMacintosh); - let confirmPromise: Promise; - // Handle confirm setting const confirmDragAndDrop = !isCopy && this.configurationService.getValue(FileDragAndDrop.CONFIRM_DND_SETTING_KEY); if (confirmDragAndDrop) { - confirmPromise = this.dialogService.confirm({ + const confirmation = await this.dialogService.confirm({ message: items.length > 1 && items.every(s => s.isRoot) ? localize('confirmRootsMove', "Are you sure you want to change the order of multiple root folders in your workspace?") : items.length > 1 ? getConfirmMessage(localize('confirmMultiMove', "Are you sure you want to move the following {0} files?", items.length), items.map(s => s.resource)) : items[0].isRoot ? localize('confirmRootMove', "Are you sure you want to change the order of root folder '{0}' in your workspace?", items[0].name) @@ -739,27 +743,19 @@ export class FileDragAndDrop implements ITreeDragAndDrop { type: 'question', primaryButton: localize({ key: 'moveButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Move") }); - } else { - confirmPromise = Promise.resolve({ confirmed: true }); - } - return confirmPromise.then(res => { - - // Check for confirmation checkbox - let updateConfirmSettingsPromise: Promise = Promise.resolve(undefined); - if (res.confirmed && res.checkboxChecked === true) { - updateConfirmSettingsPromise = this.configurationService.updateValue(FileDragAndDrop.CONFIRM_DND_SETTING_KEY, false, ConfigurationTarget.USER); + if (!confirmation.confirmed) { + return; } - return updateConfirmSettingsPromise.then(() => { - if (res.confirmed) { - const rootDropPromise = this.doHandleRootDrop(items.filter(s => s.isRoot), target); - return Promise.all(items.filter(s => !s.isRoot).map(source => this.doHandleExplorerDrop(source, target, isCopy)).concat(rootDropPromise)).then(() => undefined); - } + // Check for confirmation checkbox + if (confirmation.checkboxChecked === true) { + await this.configurationService.updateValue(FileDragAndDrop.CONFIRM_DND_SETTING_KEY, false, ConfigurationTarget.USER); + } + } - return Promise.resolve(undefined); - }); - }); + const rootDropPromise = this.doHandleRootDrop(items.filter(s => s.isRoot), target); + await Promise.all(items.filter(s => !s.isRoot).map(source => this.doHandleExplorerDrop(source, target, isCopy)).concat(rootDropPromise)); } private doHandleRootDrop(roots: ExplorerItem[], target: ExplorerItem): Promise { @@ -795,17 +791,16 @@ export class FileDragAndDrop implements ITreeDragAndDrop { return this.workspaceEditingService.updateFolders(0, workspaceCreationData.length, workspaceCreationData); } - private doHandleExplorerDrop(source: ExplorerItem, target: ExplorerItem, isCopy: boolean): Promise { + private async doHandleExplorerDrop(source: ExplorerItem, target: ExplorerItem, isCopy: boolean): Promise { // Reuse duplicate action if user copies if (isCopy) { const incrementalNaming = this.configurationService.getValue().explorer.incrementalNaming; - return this.fileService.copy(source.resource, findValidPasteFileTarget(target, { resource: source.resource, isDirectory: source.isDirectory, allowOverwrite: false }, incrementalNaming)).then(stat => { - if (!stat.isDirectory) { - return this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } }).then(() => undefined); - } + const stat = await this.fileService.copy(source.resource, findValidPasteFileTarget(target, { resource: source.resource, isDirectory: source.isDirectory, allowOverwrite: false }, incrementalNaming)); + if (!stat.isDirectory) { + await this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } }); + } - return undefined; - }); + return; } // Otherwise move @@ -815,8 +810,9 @@ export class FileDragAndDrop implements ITreeDragAndDrop { return Promise.resolve(); } - return this.textFileService.move(source.resource, targetResource).then(undefined, error => { - + try { + await this.textFileService.move(source.resource, targetResource); + } catch (error) { // Conflict if ((error).fileOperationResult === FileOperationResult.FILE_MOVE_CONFLICT) { const confirm: IConfirmation = { @@ -827,21 +823,19 @@ export class FileDragAndDrop implements ITreeDragAndDrop { }; // Move with overwrite if the user confirms - return this.dialogService.confirm(confirm).then(res => { - if (res.confirmed) { - return this.textFileService.move(source.resource, targetResource, true /* overwrite */).then(undefined, error => this.notificationService.error(error)); + const { confirmed } = await this.dialogService.confirm(confirm); + if (confirmed) { + try { + await this.textFileService.move(source.resource, targetResource, true /* overwrite */); + } catch (error) { + this.notificationService.error(error); } - - return undefined; - }); + } } - // Any other error else { this.notificationService.error(error); } - - return undefined; - }); + } } } diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index f25cd1c7554..a77e3359483 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -34,7 +34,7 @@ import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/m import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; import { DirtyEditorContext, OpenEditorsGroupContext } from 'vs/workbench/contrib/files/browser/fileCommands'; import { ResourceContextKey } from 'vs/workbench/common/resources'; -import { ResourcesDropHandler, fillResourceDataTransfers, CodeDataTransfers } from 'vs/workbench/browser/dnd'; +import { ResourcesDropHandler, fillResourceDataTransfers, CodeDataTransfers, containsDragType } from 'vs/workbench/browser/dnd'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd'; @@ -42,6 +42,7 @@ import { memoize } from 'vs/base/common/decorators'; import { ElementsDragAndDropData, DesktopDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { URI } from 'vs/base/common/uri'; import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { isWeb } from 'vs/base/common/platform'; const $ = dom.$; @@ -49,7 +50,7 @@ export class OpenEditorsView extends ViewletPanel { private static readonly DEFAULT_VISIBLE_OPEN_EDITORS = 9; static readonly ID = 'workbench.explorer.openEditorsView'; - static NAME = nls.localize({ key: 'openEditors', comment: ['Open is an adjective'] }, "Open Editors"); + static readonly NAME = nls.localize({ key: 'openEditors', comment: ['Open is an adjective'] }, "Open Editors"); private dirtyCountElement!: HTMLElement; private listRefreshScheduler: RunOnceScheduler; @@ -185,15 +186,15 @@ export class OpenEditorsView extends ViewletPanel { this.dirtyCountElement = dom.append(count, $('.monaco-count-badge')); this._register((attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { - const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; - const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : null; - const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; + const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; + const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : ''; + const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; this.dirtyCountElement.style.backgroundColor = background; this.dirtyCountElement.style.color = foreground; - this.dirtyCountElement.style.borderWidth = border ? '1px' : null; - this.dirtyCountElement.style.borderStyle = border ? 'solid' : null; + this.dirtyCountElement.style.borderWidth = border ? '1px' : ''; + this.dirtyCountElement.style.borderStyle = border ? 'solid' : ''; this.dirtyCountElement.style.borderColor = border; }))); @@ -244,8 +245,9 @@ export class OpenEditorsView extends ViewletPanel { this.dirtyEditorFocusedContext.reset(); const element = e.elements.length ? e.elements[0] : undefined; if (element instanceof OpenEditor) { - this.dirtyEditorFocusedContext.set(this.textFileService.isDirty(withNullAsUndefined(element.getResource()))); - this.resourceContext.set(withUndefinedAsNull(element.getResource())); + const resource = element.getResource(); + this.dirtyEditorFocusedContext.set(this.textFileService.isDirty(resource)); + this.resourceContext.set(withUndefinedAsNull(resource)); } else if (!!element) { this.groupFocusedContext.set(true); } @@ -580,7 +582,8 @@ class OpenEditorRenderer implements IListRenderer().explorer.decorations, - descriptionVerbosity: Verbosity.MEDIUM + descriptionVerbosity: Verbosity.MEDIUM, + title: editor.editor.getTitle(Verbosity.LONG) }); } @@ -642,16 +645,12 @@ class OpenEditorsDragAndDrop implements IListDragAndDrop this.onDirtyStateChange(e))); this._register(this.textFileService.models.onModelOrphanedChanged(e => this.onModelOrphanedChanged(e))); this._register(this.labelService.onDidChangeFormatters(() => FileEditorInput.MEMOIZER.clear())); + this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(() => FileEditorInput.MEMOIZER.clear())); } private onDirtyStateChange(e: TextFileModelChangeEvent): void { @@ -82,6 +84,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { private onModelOrphanedChanged(e: TextFileModelChangeEvent): void { if (e.resource.toString() === this.resource.toString()) { + FileEditorInput.MEMOIZER.clear(); this._onDidChangeLabel.fire(); } } @@ -90,7 +93,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return this.resource; } - getEncoding(): string { + getEncoding(): string | undefined { const textModel = this.textFileService.models.get(this.resource); if (textModel) { return textModel.getEncoding(); @@ -99,7 +102,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return this.preferredEncoding; } - getPreferredEncoding(): string { + getPreferredEncoding(): string | undefined { return this.preferredEncoding; } @@ -209,11 +212,12 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { private decorateLabel(label: string): string { const model = this.textFileService.models.get(this.resource); - if (model && model.hasState(ModelState.ORPHAN)) { + + if (model?.hasState(ModelState.ORPHAN)) { return localize('orphanedFile', "{0} (deleted)", label); } - if (model && model.isReadonly()) { + if (model?.isReadonly()) { return localize('readonlyFile', "{0} (read-only)", label); } diff --git a/src/vs/workbench/contrib/files/common/explorerModel.ts b/src/vs/workbench/contrib/files/common/explorerModel.ts index 161b94b12f9..fd2f87c5430 100644 --- a/src/vs/workbench/contrib/files/common/explorerModel.ts +++ b/src/vs/workbench/contrib/files/common/explorerModel.ts @@ -75,6 +75,7 @@ export class ExplorerModel implements IDisposable { export class ExplorerItem { private _isDirectoryResolved: boolean; + private _isDisposed: boolean; public isError = false; constructor( @@ -87,6 +88,11 @@ export class ExplorerItem { private _mtime?: number, ) { this._isDirectoryResolved = false; + this._isDisposed = false; + } + + get isDisposed(): boolean { + return this._isDisposed; } get isDirectoryResolved(): boolean { @@ -218,6 +224,7 @@ export class ExplorerItem { if (formerLocalChild) { ExplorerItem.mergeLocalWithDisk(diskChild, formerLocalChild); local.addChild(formerLocalChild); + oldLocalChildren.delete(diskChild.resource); } // New child: add @@ -225,6 +232,10 @@ export class ExplorerItem { local.addChild(diskChild); } }); + + for (let child of oldLocalChildren.values()) { + child._dispose(); + } } } @@ -274,10 +285,20 @@ export class ExplorerItem { } forgetChildren(): void { + for (let c of this.children.values()) { + c._dispose(); + } this.children.clear(); this._isDirectoryResolved = false; } + private _dispose() { + this._isDisposed = true; + for (let child of this.children.values()) { + child._dispose(); + } + } + private getPlatformAwareName(name: string): string { return (!name || !resources.hasToIgnoreCase(this.resource)) ? name : name.toLowerCase(); } diff --git a/src/vs/workbench/contrib/files/common/explorerService.ts b/src/vs/workbench/contrib/files/common/explorerService.ts index cc957101494..75df6d71f72 100644 --- a/src/vs/workbench/contrib/files/common/explorerService.ts +++ b/src/vs/workbench/contrib/files/common/explorerService.ts @@ -23,7 +23,7 @@ function getFileEventsExcludes(configurationService: IConfigurationService, root const scope = root ? { resource: root } : undefined; const configuration = scope ? configurationService.getValue(scope) : configurationService.getValue(); - return (configuration && configuration.files && configuration.files.exclude) || Object.create(null); + return configuration?.files?.exclude || Object.create(null); } export class ExplorerService implements IExplorerService { @@ -377,7 +377,7 @@ export class ExplorerService implements IExplorerService { } private onConfigurationUpdated(configuration: IFilesConfiguration, event?: IConfigurationChangeEvent): void { - const configSortOrder = configuration && configuration.explorer && configuration.explorer.sortOrder || 'default'; + const configSortOrder = configuration?.explorer?.sortOrder || 'default'; if (this._sortOrder !== configSortOrder) { const shouldRefresh = this._sortOrder !== undefined; this._sortOrder = configSortOrder; diff --git a/src/vs/workbench/contrib/files/common/files.ts b/src/vs/workbench/contrib/files/common/files.ts index 8f5470bff77..a55bbfa8ed4 100644 --- a/src/vs/workbench/contrib/files/common/files.ts +++ b/src/vs/workbench/contrib/files/common/files.ts @@ -6,7 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IWorkbenchEditorConfiguration, IEditorIdentifier, IEditorInput, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; -import { IFilesConfiguration, FileChangeType, IFileService } from 'vs/platform/files/common/files'; +import { IFilesConfiguration as PlatformIFilesConfiguration, FileChangeType, IFileService } from 'vs/platform/files/common/files'; import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; @@ -102,7 +102,7 @@ export const FILE_EDITOR_INPUT_ID = 'workbench.editors.files.fileEditorInput'; export const BINARY_FILE_EDITOR_ID = 'workbench.editors.files.binaryFileEditor'; -export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEditorConfiguration { +export interface IFilesConfiguration extends PlatformIFilesConfiguration, IWorkbenchEditorConfiguration { explorer: { openEditors: { visible: number; diff --git a/src/vs/workbench/services/files/common/workspaceWatcher.ts b/src/vs/workbench/contrib/files/common/workspaceWatcher.ts similarity index 91% rename from src/vs/workbench/services/files/common/workspaceWatcher.ts rename to src/vs/workbench/contrib/files/common/workspaceWatcher.ts index da8c120643a..661963d524a 100644 --- a/src/vs/workbench/services/files/common/workspaceWatcher.ts +++ b/src/vs/workbench/contrib/files/common/workspaceWatcher.ts @@ -7,10 +7,7 @@ import { IDisposable, Disposable, dispose } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IFilesConfiguration, IFileService } from 'vs/platform/files/common/files'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { ResourceMap } from 'vs/base/common/map'; import { onUnexpectedError } from 'vs/base/common/errors'; import { INotificationService, Severity, NeverShowAgainScope } from 'vs/platform/notification/common/notification'; @@ -110,7 +107,7 @@ export class WorkspaceWatcher extends Disposable { // Compute the watcher exclude rules from configuration const excludes: string[] = []; const config = this.configurationService.getValue({ resource }); - if (config.files && config.files.watcherExclude) { + if (config.files?.watcherExclude) { for (const key in config.files.watcherExclude) { if (config.files.watcherExclude[key] === true) { excludes.push(key); @@ -152,5 +149,3 @@ export class WorkspaceWatcher extends Disposable { this.unwatchWorkspaces(); } } - -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceWatcher, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts b/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts index b07175822e5..698fbb6acb9 100644 --- a/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts +++ b/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts @@ -38,7 +38,7 @@ export class NativeDirtyFilesTracker extends DirtyFilesTracker { super.onUntitledDidChangeDirty(resource); } - protected onTextFilesDirty(e: TextFileModelChangeEvent[]): void { + protected onTextFilesDirty(e: readonly TextFileModelChangeEvent[]): void { if ((this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) && !this.isDocumentedEdited) { this.updateDocumentEdited(); // no indication needed when auto save is enabled for short delay } @@ -46,7 +46,7 @@ export class NativeDirtyFilesTracker extends DirtyFilesTracker { super.onTextFilesDirty(e); } - protected onTextFilesSaved(e: TextFileModelChangeEvent[]): void { + protected onTextFilesSaved(e: readonly TextFileModelChangeEvent[]): void { if (this.isDocumentedEdited) { this.updateDocumentEdited(); } @@ -54,7 +54,7 @@ export class NativeDirtyFilesTracker extends DirtyFilesTracker { super.onTextFilesSaved(e); } - protected onTextFilesSaveError(e: TextFileModelChangeEvent[]): void { + protected onTextFilesSaveError(e: readonly TextFileModelChangeEvent[]): void { if (!this.isDocumentedEdited) { this.updateDocumentEdited(); } @@ -62,7 +62,7 @@ export class NativeDirtyFilesTracker extends DirtyFilesTracker { super.onTextFilesSaveError(e); } - protected onTextFilesReverted(e: TextFileModelChangeEvent[]): void { + protected onTextFilesReverted(e: readonly TextFileModelChangeEvent[]): void { if (this.isDocumentedEdited) { this.updateDocumentEdited(); } diff --git a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts index 20be6820e3f..dd9caef709a 100644 --- a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts @@ -18,9 +18,12 @@ import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/fi import { IListService } from 'vs/platform/list/browser/listService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { revealResourcesInOS } from 'vs/workbench/contrib/files/electron-browser/fileCommands'; -import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { MenuRegistry, MenuId, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { appendToCommandPalette, appendEditorTitleContextMenuItem } from 'vs/workbench/contrib/files/browser/fileActions.contribution'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; +import { ShowOpenedFileInNewWindow } from 'vs/workbench/contrib/files/browser/fileActions'; const REVEAL_IN_OS_COMMAND_ID = 'revealFileInOS'; const REVEAL_IN_OS_LABEL = isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder"); @@ -81,3 +84,6 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { const category = { value: nls.localize('filesCategory', "File"), original: 'File' }; appendToCommandPalette(REVEAL_IN_OS_COMMAND_ID, { value: REVEAL_IN_OS_LABEL, original: isWindows ? 'Reveal in Explorer' : isMacintosh ? 'Reveal in Finder' : 'Open Containing Folder' }, category); + +const registry = Registry.as(ActionExtensions.WorkbenchActions); +registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'File: Open Active File in New Window', category.value); diff --git a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts index bb715358319..18624e12e9a 100644 --- a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts @@ -10,7 +10,6 @@ import { EditorOptions } from 'vs/workbench/common/editor'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; import { MIN_MAX_MEMORY_SIZE_MB, FALLBACK_MAX_MEMORY_SIZE_MB } from 'vs/platform/files/node/files'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; -import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Action } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -22,7 +21,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IExplorerService } from 'vs/workbench/contrib/files/common/files'; import { IElectronService } from 'vs/platform/electron/node/electron'; @@ -46,19 +45,19 @@ export class NativeTextFileEditor extends TextFileEditor { @ITextFileService textFileService: ITextFileService, @IElectronService private readonly electronService: IElectronService, @IPreferencesService private readonly preferencesService: IPreferencesService, - @IWindowService windowService: IWindowService, + @IHostService hostService: IHostService, @IExplorerService explorerService: IExplorerService ) { - super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, windowService, explorerService); + super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService); } protected handleSetInputError(error: Error, input: FileEditorInput, options: EditorOptions | undefined): void { // Allow to restart with higher memory limit if the file is too large - if ((error).fileOperationResult === FileOperationResult.FILE_EXCEED_MEMORY_LIMIT) { + if ((error).fileOperationResult === FileOperationResult.FILE_EXCEEDS_MEMORY_LIMIT) { const memoryLimit = Math.max(MIN_MAX_MEMORY_SIZE_MB, +this.configurationService.getValue(undefined, 'files.maxMemoryForLargeFilesMB') || FALLBACK_MAX_MEMORY_SIZE_MB); - throw createErrorWithActions(toErrorMessage(error), { + throw createErrorWithActions(nls.localize('fileTooLargeForHeapError', "To open a file of this size, you need to restart and allow it to use more memory"), { actions: [ new Action('workbench.window.action.relaunchWithIncreasedMemoryLimit', nls.localize('relaunchWithIncreasedMemoryLimit', "Restart with {0} MB", memoryLimit), undefined, true, () => { return this.electronService.relaunch({ diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index 4b726da442f..9283054b31d 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts @@ -33,7 +33,7 @@ type FormattingEditProvider = DocumentFormattingEditProvider | DocumentRangeForm class DefaultFormatter extends Disposable implements IWorkbenchContribution { - static configName = 'editor.defaultFormatter'; + static readonly configName = 'editor.defaultFormatter'; static extensionIds: (string | null)[] = []; static extensionDescriptions: string[] = []; @@ -106,7 +106,7 @@ class DefaultFormatter extends Disposable implements IWorkbenchContribution { const langName = this._modeService.getLanguageName(document.getModeId()) || document.getModeId(); const silent = mode === FormattingMode.Silent; const message = !defaultFormatterId - ? nls.localize('config.needed', "There are multiple formatters for {0}-files. Select a default formatter to continue.", DefaultFormatter._maybeQuotes(langName)) + ? nls.localize('config.needed', "There are multiple formatters for '{0}' files. Select a default formatter to continue.", DefaultFormatter._maybeQuotes(langName)) : nls.localize('config.bad', "Extension '{0}' is configured as formatter but not available. Select a different default formatter to continue.", defaultFormatterId); return new Promise((resolve, reject) => { @@ -126,15 +126,15 @@ class DefaultFormatter extends Disposable implements IWorkbenchContribution { } private async _pickAndPersistDefaultFormatter(formatter: T[], document: ITextModel): Promise { - const picks = formatter.map((formatter, index) => { - return { + const picks = formatter.map((formatter, index): IIndexedPick => { + return { index, - label: formatter.displayName || formatter.extensionId || '?', + label: formatter.displayName || (formatter.extensionId ? formatter.extensionId.value : '?'), description: formatter.extensionId && formatter.extensionId.value }; }); const langName = this._modeService.getLanguageName(document.getModeId()) || document.getModeId(); - const pick = await this._quickInputService.pick(picks, { placeHolder: nls.localize('select', "Select a default formatter for {0}-files", DefaultFormatter._maybeQuotes(langName)) }); + const pick = await this._quickInputService.pick(picks, { placeHolder: nls.localize('select', "Select a default formatter for '{0}' files", DefaultFormatter._maybeQuotes(langName)) }); if (!pick || !formatter[pick.index].extensionId) { return undefined; } @@ -203,7 +203,7 @@ async function showFormatterPick(accessor: ServicesAccessor, model: ITextModel, const picks = formatters.map((provider, index) => { const isDefault = ExtensionIdentifier.equals(provider.extensionId, defaultFormatter); - const pick = { + const pick: IIndexedPick = { index, label: provider.displayName || '', description: isDefault ? nls.localize('def', "(default)") : undefined, @@ -234,7 +234,7 @@ async function showFormatterPick(accessor: ServicesAccessor, model: ITextModel, } else if (pick === configurePick) { // config default const langName = modeService.getLanguageName(model.getModeId()) || model.getModeId(); - const pick = await quickPickService.pick(picks, { placeHolder: nls.localize('select', "Select a default formatter for {0}-files", DefaultFormatter._maybeQuotes(langName)) }); + const pick = await quickPickService.pick(picks, { placeHolder: nls.localize('select', "Select a default formatter for '{0}' files", DefaultFormatter._maybeQuotes(langName)) }); if (pick && formatters[pick.index].extensionId) { configService.updateValue(DefaultFormatter.configName, formatters[pick.index].extensionId!.value, overrides); } diff --git a/src/vs/workbench/contrib/format/browser/formatActionsNone.ts b/src/vs/workbench/contrib/format/browser/formatActionsNone.ts index 6bce6be08ef..18b3e2b6f8d 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsNone.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsNone.ts @@ -50,7 +50,7 @@ registerEditorAction(class FormatDocumentMultipleAction extends EditorAction { return commandService.executeCommand('editor.action.formatDocument'); } else { const langName = model.getLanguageIdentifier().language; - const message = nls.localize('no.provider', "There is no formatter for '{0}'-files installed.", langName); + const message = nls.localize('no.provider', "There is no formatter for '{0}' files installed.", langName); const choice = { label: nls.localize('install.formatter', "Install Formatter..."), run: () => showExtensionQuery(viewletService, `category:formatters ${langName}`) diff --git a/src/vs/workbench/contrib/issue/browser/issue.contribution.ts b/src/vs/workbench/contrib/issue/browser/issue.contribution.ts new file mode 100644 index 00000000000..4be89357d7b --- /dev/null +++ b/src/vs/workbench/contrib/issue/browser/issue.contribution.ts @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ICommandAction, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { IWebIssueService, WebIssueService } from 'vs/workbench/contrib/issue/browser/issueService'; + +class RegisterIssueContribution implements IWorkbenchContribution { + + constructor(@IProductService readonly productService: IProductService) { + if (productService.reportIssueUrl) { + const helpCategory = { value: nls.localize('help', "Help"), original: 'Help' }; + const OpenIssueReporterActionId = 'workbench.action.openIssueReporter'; + const OpenIssueReporterActionLabel = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue"); + + CommandsRegistry.registerCommand(OpenIssueReporterActionId, function (accessor, args?: [string]) { + let extensionId: string | undefined; + if (args && Array.isArray(args)) { + [extensionId] = args; + } + + return accessor.get(IWebIssueService).openReporter({ extensionId }); + }); + + const command: ICommandAction = { + id: OpenIssueReporterActionId, + title: { value: OpenIssueReporterActionLabel, original: 'Report Issue' }, + category: helpCategory + }; + + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command }); + } + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(RegisterIssueContribution, LifecyclePhase.Starting); + +registerSingleton(IWebIssueService, WebIssueService, true); diff --git a/src/vs/workbench/contrib/issue/browser/issueService.ts b/src/vs/workbench/contrib/issue/browser/issueService.ts new file mode 100644 index 00000000000..daeb3fd7261 --- /dev/null +++ b/src/vs/workbench/contrib/issue/browser/issueService.ts @@ -0,0 +1,67 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { normalizeGitHubUrl } from 'vs/code/common/issue/issueReporterUtil'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IProductService } from 'vs/platform/product/common/productService'; + +export const IWebIssueService = createDecorator('webIssueService'); + +export interface IIssueReporterOptions { + extensionId?: string; +} + +export interface IWebIssueService { + _serviceBrand: undefined; + openReporter(options?: IIssueReporterOptions): Promise; +} + +export class WebIssueService implements IWebIssueService { + _serviceBrand: undefined; + + constructor( + @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, + @IOpenerService private readonly openerService: IOpenerService, + @IProductService private readonly productService: IProductService + ) { } + + async openReporter(options: IIssueReporterOptions): Promise { + let repositoryUrl = this.productService.reportIssueUrl; + if (options.extensionId) { + const extensionGitHubUrl = await this.getExtensionGitHubUrl(options.extensionId); + if (extensionGitHubUrl) { + repositoryUrl = extensionGitHubUrl + '/issues/new'; + } + } + + if (repositoryUrl) { + return this.openerService.open(URI.parse(repositoryUrl)).then(_ => { }); + } else { + throw new Error(`Unable to find issue reporting url for ${options.extensionId}`); + } + } + + private async getExtensionGitHubUrl(extensionId: string): Promise { + let repositoryUrl = ''; + + const extensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + const selectedExtension = extensions.filter(ext => ext.identifier.id === extensionId)[0]; + const bugsUrl = selectedExtension?.manifest.bugs?.url; + const extensionUrl = selectedExtension?.manifest.repository?.url; + + // If given, try to match the extension's bug url + if (bugsUrl && bugsUrl.match(/^https?:\/\/github\.com\/(.*)/)) { + repositoryUrl = normalizeGitHubUrl(bugsUrl); + } else if (extensionUrl && extensionUrl.match(/^https?:\/\/github\.com\/(.*)/)) { + repositoryUrl = normalizeGitHubUrl(extensionUrl); + } + + return repositoryUrl; + } +} diff --git a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts index d96fb5eee92..06b20c612ce 100644 --- a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts +++ b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts @@ -6,13 +6,11 @@ import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution, Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Disposable } from 'vs/base/common/lifecycle'; import { ConfigureLocaleAction } from 'vs/workbench/contrib/localizations/browser/localizationsActions'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { IExtensionManagementService, DidInstallExtensionEvent, IExtensionGalleryService, IGalleryExtension, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -35,7 +33,6 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureLocaleAction, export class LocalizationWorkbenchContribution extends Disposable implements IWorkbenchContribution { constructor( - @ILocalizationsService private readonly localizationService: ILocalizationsService, @INotificationService private readonly notificationService: INotificationService, @IJSONEditingService private readonly jsonEditingService: IJSONEditingService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @@ -47,26 +44,10 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo @ITelemetryService private readonly telemetryService: ITelemetryService ) { super(); - this.updateLocaleDefintionSchema(); this.checkAndInstall(); - this._register(this.localizationService.onDidLanguagesChange(() => this.updateLocaleDefintionSchema())); this._register(this.extensionManagementService.onDidInstallExtension(e => this.onDidInstallExtension(e))); } - private updateLocaleDefintionSchema(): void { - this.localizationService.getLanguageIds() - .then(languageIds => { - let lowercaseLanguageIds: string[] = []; - languageIds.forEach((languageId) => { - let lowercaseLanguageId = languageId.toLowerCase(); - if (lowercaseLanguageId !== languageId) { - lowercaseLanguageIds.push(lowercaseLanguageId); - } - }); - registerLocaleDefinitionSchema([...languageIds, ...lowercaseLanguageIds]); - }); - } - private onDidInstallExtension(e: DidInstallExtensionEvent): void { if (e.local && e.operation === InstallOperation.Install && e.local.manifest.contributes && e.local.manifest.contributes.localizations && e.local.manifest.contributes.localizations.length) { const locale = e.local.manifest.contributes.localizations[0].languageId; @@ -79,7 +60,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo [{ label: updateAndRestart ? localize('yes', "Yes") : localize('restart now', "Restart Now"), run: () => { - const updatePromise = updateAndRestart ? this.jsonEditingService.write(this.environmentService.localeResource, [{ key: 'locale', value: locale }], true) : Promise.resolve(undefined); + const updatePromise = updateAndRestart ? this.jsonEditingService.write(this.environmentService.argvResource, [{ key: 'locale', value: locale }], true) : Promise.resolve(undefined); updatePromise.then(() => this.hostService.restart(), e => this.notificationService.error(e)); } }], @@ -225,31 +206,6 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo } } -function registerLocaleDefinitionSchema(languages: string[]): void { - const localeDefinitionFileSchemaId = 'vscode://schemas/locale'; - const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); - // Keep en-US since we generated files with that content. - jsonRegistry.registerSchema(localeDefinitionFileSchemaId, { - id: localeDefinitionFileSchemaId, - allowComments: true, - allowTrailingCommas: true, - description: 'Locale Definition file', - type: 'object', - default: { - 'locale': 'en' - }, - required: ['locale'], - properties: { - locale: { - type: 'string', - enum: languages, - description: localize('JsonSchema.locale', 'The UI Language to use.') - } - } - }); -} - -registerLocaleDefinitionSchema(platform.language ? [platform.language] : []); const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(LocalizationWorkbenchContribution, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts b/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts index cd04dd6149c..928b73cd406 100644 --- a/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts +++ b/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts @@ -16,6 +16,7 @@ import { firstIndex } from 'vs/base/common/arrays'; import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IProductService } from 'vs/platform/product/common/productService'; export class ConfigureLocaleAction extends Action { public static readonly ID = 'workbench.action.configureLocale'; @@ -29,7 +30,8 @@ export class ConfigureLocaleAction extends Action { @IHostService private readonly hostService: IHostService, @INotificationService private readonly notificationService: INotificationService, @IViewletService private readonly viewletService: IViewletService, - @IDialogService private readonly dialogService: IDialogService + @IDialogService private readonly dialogService: IDialogService, + @IProductService private readonly productService: IProductService ) { super(id, label); } @@ -65,11 +67,11 @@ export class ConfigureLocaleAction extends Action { } if (selectedLanguage) { - await this.jsonEditingService.write(this.environmentService.localeResource, [{ key: 'locale', value: selectedLanguage.label }], true); + await this.jsonEditingService.write(this.environmentService.argvResource, [{ key: 'locale', value: selectedLanguage.label }], true); const restart = await this.dialogService.confirm({ type: 'info', message: localize('relaunchDisplayLanguageMessage', "A restart is required for the change in display language to take effect."), - detail: localize('relaunchDisplayLanguageDetail', "Press the restart button to restart {0} and change the display language.", this.environmentService.appNameLong), + detail: localize('relaunchDisplayLanguageDetail', "Press the restart button to restart {0} and change the display language.", this.productService.nameLong), primaryButton: localize('restart', "&&Restart") }); diff --git a/src/vs/workbench/contrib/logs/common/logConstants.ts b/src/vs/workbench/contrib/logs/common/logConstants.ts index e0d6d16c883..ca22b9947bc 100644 --- a/src/vs/workbench/contrib/logs/common/logConstants.ts +++ b/src/vs/workbench/contrib/logs/common/logConstants.ts @@ -7,4 +7,5 @@ export const mainLogChannelId = 'mainLog'; export const sharedLogChannelId = 'sharedLog'; export const rendererLogChannelId = 'rendererLog'; export const extHostLogChannelId = 'extHostLog'; -export const telemetryLogChannelId = 'telemetryLog'; \ No newline at end of file +export const telemetryLogChannelId = 'telemetryLog'; +export const userDataSyncLogChannelId = 'userDataSyncLog'; diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index ab29875c3c3..a85738f3351 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -22,6 +22,7 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { LogsDataCleaner } from 'vs/workbench/contrib/logs/common/logsDataCleaner'; +import { IProductService } from 'vs/platform/product/common/productService'; const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); const devCategory = nls.localize('developer', "Developer"); @@ -33,9 +34,11 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @ILogService private readonly logService: ILogService, @IFileService private readonly fileService: IFileService, - @IInstantiationService private readonly instantiationService: IInstantiationService + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IProductService private readonly productService: IProductService ) { super(); + this.registerCommonContributions(); if (isWeb) { this.registerWebContributions(); } else { @@ -43,19 +46,24 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { } } + private registerCommonContributions(): void { + if (this.productService.settingsSyncStoreUrl) { + this.registerLogChannel(Constants.userDataSyncLogChannelId, nls.localize('userDataSyncLog', "Configuration Sync"), this.environmentService.userDataSyncLogResource); + } + this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), this.environmentService.logFile); + } + private registerWebContributions(): void { - Registry.as(OutputExt.OutputChannels).registerChannel({ id: Constants.rendererLogChannelId, label: nls.localize('rendererLog', "Window"), file: this.environmentService.logFile, log: true }); this.instantiationService.createInstance(LogsDataCleaner); const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); const devCategory = nls.localize('developer', "Developer"); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWindowSessionLogFileAction, OpenWindowSessionLogFileAction.ID, OpenWindowSessionLogFileAction.LABEL), 'Developer: Open Browser Log File (Session)...', devCategory); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWindowSessionLogFileAction, OpenWindowSessionLogFileAction.ID, OpenWindowSessionLogFileAction.LABEL), 'Developer: Open Window Log File (Session)...', devCategory); } private registerNativeContributions(): void { this.registerLogChannel(Constants.mainLogChannelId, nls.localize('mainLog', "Main"), URI.file(join(this.environmentService.logsPath, `main.log`))); this.registerLogChannel(Constants.sharedLogChannelId, nls.localize('sharedLog', "Shared"), URI.file(join(this.environmentService.logsPath, `sharedprocess.log`))); - this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), this.environmentService.logFile); const registerTelemetryChannel = (level: LogLevel) => { if (level === LogLevel.Trace && !Registry.as(OutputExt.OutputChannels).getChannel(Constants.telemetryLogChannelId)) { @@ -76,7 +84,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { const watcher = this.fileService.watch(dirname(file)); const disposable = this.fileService.onFileChanges(e => { - if (e.contains(file, FileChangeType.ADDED)) { + if (e.contains(file, FileChangeType.ADDED) || e.contains(file, FileChangeType.UPDATED)) { watcher.dispose(); disposable.dispose(); outputChannelRegistry.registerChannel({ id, label, file, log: true }); diff --git a/src/vs/workbench/contrib/logs/common/logsActions.ts b/src/vs/workbench/contrib/logs/common/logsActions.ts index 34e9eed4475..625a8d7836a 100644 --- a/src/vs/workbench/contrib/logs/common/logsActions.ts +++ b/src/vs/workbench/contrib/logs/common/logsActions.ts @@ -15,8 +15,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic export class SetLogLevelAction extends Action { - static ID = 'workbench.action.setLogLevel'; - static LABEL = nls.localize('setLogLevel', "Set Log Level..."); + static readonly ID = 'workbench.action.setLogLevel'; + static readonly LABEL = nls.localize('setLogLevel', "Set Log Level..."); constructor(id: string, label: string, @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -60,8 +60,8 @@ export class SetLogLevelAction extends Action { export class OpenWindowSessionLogFileAction extends Action { - static ID = 'workbench.action.openSessionLogFile'; - static LABEL = nls.localize('openSessionLogFile', "Open Window Log File (Session)..."); + static readonly ID = 'workbench.action.openSessionLogFile'; + static readonly LABEL = nls.localize('openSessionLogFile', "Open Window Log File (Session)..."); constructor(id: string, label: string, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, diff --git a/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts b/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts index 547558b7deb..f2287b85265 100644 --- a/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts +++ b/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts @@ -12,8 +12,8 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; export class OpenLogsFolderAction extends Action { - static ID = 'workbench.action.openLogsFolder'; - static LABEL = nls.localize('openLogsFolder', "Open Logs Folder"); + static readonly ID = 'workbench.action.openLogsFolder'; + static readonly LABEL = nls.localize('openLogsFolder', "Open Logs Folder"); constructor(id: string, label: string, @IEnvironmentService private readonly environmentService: IEnvironmentService, diff --git a/src/vs/workbench/common/markdownDocumentRenderer.ts b/src/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts similarity index 100% rename from src/vs/workbench/common/markdownDocumentRenderer.ts rename to src/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 3a31ebe7ade..e08a13a559f 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -26,7 +26,7 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ActivePanelContext } from 'vs/workbench/common/panel'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; diff --git a/src/vs/workbench/contrib/markers/browser/markers.ts b/src/vs/workbench/contrib/markers/browser/markers.ts index 47bebfa187f..caa76b05903 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.ts @@ -38,10 +38,10 @@ export class MarkersWorkbenchService extends Disposable implements IMarkersWorkb @IInstantiationService instantiationService: IInstantiationService, ) { super(); - this.markersModel = this._register(instantiationService.createInstance(MarkersModel, this.readMarkers())); + this.markersModel = this._register(instantiationService.createInstance(MarkersModel)); this.markersModel.setResourceMarkers(groupBy(this.readMarkers(), compareMarkersByUri).map(group => [group[0].resource, group])); - this._register(Event.debounce>(markerService.onMarkerChanged, (resourcesMap, resources) => { + this._register(Event.debounce>(markerService.onMarkerChanged, (resourcesMap, resources) => { resourcesMap = resourcesMap ? resourcesMap : new ResourceMap(); resources.forEach(resource => resourcesMap!.set(resource, resource)); return resourcesMap; diff --git a/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts b/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts index 7c13cb5575e..c6eea1a6b89 100644 --- a/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts +++ b/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts @@ -19,7 +19,7 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; class MarkersDecorationsProvider implements IDecorationsProvider { readonly label: string = localize('label', "Problems"); - readonly onDidChange: Event; + readonly onDidChange: Event; constructor( private readonly _markerService: IMarkerService diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index bbc4392c7f7..c509e857100 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -117,7 +117,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations)); // actions - this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => this.collapseAll())); + this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action codicon-collapse-all', true, async () => this.collapseAll())); this.filterAction = this._register(this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], useFilesExclude: !!this.panelState['useFilesExclude'] })); } @@ -341,11 +341,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { markerFocusContextKey.set(focus.elements.some(e => e instanceof Marker)); relatedInformationFocusContextKey.set(focus.elements.some(e => e instanceof RelatedInformation)); })); - const focusTracker = this._register(dom.trackFocus(this.tree.getHTMLElement())); - this._register(focusTracker.onDidBlur(() => { - markerFocusContextKey.set(false); - relatedInformationFocusContextKey.set(false); - })); const markersNavigator = this._register(new TreeResourceNavigator2(this.tree, { openOnFocus: true })); this._register(Event.debounce(markersNavigator.onDidOpenResource, (last, event) => event, 75, true)(options => { diff --git a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts index b2498c05d82..cfba514af3f 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts @@ -196,14 +196,14 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { private createBadge(container: HTMLElement): void { const filterBadge = this.filterBadge = DOM.append(container, DOM.$('.markers-panel-filter-badge')); this._register(attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { - const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; - const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : null; - const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; + const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; + const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : ''; + const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; filterBadge.style.backgroundColor = background; - filterBadge.style.borderWidth = border ? '1px' : null; - filterBadge.style.borderStyle = border ? 'solid' : null; + filterBadge.style.borderWidth = border ? '1px' : ''; + filterBadge.style.borderStyle = border ? 'solid' : ''; filterBadge.style.borderColor = border; filterBadge.style.color = foreground; })); diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index 90158388b30..a379c7bb58a 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -254,7 +254,7 @@ class MarkerWidget extends Disposable { ) { super(); this.actionBar = this._register(new ActionBar(dom.append(parent, dom.$('.actions')), { - actionViewItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionViewItem, action) : undefined + actionViewItemProvider: (action: QuickFixAction) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionViewItem, action) : undefined })); this.icon = dom.append(parent, dom.$('')); this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions')))); @@ -267,7 +267,7 @@ class MarkerWidget extends Disposable { this.disposables.clear(); dom.clearNode(this.messageAndDetailsContainer); - this.icon.className = `marker-icon ${SeverityIcon.className(MarkerSeverity.toSeverity(element.marker.severity))}`; + this.icon.className = `marker-icon codicon ${SeverityIcon.className(MarkerSeverity.toSeverity(element.marker.severity))}`; this.renderQuickfixActionbar(element); this.renderMultilineActionbar(element); @@ -302,7 +302,7 @@ class MarkerWidget extends Disposable { const action = new Action('problems.action.toggleMultiline'); action.enabled = !!viewModel && marker.lines.length > 1; action.tooltip = multiline ? localize('single line', "Show message in single line") : localize('multi line', "Show message in multiple lines"); - action.class = multiline ? 'octicon octicon-chevron-up' : 'octicon octicon-chevron-down'; + action.class = multiline ? 'codicon codicon-chevron-up' : 'codicon codicon-chevron-down'; action.run = () => { if (viewModel) { viewModel.multiline = !viewModel.multiline; } return Promise.resolve(); }; this.multilineActionbar.push([action], { icon: true, label: false }); } diff --git a/src/vs/workbench/contrib/markers/browser/media/markers.css b/src/vs/workbench/contrib/markers/browser/media/markers.css index cdec9f47999..cf54727d396 100644 --- a/src/vs/workbench/contrib/markers/browser/media/markers.css +++ b/src/vs/workbench/contrib/markers/browser/media/markers.css @@ -132,9 +132,15 @@ margin-left: 6px; } -.markers-panel .monaco-tl-contents .marker-icon, -.markers-panel .monaco-tl-contents .actions .action-item { +.markers-panel .monaco-tl-contents .marker-icon { margin-right: 6px; + display: flex; + align-items: center; + justify-content: center; +} + +.markers-panel .monaco-tl-contents .actions .action-item { + margin-right: 2px; } .markers-panel .markers-panel-container .tree-container .monaco-tl-contents .marker-source, diff --git a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts index 57cda74ad2d..494add53bf1 100644 --- a/src/vs/workbench/contrib/outline/browser/outline.contribution.ts +++ b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts @@ -50,6 +50,136 @@ Registry.as(ConfigurationExtensions.Configuration).regis 'description': localize('outline.problems.badges', "Use badges for Errors & Warnings."), 'type': 'boolean', 'default': true + }, + 'outline.showFiles': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.file', "When enabled outline shows `file`-symbols.") + }, + 'outline.showModules': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.module', "When enabled outline shows `module`-symbols.") + }, + 'outline.showNamespaces': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.namespace', "When enabled outline shows `namespace`-symbols.") + }, + 'outline.showPackages': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.package', "When enabled outline shows `package`-symbols.") + }, + 'outline.showClasses': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.class', "When enabled outline shows `class`-symbols.") + }, + 'outline.showMethods': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.method', "When enabled outline shows `method`-symbols.") + }, + 'outline.showProperties': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.property', "When enabled outline shows `property`-symbols.") + }, + 'outline.showFields': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.field', "When enabled outline shows `field`-symbols.") + }, + 'outline.showConstructors': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.constructor', "When enabled outline shows `constructor`-symbols.") + }, + 'outline.showEnums': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.enum', "When enabled outline shows `enum`-symbols.") + }, + 'outline.showInterfaces': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.interface', "When enabled outline shows `interface`-symbols.") + }, + 'outline.showFunctions': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.function', "When enabled outline shows `function`-symbols.") + }, + 'outline.showVariables': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.variable', "When enabled outline shows `variable`-symbols.") + }, + 'outline.showConstants': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.constant', "When enabled outline shows `constant`-symbols.") + }, + 'outline.showStrings': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.string', "When enabled outline shows `string`-symbols.") + }, + 'outline.showNumbers': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.number', "When enabled outline shows `number`-symbols.") + }, + 'outline.showBooleans': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.boolean', "When enabled outline shows `boolean`-symbols.") + }, + 'outline.showArrays': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.array', "When enabled outline shows `array`-symbols.") + }, + 'outline.showObjects': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.object', "When enabled outline shows `object`-symbols.") + }, + 'outline.showKeys': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.key', "When enabled outline shows `key`-symbols.") + }, + 'outline.showNull': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.null', "When enabled outline shows `null`-symbols.") + }, + 'outline.showEnumMembers': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.enumMember', "When enabled outline shows `enumMember`-symbols.") + }, + 'outline.showStructs': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.struct', "When enabled outline shows `struct`-symbols.") + }, + 'outline.showEvents': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.event', "When enabled outline shows `event`-symbols.") + }, + 'outline.showOperators': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.operator', "When enabled outline shows `operator`-symbols.") + }, + 'outline.showTypeParameters': { + type: 'boolean', + default: true, + markdownDescription: localize('filteredTypes.typeParameter', "When enabled outline shows `typeParameter`-symbols.") } } }); diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index 9ee2c27c02d..bf6ab98899a 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -40,7 +40,7 @@ import { CollapseAction } from 'vs/workbench/browser/viewlet'; import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { OutlineConfigKeys, OutlineViewFocused, OutlineViewFiltered } from 'vs/editor/contrib/documentSymbols/outline'; import { FuzzyScore } from 'vs/base/common/filters'; -import { OutlineDataSource, OutlineItemComparator, OutlineSortOrder, OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItem, OutlineIdentityProvider, OutlineNavigationLabelProvider } from 'vs/editor/contrib/documentSymbols/outlineTree'; +import { OutlineDataSource, OutlineItemComparator, OutlineSortOrder, OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItem, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineFilter } from 'vs/editor/contrib/documentSymbols/outlineTree'; import { IDataTreeViewState } from 'vs/base/browser/ui/tree/dataTree'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { basename } from 'vs/base/common/resources'; @@ -247,10 +247,9 @@ export class OutlinePanel extends ViewletPanel { private _treeDataSource!: OutlineDataSource; private _treeRenderer!: OutlineElementRenderer; private _treeComparator!: OutlineItemComparator; + private _treeFilter!: OutlineFilter; private _treeStates = new LRUCache(10); - private _treeFakeUIEvent = new UIEvent('me'); - private readonly _contextKeyFocused: IContextKey; private readonly _contextKeyFiltered: IContextKey; @@ -315,6 +314,7 @@ export class OutlinePanel extends ViewletPanel { this._treeRenderer = this._instantiationService.createInstance(OutlineElementRenderer); this._treeDataSource = new OutlineDataSource(); this._treeComparator = new OutlineItemComparator(this._outlineViewState.sortBy); + this._treeFilter = this._instantiationService.createInstance(OutlineFilter, 'outline'); this._tree = this._instantiationService.createInstance( WorkbenchDataTree, 'OutlinePanel', @@ -328,8 +328,10 @@ export class OutlinePanel extends ViewletPanel { multipleSelectionSupport: false, filterOnType: this._outlineViewState.filterOnType, sorter: this._treeComparator, + filter: this._treeFilter, identityProvider: new OutlineIdentityProvider(), - keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider() + keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider(), + hideTwistiesOfChildlessElements: true } ); @@ -366,6 +368,10 @@ export class OutlinePanel extends ViewletPanel { if (e.affectsConfiguration(OutlineConfigKeys.icons)) { this._tree.updateChildren(); } + if (e.affectsConfiguration('outline')) { + this._treeFilter.update(); + this._tree.refilter(); + } })); this._register(this.onDidChangeBodyVisibility(visible => { @@ -395,7 +401,7 @@ export class OutlinePanel extends ViewletPanel { const group = this._register(new RadioGroup([ new SimpleToggleAction(this._outlineViewState, localize('sortByPosition', "Sort By: Position"), () => this._outlineViewState.sortBy === OutlineSortOrder.ByPosition, _ => this._outlineViewState.sortBy = OutlineSortOrder.ByPosition), new SimpleToggleAction(this._outlineViewState, localize('sortByName', "Sort By: Name"), () => this._outlineViewState.sortBy === OutlineSortOrder.ByName, _ => this._outlineViewState.sortBy = OutlineSortOrder.ByName), - new SimpleToggleAction(this._outlineViewState, localize('sortByKind', "Sort By: Type"), () => this._outlineViewState.sortBy === OutlineSortOrder.ByKind, _ => this._outlineViewState.sortBy = OutlineSortOrder.ByKind), + new SimpleToggleAction(this._outlineViewState, localize('sortByKind', "Sort By: Category"), () => this._outlineViewState.sortBy === OutlineSortOrder.ByKind, _ => this._outlineViewState.sortBy = OutlineSortOrder.ByKind), ])); const result = [ new SimpleToggleAction(this._outlineViewState, localize('followCur', "Follow Cursor"), () => this._outlineViewState.followCursor, action => this._outlineViewState.followCursor = action.checked), @@ -447,7 +453,6 @@ export class OutlinePanel extends ViewletPanel { private async _doUpdate(editor: ICodeEditor | undefined, event: IModelContentChangedEvent | undefined): Promise { this._editorDisposables.clear(); - this._progressBar.infinite().show(150); const oldModel = this._tree.getInput(); @@ -460,16 +465,16 @@ export class OutlinePanel extends ViewletPanel { return this._showMessage(localize('no-editor', "The active editor cannot provide outline information.")); } - let textModel = editor.getModel(); - let loadingMessage: IDisposable | undefined; - if (!oldModel) { - loadingMessage = new TimeoutTimer( - () => this._showMessage(localize('loading', "Loading document symbols for '{0}'...", basename(textModel.uri))), - 100 - ); - } + const textModel = editor.getModel(); + const loadingMessage = oldModel && new TimeoutTimer( + () => this._showMessage(localize('loading', "Loading document symbols for '{0}'...", basename(textModel.uri))), + 100 + ); - let createdModel = await OutlinePanel._createOutlineModel(textModel, this._editorDisposables); + const requestDelay = OutlineModel.getRequestDelay(textModel); + this._progressBar.infinite().show(requestDelay); + + const createdModel = await OutlinePanel._createOutlineModel(textModel, this._editorDisposables); dispose(loadingMessage); if (!createdModel) { return; @@ -519,7 +524,7 @@ export class OutlinePanel extends ViewletPanel { newModel = oldModel; } else { let state = this._treeStates.get(newModel.textModel.uri.toString()); - await this._tree.setInput(newModel, state); + this._tree.setInput(newModel, state); } // transfer focus from domNode to the tree @@ -531,10 +536,8 @@ export class OutlinePanel extends ViewletPanel { // feature: reveal outline selection in editor // on change -> reveal/select defining range - this._editorDisposables.add(this._tree.onDidChangeSelection(e => { - if (e.browserEvent === this._treeFakeUIEvent /* || e.payload && e.payload.didClickOnTwistie */) { - return; - } + this._editorDisposables.add(this._tree.onDidOpen(e => { + let [first] = e.elements; if (!(first instanceof OutlineElement)) { return; @@ -636,7 +639,7 @@ export class OutlinePanel extends ViewletPanel { if (top === null) { this._tree.reveal(item, 0.5); } - this._tree.setFocus([item], this._treeFakeUIEvent); - this._tree.setSelection([item], this._treeFakeUIEvent); + this._tree.setFocus([item]); + this._tree.setSelection([item]); } } diff --git a/src/vs/workbench/contrib/output/browser/logViewer.ts b/src/vs/workbench/contrib/output/browser/logViewer.ts index c1bbbd2f7c0..ce500dfe4a3 100644 --- a/src/vs/workbench/contrib/output/browser/logViewer.ts +++ b/src/vs/workbench/contrib/output/browser/logViewer.ts @@ -19,13 +19,13 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { LOG_SCHEME, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/output/common/output'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; export class LogViewerInput extends ResourceEditorInput { public static readonly ID = 'workbench.editorinputs.output'; - constructor(private outputChannelDescriptor: IFileOutputChannelDescriptor, + constructor(private readonly outputChannelDescriptor: IFileOutputChannelDescriptor, @ITextModelService textModelResolverService: ITextModelService ) { super(basename(outputChannelDescriptor.file.path), dirname(outputChannelDescriptor.file.path), URI.from({ scheme: LOG_SCHEME, path: outputChannelDescriptor.id }), undefined, textModelResolverService); @@ -54,9 +54,9 @@ export class LogViewer extends AbstractTextResourceEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IWindowService windowService: IWindowService + @IHostService hostService: IHostService ) { - super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, windowService); + super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService); } protected getConfigurationOverrides(): IEditorOptions { diff --git a/src/vs/workbench/contrib/output/browser/outputActions.ts b/src/vs/workbench/contrib/output/browser/outputActions.ts index 3760d018bf5..869b8da42d6 100644 --- a/src/vs/workbench/contrib/output/browser/outputActions.ts +++ b/src/vs/workbench/contrib/output/browser/outputActions.ts @@ -21,6 +21,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { LogViewerInput } from 'vs/workbench/contrib/output/browser/logViewer'; import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; +import { assertIsDefined } from 'vs/base/common/types'; export class ToggleOutputAction extends TogglePanelAction { @@ -213,8 +214,8 @@ export class OpenLogOutputFile extends Action { export class ShowLogsOutputChannelAction extends Action { - static ID = 'workbench.action.showLogs'; - static LABEL = nls.localize('showLogs', "Show Logs..."); + static readonly ID = 'workbench.action.showLogs'; + static readonly LABEL = nls.localize('showLogs', "Show Logs..."); constructor(id: string, label: string, @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -243,8 +244,8 @@ interface IOutputChannelQuickPickItem extends IQuickPickItem { export class OpenOutputLogFileAction extends Action { - static ID = 'workbench.action.openLogFile'; - static LABEL = nls.localize('openLogFile', "Open Log File..."); + static readonly ID = 'workbench.action.openLogFile'; + static readonly LABEL = nls.localize('openLogFile', "Open Log File..."); constructor(id: string, label: string, @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -262,7 +263,8 @@ export class OpenOutputLogFileAction extends Action { return this.quickInputService.pick(entries, { placeHolder: nls.localize('selectlogFile', "Select Log file") }) .then(entry => { if (entry) { - return this.editorService.openEditor(this.instantiationService.createInstance(LogViewerInput, entry.channel)).then(() => undefined); + assertIsDefined(entry.channel.file); + return this.editorService.openEditor(this.instantiationService.createInstance(LogViewerInput, entry.channel as IFileOutputChannelDescriptor)).then(() => undefined); } return undefined; }); diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index 9f58f043851..d9eeefed511 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -24,7 +24,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; export class OutputPanel extends AbstractTextResourceEditor { @@ -44,9 +44,9 @@ export class OutputPanel extends AbstractTextResourceEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IWindowService windowService: IWindowService + @IHostService hostService: IHostService ) { - super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, windowService); + super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService); this.scopedInstantiationService = instantiationService; } diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index 1a3e692d6e7..940441708e4 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -155,7 +155,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo } } - private onDidPanelOpen(panel: IPanel | null, preserveFocus: boolean): Promise { + private onDidPanelOpen(panel: IPanel | undefined, preserveFocus: boolean): Promise { if (panel && panel.getId() === OUTPUT_PANEL_ID) { this._outputPanel = this.panelService.getActivePanel(); if (this.activeChannel) { diff --git a/src/vs/workbench/contrib/output/common/outputLinkComputer.ts b/src/vs/workbench/contrib/output/common/outputLinkComputer.ts index ee681d2dccf..b61cccb5e95 100644 --- a/src/vs/workbench/contrib/output/common/outputLinkComputer.ts +++ b/src/vs/workbench/contrib/output/common/outputLinkComputer.ts @@ -12,6 +12,7 @@ import * as strings from 'vs/base/common/strings'; import { Range } from 'vs/editor/common/core/range'; import { isWindows } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; +import { find } from 'vs/base/common/arrays'; export interface ICreateData { workspaceFolders: string[]; @@ -44,15 +45,9 @@ export class OutputLinkComputer { }); } - private getModel(uri: string): IMirrorModel | null { + private getModel(uri: string): IMirrorModel | undefined { const models = this.ctx.getMirrorModels(); - for (const model of models) { - if (model.uri.toString() === uri) { - return model; - } - } - - return null; + return find(models, model => model.uri.toString() === uri); } public computeLinks(uri: string): Promise { diff --git a/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts index e4039966c6e..fb206077648 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts @@ -18,6 +18,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { URI } from 'vs/base/common/uri'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IProductService } from 'vs/platform/product/common/productService'; export class StartupProfiler implements IWorkbenchContribution { @@ -29,7 +30,8 @@ export class StartupProfiler implements IWorkbenchContribution { @ILifecycleService lifecycleService: ILifecycleService, @IExtensionService extensionService: IExtensionService, @IOpenerService private readonly _openerService: IOpenerService, - @IElectronService private readonly _electronService: IElectronService + @IElectronService private readonly _electronService: IElectronService, + @IProductService private readonly _productService: IProductService ) { // wait for everything to be ready Promise.all([ @@ -88,7 +90,7 @@ export class StartupProfiler implements IWorkbenchContribution { return this._dialogService.confirm({ type: 'info', message: localize('prof.thanks', "Thanks for helping us."), - detail: localize('prof.detail.restart', "A final restart is required to continue to use '{0}'. Again, thank you for your contribution.", this._environmentService.appNameLong), + detail: localize('prof.detail.restart', "A final restart is required to continue to use '{0}'. Again, thank you for your contribution.", this._productService.nameLong), primaryButton: localize('prof.restart', "Restart"), secondaryButton: undefined }).then(() => { diff --git a/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts b/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts index 2a945fc8e68..789a38d7dbb 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts @@ -21,7 +21,6 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { didUseCachedData, ITimerService } from 'vs/workbench/services/timer/electron-browser/timerService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { getEntries } from 'vs/base/common/performance'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; export class StartupTimings implements IWorkbenchContribution { @@ -34,8 +33,7 @@ export class StartupTimings implements IWorkbenchContribution { @ITelemetryService private readonly _telemetryService: ITelemetryService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IUpdateService private readonly _updateService: IUpdateService, - @IEnvironmentService private readonly _envService: IEnvironmentService, - @IHostService private readonly _hostService: IHostService + @IEnvironmentService private readonly _envService: IEnvironmentService ) { // this._report().catch(onUnexpectedError); @@ -93,7 +91,7 @@ export class StartupTimings implements IWorkbenchContribution { if (this._lifecycleService.startupKind !== StartupKind.NewWindow) { return false; } - if (await this._hostService.windowCount !== 1) { + if (await this._electronService.getWindowCount() !== 1) { return false; } const activeViewlet = this._viewletService.getActiveViewlet(); diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts b/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts index 81433e42323..4002fe6e377 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts @@ -59,6 +59,9 @@ export class KeybindingsSearchWidget extends SearchWidget { super(parent, options, contextViewService, instantiationService, themeService); this._register(attachInputBoxStyler(this.inputBox, themeService)); this._register(toDisposable(() => this.stopRecordingKeys())); + this._firstPart = null; + this._chordPart = null; + this._inputValue = ''; this._reset(); } @@ -161,12 +164,50 @@ export class DefineKeybindingWidget extends Widget { readonly onShowExistingKeybidings: Event = this._onShowExistingKeybindings.event; constructor( - parent: HTMLElement, + parent: HTMLElement | null, @IInstantiationService private readonly instantiationService: IInstantiationService, @IThemeService private readonly themeService: IThemeService ) { super(); - this.create(); + + this._domNode = createFastDomNode(document.createElement('div')); + this._domNode.setDisplay('none'); + this._domNode.setClassName('defineKeybindingWidget'); + this._domNode.setWidth(DefineKeybindingWidget.WIDTH); + this._domNode.setHeight(DefineKeybindingWidget.HEIGHT); + + const message = nls.localize('defineKeybinding.initial', "Press desired key combination and then press ENTER."); + dom.append(this._domNode.domNode, dom.$('.message', undefined, message)); + + this._register(attachStylerCallback(this.themeService, { editorWidgetBackground, editorWidgetForeground, widgetShadow }, colors => { + if (colors.editorWidgetBackground) { + this._domNode.domNode.style.backgroundColor = colors.editorWidgetBackground.toString(); + } else { + this._domNode.domNode.style.backgroundColor = ''; + } + if (colors.editorWidgetForeground) { + this._domNode.domNode.style.color = colors.editorWidgetForeground.toString(); + } else { + this._domNode.domNode.style.color = null; + } + + if (colors.widgetShadow) { + this._domNode.domNode.style.boxShadow = `0 2px 8px ${colors.widgetShadow}`; + } else { + this._domNode.domNode.style.boxShadow = ''; + } + })); + + this._keybindingInputWidget = this._register(this.instantiationService.createInstance(KeybindingsSearchWidget, this._domNode.domNode, { ariaLabel: message })); + this._keybindingInputWidget.startRecordingKeys(); + this._register(this._keybindingInputWidget.onKeybinding(keybinding => this.onKeybinding(keybinding))); + this._register(this._keybindingInputWidget.onEnter(() => this.hide())); + this._register(this._keybindingInputWidget.onEscape(() => this.onCancel())); + this._register(this._keybindingInputWidget.onBlur(() => this.onCancel())); + + this._outputNode = dom.append(this._domNode.domNode, dom.$('.output')); + this._showExistingKeybindingsNode = dom.append(this._domNode.domNode, dom.$('.existing')); + if (parent) { dom.append(parent, this._domNode.domNode); } @@ -217,46 +258,6 @@ export class DefineKeybindingWidget extends Widget { } } - private create(): void { - this._domNode = createFastDomNode(document.createElement('div')); - this._domNode.setDisplay('none'); - this._domNode.setClassName('defineKeybindingWidget'); - this._domNode.setWidth(DefineKeybindingWidget.WIDTH); - this._domNode.setHeight(DefineKeybindingWidget.HEIGHT); - - const message = nls.localize('defineKeybinding.initial', "Press desired key combination and then press ENTER."); - dom.append(this._domNode.domNode, dom.$('.message', undefined, message)); - - this._register(attachStylerCallback(this.themeService, { editorWidgetBackground, editorWidgetForeground, widgetShadow }, colors => { - if (colors.editorWidgetBackground) { - this._domNode.domNode.style.backgroundColor = colors.editorWidgetBackground.toString(); - } else { - this._domNode.domNode.style.backgroundColor = null; - } - if (colors.editorWidgetForeground) { - this._domNode.domNode.style.color = colors.editorWidgetForeground.toString(); - } else { - this._domNode.domNode.style.color = null; - } - - if (colors.widgetShadow) { - this._domNode.domNode.style.boxShadow = `0 2px 8px ${colors.widgetShadow}`; - } else { - this._domNode.domNode.style.boxShadow = null; - } - })); - - this._keybindingInputWidget = this._register(this.instantiationService.createInstance(KeybindingsSearchWidget, this._domNode.domNode, { ariaLabel: message })); - this._keybindingInputWidget.startRecordingKeys(); - this._register(this._keybindingInputWidget.onKeybinding(keybinding => this.onKeybinding(keybinding))); - this._register(this._keybindingInputWidget.onEnter(() => this.hide())); - this._register(this._keybindingInputWidget.onEscape(() => this.onCancel())); - this._register(this._keybindingInputWidget.onBlur(() => this.onCancel())); - - this._outputNode = dom.append(this._domNode.domNode, dom.$('.output')); - this._showExistingKeybindingsNode = dom.append(this._domNode.domNode, dom.$('.existing')); - } - private onKeybinding(keybinding: [ResolvedKeybinding | null, ResolvedKeybinding | null]): void { const [firstPart, chordPart] = keybinding; this._firstPart = firstPart; diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 304a9dbf686..4169b1d34bb 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -29,7 +29,6 @@ import { } from 'vs/workbench/contrib/preferences/common/preferences'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; -import { List } from 'vs/base/browser/ui/list/listWidget'; import { IListVirtualDelegate, IListRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -79,7 +78,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private keybindingsListContainer: HTMLElement; private unAssignedKeybindingItemToRevealAndFocus: IKeybindingItemEntry | null; private listEntries: IListEntry[]; - private keybindingsList: List; + private keybindingsList: WorkbenchList; private dimension: DOM.Dimension; private delayedFiltering: Delayer; @@ -317,7 +316,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor const fullTextSearchPlaceholder = localize('SearchKeybindings.FullTextSearchPlaceholder', "Type to search in keybindings"); const keybindingsSearchPlaceholder = localize('SearchKeybindings.KeybindingsSearchPlaceholder', "Recording Keys. Press Escape to exit"); - const clearInputAction = new Action(KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, localize('clearInput', "Clear Keybindings Search Input"), 'clear-input', false, () => { this.search(''); return Promise.resolve(null); }); + const clearInputAction = new Action(KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, localize('clearInput', "Clear Keybindings Search Input"), 'codicon-clear-all', false, () => { this.search(''); return Promise.resolve(null); }); const searchContainer = DOM.append(this.headerContainer, $('.search-container')); this.searchWidget = this._register(this.instantiationService.createInstance(KeybindingsSearchWidget, searchContainer, { @@ -340,7 +339,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor const sortByPrecedenceActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE); const sortByPrecedenceActionLabel = localize('sortByPrecedeneLabel', "Sort by Precedence"); - this.sortByPrecedenceAction = new Action('keybindings.editor.sortByPrecedence', sortByPrecedenceActionKeybinding ? localize('sortByPrecedeneLabelWithKeybinding', "{0} ({1})", sortByPrecedenceActionLabel, sortByPrecedenceActionKeybinding.getLabel()) : sortByPrecedenceActionLabel, 'sort-by-precedence'); + this.sortByPrecedenceAction = new Action('keybindings.editor.sortByPrecedence', sortByPrecedenceActionKeybinding ? localize('sortByPrecedeneLabelWithKeybinding', "{0} ({1})", sortByPrecedenceActionLabel, sortByPrecedenceActionKeybinding.getLabel()) : sortByPrecedenceActionLabel, 'codicon-sort-precedence'); this.sortByPrecedenceAction.checked = false; this._register(this.sortByPrecedenceAction.onDidChange(e => { if (e.checked !== undefined) { @@ -351,7 +350,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor const recordKeysActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS); const recordKeysActionLabel = localize('recordKeysLabel', "Record Keys"); - this.recordKeysAction = new Action(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, recordKeysActionKeybinding ? localize('recordKeysLabelWithKeybinding', "{0} ({1})", recordKeysActionLabel, recordKeysActionKeybinding.getLabel()) : recordKeysActionLabel, 'record-keys'); + this.recordKeysAction = new Action(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, recordKeysActionKeybinding ? localize('recordKeysLabelWithKeybinding', "{0} ({1})", recordKeysActionLabel, recordKeysActionKeybinding.getLabel()) : recordKeysActionLabel, 'codicon-record-keys'); this.recordKeysAction.checked = false; this._register(this.recordKeysAction.onDidChange(e => { if (e.checked !== undefined) { @@ -402,13 +401,13 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor const recordingBadge = DOM.append(container, DOM.$('.recording-badge.disabled')); recordingBadge.textContent = localize('recording', "Recording Keys"); this._register(attachStylerCallback(this.themeService, { badgeBackground, contrastBorder, badgeForeground }, colors => { - const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; - const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; - const color = colors.badgeForeground ? colors.badgeForeground.toString() : null; + const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; + const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; + const color = colors.badgeForeground ? colors.badgeForeground.toString() : ''; recordingBadge.style.backgroundColor = background; - recordingBadge.style.borderWidth = border ? '1px' : null; - recordingBadge.style.borderStyle = border ? 'solid' : null; + recordingBadge.style.borderWidth = border ? '1px' : ''; + recordingBadge.style.borderStyle = border ? 'solid' : ''; recordingBadge.style.borderColor = border; recordingBadge.style.color = color ? color.toString() : null; })); @@ -888,7 +887,7 @@ class ActionsColumn extends Column { private createEditAction(keybindingItemEntry: IKeybindingItemEntry): IAction { const keybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_DEFINE); return { - class: 'edit', + class: 'codicon-edit', enabled: true, id: 'editKeybinding', tooltip: keybinding ? localize('editKeybindingLabelWithKey', "Change Keybinding {0}", `(${keybinding.getLabel()})`) : localize('editKeybindingLabel', "Change Keybinding"), @@ -899,7 +898,7 @@ class ActionsColumn extends Column { private createAddAction(keybindingItemEntry: IKeybindingItemEntry): IAction { const keybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_DEFINE); return { - class: 'add', + class: 'codicon-add', enabled: true, id: 'addKeybinding', tooltip: keybinding ? localize('addKeybindingLabelWithKey', "Add Keybinding {0}", `(${keybinding.getLabel()})`) : localize('addKeybindingLabel', "Add Keybinding"), @@ -1152,7 +1151,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list:focus .monaco-list-row.selected > .column .monaco-keybinding-key { color: ${listActiveSelectionForegroundColor}; }`); } const listInactiveFocusAndSelectionForegroundColor = theme.getColor(listInactiveSelectionForeground); - if (listActiveSelectionForegroundColor) { + if (listInactiveFocusAndSelectionForegroundColor) { collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list .monaco-list-row.selected > .column .monaco-keybinding-key { color: ${listInactiveFocusAndSelectionForegroundColor}; }`); } const listHoverForegroundColor = theme.getColor(listHoverForeground); diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts index 9b45e34dee4..8d8eb232266 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts @@ -14,7 +14,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { registerEditorContribution, ServicesAccessor, registerEditorCommand, EditorCommand } from 'vs/editor/browser/editorExtensions'; -import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; import { SmartSnippetInserter } from 'vs/workbench/contrib/preferences/common/smartSnippetInserter'; import { DefineKeybindingOverlayWidget } from 'vs/workbench/contrib/preferences/browser/keybindingWidgets'; @@ -23,14 +23,14 @@ import { parseTree, Node } from 'vs/base/common/json'; import { ScanCodeBinding } from 'vs/base/common/scanCode'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { WindowsNativeResolvedKeybinding } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper'; -import { themeColorFromId, ThemeColor, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeService'; import { overviewRulerInfo, overviewRulerError } from 'vs/editor/common/view/editorColorRegistry'; import { IModelDeltaDecoration, ITextModel, TrackedRangeStickiness, OverviewRulerLane } from 'vs/editor/common/model'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; -import Severity from 'vs/base/common/severity'; -import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { equals } from 'vs/base/common/arrays'; +import { assertIsDefined } from 'vs/base/common/types'; const NLS_LAUNCH_MESSAGE = nls.localize('defineKeybinding.start', "Define Keybinding"); const NLS_KB_LAYOUT_ERROR_MESSAGE = nls.localize('defineKeybinding.kbLayoutErrorMessage', "You won't be able to produce this key combination under your current keyboard layout."); @@ -39,7 +39,7 @@ const INTERESTING_FILE = /keybindings\.json$/; export class DefineKeybindingController extends Disposable implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.contrib.defineKeybinding'; + public static readonly ID = 'editor.contrib.defineKeybinding'; static get(editor: ICodeEditor): DefineKeybindingController { return editor.getContribution(DefineKeybindingController.ID); @@ -58,10 +58,6 @@ export class DefineKeybindingController extends Disposable implements editorComm this._update(); } - getId(): string { - return DefineKeybindingController.ID; - } - get keybindingWidgetRenderer(): KeybindingWidgetRenderer | undefined { return this._keybindingWidgetRenderer; } @@ -169,14 +165,14 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { private _dec: string[] = []; constructor( - private _editor: IActiveCodeEditor, + private _editor: ICodeEditor, @IKeybindingService private readonly _keybindingService: IKeybindingService, ) { super(); this._updateDecorations = this._register(new RunOnceScheduler(() => this._updateDecorationsNow(), 500)); - const model = this._editor.getModel(); + const model = assertIsDefined(this._editor.getModel()); this._register(model.onDidChangeContent(() => this._updateDecorations.schedule())); this._register(this._keybindingService.onDidUpdateKeybindings((e) => this._updateDecorations.schedule())); this._register({ @@ -189,7 +185,7 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { } private _updateDecorationsNow(): void { - const model = this._editor.getModel(); + const model = assertIsDefined(this._editor.getModel()); const newDecorations: IModelDeltaDecoration[] = []; @@ -267,18 +263,7 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { const aParts = KeybindingParser.parseUserBinding(a); const bParts = KeybindingParser.parseUserBinding(b); - - if (aParts.length !== bParts.length) { - return false; - } - - for (let i = 0, len = aParts.length; i < len; i++) { - if (!this._userBindingEquals(aParts[i], bParts[i])) { - return false; - } - } - - return true; + return equals(aParts, bParts, (a, b) => this._userBindingEquals(a, b)); } private static _userBindingEquals(a: SimpleKeybinding | ScanCodeBinding, b: SimpleKeybinding | ScanCodeBinding): boolean { @@ -397,10 +382,5 @@ function isInterestingEditorModel(editor: ICodeEditor): boolean { return INTERESTING_FILE.test(url); } -registerEditorContribution(DefineKeybindingController); +registerEditorContribution(DefineKeybindingController.ID, DefineKeybindingController); registerEditorCommand(new DefineKeybindingCommand()); - -registerThemingParticipant((theme, collector) => { - collector.addRule(`.monaco-editor .inlineKeybindingInfo:before { background: url("data:image/svg+xml,${SeverityIcon.getSVGData(Severity.Info, theme)}") -0.1em -0.2em no-repeat; }`); - collector.addRule(`.monaco-editor .inlineKeybindingError:before { background: url("data:image/svg+xml,${SeverityIcon.getSVGData(Severity.Error, theme)}") -0.1em -0.2em no-repeat; }`); -}); diff --git a/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts b/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts index 7180550bc65..b076def7c83 100644 --- a/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts +++ b/src/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; +import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/common/statusbar'; import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IKeymapService, areKeyboardLayoutsEqual, parseKeyboardLayoutDescription, getKeyboardLayoutId, IKeyboardLayoutInfo } from 'vs/workbench/services/keybinding/common/keymapInfo'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; @@ -13,7 +13,7 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchCo import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KEYBOARD_LAYOUT_OPEN_PICKER } from 'vs/workbench/contrib/preferences/common/preferences'; import { Action } from 'vs/base/common/actions'; -import { isWeb, isMacintosh, isWindows } from 'vs/base/common/platform'; +import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { QuickPickInput, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -99,9 +99,7 @@ export class KeyboardLayoutPickerAction extends Action { @IEnvironmentService private readonly environmentService: IEnvironmentService, @IEditorService private readonly editorService: IEditorService ) { - super(actionId, actionLabel); - - this.enabled = isWeb; + super(actionId, actionLabel, undefined, true); } async run(): Promise { diff --git a/src/vs/workbench/contrib/preferences/browser/media/add-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/add-dark.svg deleted file mode 100644 index 4d9389336b9..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/add-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/add-light.svg b/src/vs/workbench/contrib/preferences/browser/media/add-light.svg deleted file mode 100644 index 01a9de7d5ab..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/add-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/check-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/check-dark.svg deleted file mode 100644 index 51674695e1f..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/check-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/check-light.svg b/src/vs/workbench/contrib/preferences/browser/media/check-light.svg deleted file mode 100644 index 7b1da6d7208..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/check-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/clear-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/clear-dark.svg deleted file mode 100644 index 04d64ab41ca..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/clear-dark.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/clear-light.svg b/src/vs/workbench/contrib/preferences/browser/media/clear-light.svg deleted file mode 100644 index f6a51c856f0..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/clear-light.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/configure-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/configure-dark.svg deleted file mode 100644 index ace01a5ddf5..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/configure-dark.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/configure-light.svg b/src/vs/workbench/contrib/preferences/browser/media/configure-light.svg deleted file mode 100644 index 4194780bbaa..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/configure-light.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/edit-dark.svg deleted file mode 100644 index a72757482be..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit-light.svg b/src/vs/workbench/contrib/preferences/browser/media/edit-light.svg deleted file mode 100644 index ae71150c0c8..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/edit-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css index 3fd18df42d1..7336b05ee6c 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css +++ b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css @@ -45,31 +45,11 @@ margin-right: 4px; } -.keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence { - background: url('sort-precedence-light.svg') center center no-repeat; -} - -.hc-black .keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence, -.vs-dark .keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence { - background: url('sort-precedence-dark.svg') center center no-repeat; -} - -.keybindings-editor .monaco-action-bar .action-item > .record-keys { - background: url('record-keys-light.svg') center center no-repeat; -} - -.hc-black .keybindings-editor .monaco-action-bar .action-item > .record-keys, -.vs-dark .keybindings-editor .monaco-action-bar .action-item > .record-keys { - background: url('record-keys-dark.svg') center center no-repeat; -} - -.keybindings-editor .monaco-action-bar .action-item > .clear-input { - background: url('clear-light.svg') center center no-repeat; -} - -.hc-black .keybindings-editor .monaco-action-bar .action-item > .clear-input, -.vs-dark .keybindings-editor .monaco-action-bar .action-item > .clear-input { - background: url('clear-dark.svg') center center no-repeat; +.keybindings-editor .monaco-action-bar .action-item > .codicon { + display: flex; + align-items: center; + justify-content: center; + color: inherit; } .keybindings-editor > .keybindings-header .open-keybindings-container { @@ -206,22 +186,3 @@ cursor: pointer; margin-top: 3px; } - -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar .action-item > .icon.edit { - background: url('edit-light.svg') center center no-repeat; - transform: rotate(-90deg); -} - -.hc-black .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar .action-item > .icon.edit, -.vs-dark .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar .action-item > .icon.edit { - background: url('edit-dark.svg') center center no-repeat; -} - -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar .action-item > .icon.add { - background: url('add-light.svg') center center no-repeat; -} - -.hc-black .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar .action-item > .icon.add, -.vs-dark .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar .action-item > .icon.add { - background: url('add-dark.svg') center center no-repeat; -} diff --git a/src/vs/workbench/contrib/preferences/browser/media/preferences.css b/src/vs/workbench/contrib/preferences/browser/media/preferences.css index c9feed29055..73c3859d0f3 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/preferences.css +++ b/src/vs/workbench/contrib/preferences/browser/media/preferences.css @@ -139,6 +139,7 @@ .monaco-editor .settings-header-widget .title-container { display: flex; user-select: none; + -webkit-user-select: none; } .vs .monaco-editor .settings-header-widget .title-container { @@ -170,6 +171,7 @@ cursor: pointer; font-weight: bold; user-select: none; + -webkit-user-select: none; display: flex; } @@ -203,45 +205,31 @@ outline: 1px dotted #f38518; } -.monaco-editor .settings-group-title-widget .title-container .expand-collapse-icon { - background: url("tree-expanded-light.svg") 50% 50% no-repeat; - margin-right: 2px; +.monaco-editor .settings-group-title-widget .title-container .codicon { + margin: 0 2px; width: 16px; height: 100%; + display: flex; + align-items: center; + justify-content: center; } -.monaco-editor.vs-dark .settings-group-title-widget .title-container .expand-collapse-icon, -.monaco-editor.hc-black .settings-group-title-widget .title-container .expand-collapse-icon { - background: url("tree-expanded-dark.svg") 50% 50% no-repeat; +.monaco-editor .settings-group-title-widget .title-container.collapsed .codicon::before { + transform: rotate(-90deg); } -.monaco-editor .settings-group-title-widget .title-container.collapsed .expand-collapse-icon { - background: url("tree-collapsed-light.svg") 50% 50% no-repeat; -} - -.monaco-editor.vs-dark .settings-group-title-widget .title-container.collapsed .expand-collapse-icon, -.monaco-editor.hc-black .settings-group-title-widget .title-container.collapsed .expand-collapse-icon { - background: url("tree-collapsed-dark.svg") 50% 50% no-repeat; -} - -.monaco-editor .edit-preferences-widget { - background: url('edit-light.svg') center center no-repeat; +.monaco-editor .codicon-edit { transform: rotate(-90deg); width:16px; height: 16px; cursor: pointer; } -.monaco-editor .edit-preferences-widget.hidden { +.monaco-editor .codicon-edit.hidden { display: none; visibility: hidden; } -.monaco-editor.hc-black .edit-preferences-widget, -.monaco-editor.vs-dark .edit-preferences-widget { - background: url('edit-dark.svg') center center no-repeat; -} - .monaco-editor .dim-configuration { color: #b1b1b1; } diff --git a/src/vs/workbench/contrib/preferences/browser/media/record-keys-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/record-keys-dark.svg deleted file mode 100644 index 4341206b83d..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/record-keys-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/record-keys-light.svg b/src/vs/workbench/contrib/preferences/browser/media/record-keys-light.svg deleted file mode 100644 index af980359439..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/record-keys-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/remove-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/remove-dark.svg deleted file mode 100644 index 75644595d19..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/remove-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/remove-light.svg b/src/vs/workbench/contrib/preferences/browser/media/remove-light.svg deleted file mode 100644 index cf5f28ca35c..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/remove-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index 3cf2a4b042d..82ac9658052 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -12,6 +12,14 @@ overflow: hidden; } +.settings-editor .codicon { + color: inherit !important; +} + +.settings-editor:focus { + outline: none !important; +} + /* header styling */ .settings-editor > .settings-header { box-sizing: border-box; @@ -36,7 +44,16 @@ padding: 0px 8px; border-radius: 2px; position: absolute; - right: 10px; + right: 35px; + top: 0; +} + +.settings-editor > .settings-header > .search-container > .settings-clear-widget { + margin: 6px 0px; + padding: 0px 8px; + border-radius: 2px; + position: absolute; + right: 0px; top: 0; } @@ -88,7 +105,6 @@ .settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item .action-label { text-transform: none; font-size: 13px; - padding-bottom: 7px; padding-top: 7px; padding-left: 8px; @@ -155,7 +171,7 @@ } .settings-editor > .settings-body .settings-tree-container .monaco-list-row .mouseover .setting-toolbar-container > .monaco-toolbar .codicon-more, -.settings-editor > .settings-body .settings-tree-container .monaco-list-row .setting-item.focused .setting-toolbar-container > .monaco-toolbar .codicon-more, +.settings-editor > .settings-body .settings-tree-container .monaco-list-row .setting-item-contents.focused .setting-toolbar-container > .monaco-toolbar .codicon-more, .settings-editor > .settings-body .settings-tree-container .monaco-list-row .setting-toolbar-container:hover > .monaco-toolbar .codicon-more, .settings-editor > .settings-body .settings-tree-container .monaco-list-row .setting-toolbar-container > .monaco-toolbar .active .codicon-more { opacity: 1; @@ -166,21 +182,9 @@ transition: opacity .3s; width: 22px; height: 22px; - background-position: center; - background-repeat: no-repeat; - background-size: 16px; -} - -.settings-editor > .settings-body .settings-tree-container .setting-toolbar-container > .monaco-toolbar .codicon-more::before { - content: ' '; -} - -.vs .settings-editor > .settings-body .settings-tree-container .monaco-toolbar .codicon-more { - background-image: url('configure-light.svg'); -} - -.vs-dark .settings-editor > .settings-body .settings-tree-container .monaco-toolbar .codicon-more { - background-image: url('configure-dark.svg'); + display: flex; + align-items: center; + justify-content: center; } .settings-editor > .settings-body .settings-toc-container { @@ -278,7 +282,7 @@ max-width: 1000px; margin: auto; box-sizing: border-box; - padding-left: 217px; + padding-left: 219px; padding-right: 20px; overflow: visible; } @@ -341,6 +345,7 @@ .settings-editor > .settings-body > .settings-tree-container .setting-item-contents .setting-item-category { font-weight: 600; user-select: text; + -webkit-user-select: text; } .settings-editor > .settings-body > .settings-tree-container .setting-item-contents .setting-item-category { @@ -350,11 +355,13 @@ .settings-editor > .settings-body > .settings-tree-container .setting-item-contents .setting-item-deprecation-message { margin-top: 3px; user-select: text; + -webkit-user-select: text; } .settings-editor > .settings-body > .settings-tree-container .setting-item-contents .setting-item-description { margin-top: -1px; user-select: text; + -webkit-user-select: text; } .settings-editor > .settings-body > .settings-tree-container .setting-item-contents .setting-item-deprecation-message { @@ -391,6 +398,11 @@ -webkit-appearance: none !important; } +.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-number input[type=number] { + /* Hide arrow button that shows in type=number fields */ + -moz-appearance: textfield !important; +} + .settings-editor > .settings-body > .settings-tree-container .setting-item-contents .setting-item-description-markdown * { margin: 0px; } @@ -436,16 +448,10 @@ margin-right: 9px; margin-left: 0px; padding: 0px; - background-size: 16px !important; } -.vs .settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox.checked { - background: url('check-light.svg') center center no-repeat; -} - -.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox.checked, -.hc-black .settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox.checked { - background: url('check-dark.svg') center center no-repeat; +.settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox.codicon:not(.checked)::before { + opacity: 0; } .settings-editor > .settings-body > .settings-tree-container .setting-item-contents .setting-item-value { @@ -482,6 +488,7 @@ width: initial; font: inherit; height: 26px; + padding: 2px 8px; } .settings-editor > .settings-body > .settings-tree-container .setting-item-new-extensions { diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css b/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css index ff5f813a4fc..c78c447a370 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css @@ -70,28 +70,15 @@ height: 20px; padding: 2px; margin-right: 2px; + display: flex; + align-items: center; + justify-content: center; } .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit { margin-right: 4px; } -.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit { - background: url("edit-light.svg") center center no-repeat; -} - -.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit { - background: url("edit-dark.svg") center center no-repeat; -} - -.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-remove { - background: url("remove-light.svg") center center no-repeat; -} - -.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-remove { - background: url("remove-dark.svg") center center no-repeat; -} - .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .monaco-text-button { width: initial; padding: 2px 14px; diff --git a/src/vs/workbench/contrib/preferences/browser/media/sort-precedence-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/sort-precedence-dark.svg deleted file mode 100644 index 6b533e0824d..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/sort-precedence-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/sort-precedence-light.svg b/src/vs/workbench/contrib/preferences/browser/media/sort-precedence-light.svg deleted file mode 100644 index 494e5e458c0..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/sort-precedence-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/tree-collapsed-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/tree-collapsed-dark.svg deleted file mode 100644 index 17de497f336..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/tree-collapsed-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/tree-collapsed-light.svg b/src/vs/workbench/contrib/preferences/browser/media/tree-collapsed-light.svg deleted file mode 100644 index 296499b8e5c..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/tree-collapsed-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/tree-expanded-dark.svg b/src/vs/workbench/contrib/preferences/browser/media/tree-expanded-dark.svg deleted file mode 100644 index a1df6a8d44a..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/tree-expanded-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/media/tree-expanded-light.svg b/src/vs/workbench/contrib/preferences/browser/media/tree-expanded-light.svg deleted file mode 100644 index e60e357f573..00000000000 --- a/src/vs/workbench/contrib/preferences/browser/media/tree-expanded-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 78ae46235bf..5e544b6a1c5 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -374,7 +374,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon constructor( @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IPreferencesService private readonly preferencesService: IPreferencesService, - @IWorkspaceContextService private readonly workpsaceContextService: IWorkspaceContextService, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @ILabelService labelService: ILabelService, @IExtensionService extensionService: IExtensionService, ) { @@ -410,8 +410,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon }); this.updatePreferencesEditorMenuItem(); - this._register(workpsaceContextService.onDidChangeWorkbenchState(() => this.updatePreferencesEditorMenuItem())); - this._register(workpsaceContextService.onDidChangeWorkspaceFolders(() => this.updatePreferencesEditorMenuItemForWorkspaceFolders())); + this._register(workspaceContextService.onDidChangeWorkbenchState(() => this.updatePreferencesEditorMenuItem())); + this._register(workspaceContextService.onDidChangeWorkspaceFolders(() => this.updatePreferencesEditorMenuItemForWorkspaceFolders())); extensionService.whenInstalledExtensionsRegistered() .then(() => { @@ -434,7 +434,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon private updatePreferencesEditorMenuItem() { const commandId = '_workbench.openWorkspaceSettingsEditor'; - if (this.workpsaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && !CommandsRegistry.getCommand(commandId)) { + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && !CommandsRegistry.getCommand(commandId)) { CommandsRegistry.registerCommand(commandId, () => this.preferencesService.openWorkspaceSettings(false)); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { @@ -454,11 +454,11 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon } private updatePreferencesEditorMenuItemForWorkspaceFolders() { - for (const folder of this.workpsaceContextService.getWorkspace().folders) { + for (const folder of this.workspaceContextService.getWorkspace().folders) { const commandId = `_workbench.openFolderSettings.${folder.uri.toString()}`; if (!CommandsRegistry.getCommand(commandId)) { CommandsRegistry.registerCommand(commandId, () => { - if (this.workpsaceContextService.getWorkbenchState() === WorkbenchState.FOLDER) { + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.FOLDER) { return this.preferencesService.openWorkspaceSettings(false); } else { return this.preferencesService.openFolderSettings(folder.uri, false); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts b/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts index b93c9b2fd62..b7742712238 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Action } from 'vs/base/common/actions'; -import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -198,9 +198,6 @@ export class OpenFolderSettingsAction extends Action { static readonly ID = 'workbench.action.openFolderSettings'; static readonly LABEL = OPEN_FOLDER_SETTINGS_LABEL; - private disposables: IDisposable[] = []; - - constructor( id: string, label: string, @@ -210,8 +207,8 @@ export class OpenFolderSettingsAction extends Action { ) { super(id, label); this.update(); - this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); - this.workspaceContextService.onDidChangeWorkspaceFolders(() => this.update(), this, this.disposables); + this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this)); + this._register(this.workspaceContextService.onDidChangeWorkspaceFolders(() => this.update(), this)); } private update(): void { @@ -228,11 +225,6 @@ export class OpenFolderSettingsAction extends Action { return undefined; }); } - - dispose(): void { - this.disposables = dispose(this.disposables); - super.dispose(); - } } export class ConfigureLanguageBasedSettingsAction extends Action { diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index 356f87830bd..abec70f1f28 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -17,7 +17,7 @@ import { Disposable, dispose, IDisposable } 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'; -import { EditorExtensionsRegistry, IEditorContributionCtor, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { EditorExtensionsRegistry, registerEditorContribution, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -53,8 +53,8 @@ import { IFilterResult, IPreferencesService, ISetting, ISettingsEditorModel, ISe import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { DefaultSettingsEditorModel, SettingsEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IWindowService } from 'vs/platform/windows/common/windows'; -import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types'; export class PreferencesEditor extends BaseEditor { @@ -634,7 +634,7 @@ class PreferencesRenderersController extends Disposable { if (filterResult) { filterResult.query = filter; - filterResult.exactMatch = searchResult && searchResult.exactMatch; + filterResult.exactMatch = !!searchResult && searchResult.exactMatch; } return filterResult; @@ -683,7 +683,7 @@ class PreferencesRenderersController extends Disposable { } private _updatePreference(key: string, value: any, source: ISetting, fromEditableSettings?: boolean): void { - const data: { [key: string]: any } = { + const data: { [key: string]: any; } = { userConfigurationKeys: [key] }; @@ -718,7 +718,7 @@ class PreferencesRenderersController extends Disposable { this.telemetryService.publicLog('defaultSettingsActions.copySetting', data); } - private _findSetting(filterResult: IFilterResult, key: string): { groupIdx: number, settingIdx: number, overallSettingIdx: number } | undefined { + private _findSetting(filterResult: IFilterResult, key: string): { groupIdx: number, settingIdx: number, overallSettingIdx: number; } | undefined { let overallSettingIdx = 0; for (let groupIdx = 0; groupIdx < filterResult.filteredGroups.length; groupIdx++) { @@ -826,11 +826,7 @@ class SideBySidePreferencesWidget extends Widget { this._register(attachStylerCallback(this.themeService, { scrollbarShadow }, colors => { const shadow = colors.scrollbarShadow ? colors.scrollbarShadow.toString() : null; - if (shadow) { - this.editablePreferencesEditorContainer.style.boxShadow = `-6px 0 5px -5px ${shadow}`; - } else { - this.editablePreferencesEditorContainer.style.boxShadow = null; - } + this.editablePreferencesEditorContainer.style.boxShadow = shadow ? `-6px 0 5px -5px ${shadow}` : ''; })); this.splitview.addView({ @@ -845,7 +841,7 @@ class SideBySidePreferencesWidget extends Widget { this._register(focusTracker.onDidFocus(() => this._onFocus.fire())); } - setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<{ defaultPreferencesRenderer?: IPreferencesRenderer, editablePreferencesRenderer?: IPreferencesRenderer }> { + setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<{ defaultPreferencesRenderer?: IPreferencesRenderer, editablePreferencesRenderer?: IPreferencesRenderer; }> { this.getOrCreateEditablePreferencesEditor(editablePreferencesEditorInput); this.settingsTargetsWidget.settingsTarget = this.getSettingsTarget(editablePreferencesEditorInput.getResource()!); return Promise.all([ @@ -985,15 +981,15 @@ export class DefaultPreferencesEditor extends BaseTextEditor { @ITextFileService textFileService: ITextFileService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, - @IWindowService windowService: IWindowService + @IHostService hostService: IHostService ) { - super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService); + super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); } - private static _getContributions(): IEditorContributionCtor[] { - const skipContributions = [FoldingController.prototype, SelectionHighlighter.prototype, FindController.prototype]; - const contributions = EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.prototype) === -1); - contributions.push(DefaultSettingsEditorContribution); + private static _getContributions(): IEditorContributionDescription[] { + const skipContributions = [FoldingController.ID, SelectionHighlighter.ID, FindController.ID]; + const contributions = EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1); + contributions.push({ id: DefaultSettingsEditorContribution.ID, ctor: DefaultSettingsEditorContribution }); return contributions; } @@ -1049,20 +1045,25 @@ export class DefaultPreferencesEditor extends BaseTextEditor { return; } - this.getControl().setModel((editorModel).textEditorModel); + const editor = assertIsDefined(this.getControl()); + editor.setModel((editorModel).textEditorModel); })); } clearInput(): void { // Clear Model - this.getControl().setModel(null); + const editor = this.getControl(); + if (editor) { + editor.setModel(null); + } // Pass to super super.clearInput(); } layout(dimension: DOM.Dimension) { - this.getControl().layout(dimension); + const editor = assertIsDefined(this.getControl()); + editor.layout(dimension); } protected getAriaLabel(): string { @@ -1157,17 +1158,12 @@ abstract class AbstractSettingsEditorContribution extends Disposable implements } protected abstract _createPreferencesRenderer(): Promise | null> | null; - abstract getId(): string; } export class DefaultSettingsEditorContribution extends AbstractSettingsEditorContribution implements ISettingsEditorContribution { static readonly ID: string = 'editor.contrib.defaultsettings'; - getId(): string { - return DefaultSettingsEditorContribution.ID; - } - protected _createPreferencesRenderer(): Promise | null> | null { return this.preferencesService.createPreferencesEditorModel(this.editor.getModel()!.uri) .then(editorModel => { @@ -1194,10 +1190,6 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this._onModelChanged())); } - getId(): string { - return SettingsEditorContribution.ID; - } - protected _createPreferencesRenderer(): Promise | null> | null { const model = this.editor.getModel(); if (model) { @@ -1227,4 +1219,4 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl } } -registerEditorContribution(SettingsEditorContribution); +registerEditorContribution(SettingsEditorContribution.ID, SettingsEditorContribution); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts index 2881d09fec2..1d61e9073c2 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts @@ -32,6 +32,7 @@ import { DefaultSettingsEditorModel, SettingsEditorModel, WorkspaceConfiguration import { IMarkerService, IMarkerData, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { find } from 'vs/base/common/arrays'; export interface IPreferencesRenderer extends IDisposable { readonly preferencesModel: IPreferencesEditorModel; @@ -258,7 +259,7 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR this.settingsGroupTitleRenderer = this._register(instantiationService.createInstance(SettingsGroupTitleRenderer, editor)); this.filteredMatchesRenderer = this._register(instantiationService.createInstance(FilteredMatchesRenderer, editor)); this.editSettingActionRenderer = this._register(instantiationService.createInstance(EditSettingRenderer, editor, preferencesModel, this.settingHighlighter)); - this.bracesHidingRenderer = this._register(instantiationService.createInstance(BracesHidingRenderer, editor, preferencesModel)); + this.bracesHidingRenderer = this._register(instantiationService.createInstance(BracesHidingRenderer, editor)); this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, this.bracesHidingRenderer])); this._register(this.editSettingActionRenderer.onUpdateSetting(e => this._onUpdatePreference.fire(e))); @@ -321,12 +322,7 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR const { key, overrideOf } = setting; if (overrideOf) { const setting = this.getSetting(overrideOf); - for (const override of setting!.overrides!) { - if (override.key === key) { - return override; - } - } - return undefined; + return find(setting!.overrides!, override => override.key === key); } const settingsGroups = this.filterResult ? this.filterResult.filteredGroups : this.preferencesModel.settingsGroups; return this.getPreference(key, settingsGroups); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index c683b6dab4c..048b1ae6004 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -34,6 +34,7 @@ import { PANEL_ACTIVE_TITLE_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIV import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { isEqual } from 'vs/base/common/resources'; export class SettingsHeaderWidget extends Widget implements IViewZone { @@ -168,7 +169,7 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone { this._register(focusTracker.onDidFocus(() => this.toggleFocus(true))); this._register(focusTracker.onDidBlur(() => this.toggleFocus(false))); - this.icon = DOM.append(this.titleContainer, DOM.$('.expand-collapse-icon')); + this.icon = DOM.append(this.titleContainer, DOM.$('.codicon.codicon-chevron-down')); this.title = DOM.append(this.titleContainer, DOM.$('.title')); this.title.textContent = this.settingsGroup.title + ` (${this.settingsGroup.sections.reduce((count, section) => count + section.settings.length, 0)})`; @@ -341,7 +342,7 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { this.container = container; this.labelElement = DOM.$('.action-title'); this.detailsElement = DOM.$('.action-details'); - this.dropDownElement = DOM.$('.dropdown-icon.octicon.octicon-triangle-down.hide'); + this.dropDownElement = DOM.$('.dropdown-icon.codicon.codicon-triangle-down.hide'); this.anchorElement = DOM.$('a.action-label.folder-settings', { role: 'button', 'aria-haspopup': 'true', @@ -387,7 +388,7 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { const oldFolder = this._folder; const workspace = this.contextService.getWorkspace(); if (oldFolder) { - this._folder = workspace.folders.filter(folder => folder.uri.toString() === oldFolder.uri.toString())[0] || workspace.folders[0]; + this._folder = workspace.folders.filter(folder => isEqual(folder.uri, oldFolder.uri))[0] || workspace.folders[0]; } this._folder = this._folder ? this._folder : workspace.folders.length === 1 ? workspace.folders[0] : null; @@ -440,7 +441,7 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { return { id: 'folderSettingsTarget' + index, label: this.labelWithCount(folder.name, folderCount), - checked: this.folder && this.folder.uri.toString() === folder.uri.toString(), + checked: this.folder && isEqual(this.folder.uri, folder.uri), enabled: true, run: () => this._action.run(folder) }; @@ -574,7 +575,7 @@ export class SettingsTargetsWidget extends Widget { const isSameTarget = this.settingsTarget === settingsTarget || settingsTarget instanceof URI && this.settingsTarget instanceof URI && - this.settingsTarget.toString() === settingsTarget.toString(); + isEqual(this.settingsTarget, settingsTarget); if (!isSameTarget) { this.settingsTarget = settingsTarget; @@ -632,13 +633,13 @@ export class SearchWidget extends Widget { if (this.options.showResultCount) { this.countElement = DOM.append(this.controlsDiv, DOM.$('.settings-count-widget')); this._register(attachStylerCallback(this.themeService, { badgeBackground, contrastBorder }, colors => { - const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; - const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; + const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; + const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; this.countElement.style.backgroundColor = background; - this.countElement.style.borderWidth = border ? '1px' : null; - this.countElement.style.borderStyle = border ? 'solid' : null; + this.countElement.style.borderWidth = border ? '1px' : ''; + this.countElement.style.borderStyle = border ? 'solid' : ''; this.countElement.style.borderColor = border; const color = this.themeService.getTheme().getColor(badgeForeground); @@ -737,7 +738,7 @@ export class SearchWidget extends Widget { export class EditPreferenceWidget extends Disposable { - static readonly GLYPH_MARGIN_CLASS_NAME = 'edit-preferences-widget'; + static readonly GLYPH_MARGIN_CLASS_NAME = 'codicon codicon-edit'; private _line: number = -1; private _preferences: T[] = []; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 7e3bca1e76f..f8d98b3d05c 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -12,7 +12,7 @@ import * as collections from 'vs/base/common/collections'; import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors'; import { Iterator } from 'vs/base/common/iterator'; import * as strings from 'vs/base/common/strings'; -import { isArray, withNullAsUndefined } from 'vs/base/common/types'; +import { isArray, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/settingsEditor2'; import { localize } from 'vs/nls'; @@ -36,11 +36,13 @@ import { AbstractSettingRenderer, ISettingLinkClickEvent, ISettingOverrideClickE import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree'; -import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; +import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/contrib/preferences/common/preferences'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingsEditorOptions, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; +import { Action } from 'vs/base/common/actions'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; function createGroupIterator(group: SettingsTreeGroupElement): Iterator> { const groupsIt = Iterator.fromArray(group.children); @@ -68,6 +70,7 @@ export class SettingsEditor2 extends BaseEditor { private static NUM_INSTANCES: number = 0; private static SETTING_UPDATE_FAST_DEBOUNCE: number = 200; private static SETTING_UPDATE_SLOW_DEBOUNCE: number = 1000; + private static CONFIG_SCHEMA_UPDATE_DELAYER = 500; private static readonly SUGGESTIONS: string[] = [ `@${MODIFIED_SETTING_TAG}`, '@tag:usesOnlineServices', `@${EXTENSION_SETTING_TAG}` @@ -112,6 +115,8 @@ export class SettingsEditor2 extends BaseEditor { private remoteSearchThrottle: ThrottledDelayer; private searchInProgress: CancellationTokenSource | null = null; + private updatedConfigSchemaDelayer: Delayer; + private settingFastUpdateDelayer: Delayer; private settingSlowUpdateDelayer: Delayer; private pendingSettingUpdate: { key: string, value: any } | null = null; @@ -158,6 +163,8 @@ export class SettingsEditor2 extends BaseEditor { this.settingFastUpdateDelayer = new Delayer(SettingsEditor2.SETTING_UPDATE_FAST_DEBOUNCE); this.settingSlowUpdateDelayer = new Delayer(SettingsEditor2.SETTING_UPDATE_SLOW_DEBOUNCE); + this.updatedConfigSchemaDelayer = new Delayer(SettingsEditor2.CONFIG_SCHEMA_UPDATE_DELAYER); + this.inSettingsEditorContextKey = CONTEXT_SETTINGS_EDITOR.bindTo(contextKeyService); this.searchFocusContextKey = CONTEXT_SETTINGS_SEARCH_FOCUS.bindTo(contextKeyService); this.tocRowFocused = CONTEXT_TOC_ROW_FOCUS.bindTo(contextKeyService); @@ -201,7 +208,7 @@ export class SettingsEditor2 extends BaseEditor { createEditor(parent: HTMLElement): void { parent.setAttribute('tabindex', '-1'); - this.rootElement = DOM.append(parent, $('.settings-editor')); + this.rootElement = DOM.append(parent, $('.settings-editor', { tabindex: '-1' })); this.createHeader(this.rootElement); this.createBody(this.rootElement); @@ -213,31 +220,29 @@ export class SettingsEditor2 extends BaseEditor { return super.setInput(input, options, token) .then(() => timeout(0)) // Force setInput to be async .then(() => { - return this.render(token); - }) - .then(() => { - options = options || SettingsEditorOptions.create({}); + // Don't block setInput on render (which can trigger an async search) + this.render(token).then(() => { + options = options || SettingsEditorOptions.create({}); - if (!this.viewState.settingsTarget) { - if (!options.target) { - options.target = ConfigurationTarget.USER_LOCAL; + if (!this.viewState.settingsTarget) { + if (!options.target) { + options.target = ConfigurationTarget.USER_LOCAL; + } } - } - this._setOptions(options); + this._setOptions(options); - this._register(input.onDispose(() => { - this.searchWidget.setValue(''); - })); + this._register(input.onDispose(() => { + this.searchWidget.setValue(''); + })); - // Init TOC selection - this.updateTreeScrollSync(); - - this.restoreCachedState(); + // Init TOC selection + this.updateTreeScrollSync(); + }); }); } - private restoreCachedState(): void { + private restoreCachedState(): ISettingsEditor2State | null { const cachedState = this.group && this.input && this.editorMemento.loadEditorState(this.group, this.input); if (cachedState && typeof cachedState.target === 'object') { cachedState.target = URI.revive(cachedState.target); @@ -246,9 +251,15 @@ export class SettingsEditor2 extends BaseEditor { if (cachedState) { const settingsTarget = cachedState.target; this.settingsTargetsWidget.settingsTarget = settingsTarget; - this.onDidSettingsTargetChange(settingsTarget); + this.viewState.settingsTarget = settingsTarget; this.searchWidget.setValue(cachedState.searchQuery); } + + if (this.input) { + this.editorMemento.clearEditorState(this.input, this.group); + } + + return withUndefinedAsNull(cachedState); } setOptions(options: SettingsEditorOptions | undefined): void { @@ -273,10 +284,6 @@ export class SettingsEditor2 extends BaseEditor { clearInput(): void { this.inSettingsEditorContextKey.set(false); - if (this.input) { - this.editorMemento.clearEditorState(this.input, this.group); - } - super.clearInput(); } @@ -372,11 +379,18 @@ export class SettingsEditor2 extends BaseEditor { this.searchWidget.setValue(query.trim()); } + clearSearch(): void { + this.clearSearchResults(); + this.focusSearch(); + } + private createHeader(parent: HTMLElement): void { this.headerContainer = DOM.append(parent, $('.settings-header')); const searchContainer = DOM.append(this.headerContainer, $('.search-container')); + const clearInputAction = new Action(SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, localize('clearInput', "Clear Settings Search Input"), 'codicon-clear-all', false, () => { this.clearSearch(); return Promise.resolve(null); }); + const searchBoxLabel = localize('SearchSettings.AriaLabel', "Search settings"); this.searchWidget = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${SettingsEditor2.ID}.searchbox`, searchContainer, { triggerCharacters: ['@'], @@ -400,25 +414,38 @@ export class SettingsEditor2 extends BaseEditor { this.countElement = DOM.append(searchContainer, DOM.$('.settings-count-widget')); this._register(attachStylerCallback(this.themeService, { badgeBackground, contrastBorder, badgeForeground }, colors => { - const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; - const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; - const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : null; + const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; + const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; + const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : ''; this.countElement.style.backgroundColor = background; this.countElement.style.color = foreground; - this.countElement.style.borderWidth = border ? '1px' : null; - this.countElement.style.borderStyle = border ? 'solid' : null; + this.countElement.style.borderWidth = border ? '1px' : ''; + this.countElement.style.borderStyle = border ? 'solid' : ''; this.countElement.style.borderColor = border; })); - this._register(this.searchWidget.onInputDidChange(() => this.onSearchInputChanged())); + this._register(this.searchWidget.onInputDidChange(() => { + const searchVal = this.searchWidget.getValue(); + clearInputAction.enabled = !!searchVal; + this.onSearchInputChanged(); + })); const headerControlsContainer = DOM.append(this.headerContainer, $('.settings-header-controls')); const targetWidgetContainer = DOM.append(headerControlsContainer, $('.settings-target-container')); this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, targetWidgetContainer, { enableRemoteSettings: true })); this.settingsTargetsWidget.settingsTarget = ConfigurationTarget.USER_LOCAL; this.settingsTargetsWidget.onDidTargetChange(target => this.onDidSettingsTargetChange(target)); + + const actionsContainer = DOM.append(searchContainer, DOM.$('.settings-clear-widget')); + + const actionBar = this._register(new ActionBar(actionsContainer, { + animated: false, + actionViewItemProvider: (action: Action) => { return undefined; } + })); + + actionBar.push([clearInputAction], { label: false, icon: true }); } private onDidSettingsTargetChange(target: SettingsTarget): void { @@ -847,7 +874,11 @@ export class SettingsEditor2 extends BaseEditor { return undefined; } - this._register(model.onDidChangeGroups(() => this.onConfigUpdate())); + this._register(model.onDidChangeGroups(() => { + this.updatedConfigSchemaDelayer.trigger(() => { + this.onConfigUpdate(undefined, undefined, true); + }); + })); this.defaultSettingsEditorModel = model; return this.onConfigUpdate(undefined, true); }); @@ -881,7 +912,7 @@ export class SettingsEditor2 extends BaseEditor { }); } - private onConfigUpdate(keys?: string[], forceRefresh = false): void { + private async onConfigUpdate(keys?: string[], forceRefresh = false, schemaChange = false): Promise { if (keys && this.settingsTreeModel) { return this.updateElementsByKey(keys); } @@ -914,23 +945,26 @@ export class SettingsEditor2 extends BaseEditor { if (this.settingsTreeModel) { this.settingsTreeModel.update(resolvedSettingsRoot); - // Make sure that all extensions' settings are included in search results - const cachedState = this.group && this.input && this.editorMemento.loadEditorState(this.group, this.input); - if (cachedState && cachedState.searchQuery) { - this.triggerSearch(cachedState.searchQuery); - } else { - this.renderTree(undefined, forceRefresh); - this.refreshTOCTree(); + if (schemaChange && !!this.searchResultModel) { + // If an extension's settings were just loaded and a search is active, retrigger the search so it shows up + return await this.onSearchInputChanged(); } + + this.refreshTOCTree(); + this.renderTree(undefined, forceRefresh); } else { this.settingsTreeModel = this.instantiationService.createInstance(SettingsTreeModel, this.viewState); this.settingsTreeModel.update(resolvedSettingsRoot); this.tocTreeModel.settingsTreeRoot = this.settingsTreeModel.root as SettingsTreeGroupElement; - this.refreshTOCTree(); - this.refreshTree(); - - this.tocTree.collapseAll(); + const cachedState = this.restoreCachedState(); + if (cachedState && cachedState.searchQuery) { + await this.onSearchInputChanged(); + } else { + this.refreshTOCTree(); + this.refreshTree(); + this.tocTree.collapseAll(); + } } } @@ -1037,14 +1071,14 @@ export class SettingsEditor2 extends BaseEditor { } } - private onSearchInputChanged(): void { + private async onSearchInputChanged(): Promise { const query = this.searchWidget.getValue().trim(); this.delayedFilterLogging.cancel(); - this.triggerSearch(query.replace(/›/g, ' ')).then(() => { - if (query && this.searchResultModel) { - this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(query, this.searchResultModel!.getUniqueResults())); - } - }); + await this.triggerSearch(query.replace(/›/g, ' ')); + + if (query && this.searchResultModel) { + this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(query, this.searchResultModel!.getUniqueResults())); + } } private parseSettingFromJSON(query: string): string | null { @@ -1089,16 +1123,16 @@ export class SettingsEditor2 extends BaseEditor { // Added a filter model this.tocTree.setSelection([]); this.tocTree.expandAll(); + this.refreshTOCTree(); this.renderResultCountMessages(); this.refreshTree(); } else { // Leaving search mode this.tocTree.collapseAll(); + this.refreshTOCTree(); this.renderResultCountMessages(); this.refreshTree(); } - - this.refreshTOCTree(); } return Promise.resolve(); @@ -1227,8 +1261,8 @@ export class SettingsEditor2 extends BaseEditor { this.viewState.filterToCategory = undefined; this.tocTree.expandAll(); - this.renderTree(undefined, true); this.refreshTOCTree(); + this.renderTree(undefined, true); return result; }); } @@ -1271,7 +1305,7 @@ export class SettingsEditor2 extends BaseEditor { private _filterOrSearchPreferencesModel(filter: string, model: ISettingsEditorModel, provider?: ISearchProvider, token?: CancellationToken): Promise { const searchP = provider ? provider.searchModel(model, token) : Promise.resolve(null); return searchP - .then(null, err => { + .then(undefined, err => { if (isPromiseCanceledError(err)) { return Promise.reject(err); } else { @@ -1287,7 +1321,7 @@ export class SettingsEditor2 extends BaseEditor { this.telemetryService.publicLog('settingsEditor.searchError', { message, filter }); this.logService.info('Setting search error: ' + message); } - return Promise.resolve(null); + return null; } }); } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts index 945a4981851..10c4a7e5af1 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts @@ -132,7 +132,7 @@ export const tocData: ITOCEntry = { { id: 'features/search', label: localize('search', "Search"), - settings: ['search.*', 'searchRipgrep.*'] + settings: ['search.*'] } , { @@ -155,6 +155,11 @@ export const tocData: ITOCEntry = { label: localize('terminal', "Terminal"), settings: ['terminal.*'] }, + { + id: 'features/task', + label: localize('task', "Task"), + settings: ['task.*'] + }, { id: 'features/problems', label: localize('problems', "Problems"), @@ -197,9 +202,9 @@ export const tocData: ITOCEntry = { settings: ['telemetry.*'] }, { - id: 'application/sync', - label: localize('sync', "Sync"), - settings: ['userConfiguration.*'] + id: 'application/configurationSync', + label: localize('configuration sync', "Configuration Sync"), + settings: ['configurationSync.*'] } ] } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 05894806680..329d660bca6 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -12,7 +12,7 @@ import { alert as ariaAlert } from 'vs/base/browser/ui/aria/aria'; import { Button } from 'vs/base/browser/ui/button/button'; import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; -import { IListVirtualDelegate, ListAriaRootRole } from 'vs/base/browser/ui/list/list'; +import { ListAriaRootRole, CachedListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { DefaultStyleController } from 'vs/base/browser/ui/list/listWidget'; import { ISelectOptionItem, SelectBox } from 'vs/base/browser/ui/selectBox/selectBox'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; @@ -37,7 +37,7 @@ import { IContextMenuService, IContextViewService } from 'vs/platform/contextvie import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { editorBackground, errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, transparent } from 'vs/platform/theme/common/colorRegistry'; import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler, attachStyler } from 'vs/platform/theme/common/styler'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ITOCEntry } from 'vs/workbench/contrib/preferences/browser/settingsLayout'; @@ -393,9 +393,13 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre toggleMenuTitle }); toolbar.setActions([], this.settingActions)(); - const button = container.querySelector('.toolbar-toggle-more'); + + const button = container.querySelector('.codicon-more'); if (button) { (button).tabIndex = -1; + + // change icon from ellipsis to gear + (button).classList.add('codicon-gear'); } return toolbar; @@ -409,7 +413,6 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre const setting = element.setting; DOM.toggleClass(template.containerElement, 'is-configured', element.isConfigured); - DOM.toggleClass(template.containerElement, 'is-expanded', true); template.containerElement.setAttribute(AbstractSettingRenderer.SETTING_KEY_ATTR, element.setting.key); template.containerElement.setAttribute(AbstractSettingRenderer.SETTING_ID_ATTR, element.id); @@ -1071,7 +1074,7 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre const deprecationWarningElement = DOM.append(container, $('.setting-item-deprecation-message')); const toDispose = new DisposableStore(); - const checkbox = new Checkbox({ actionClassName: 'setting-value-checkbox', isChecked: true, title: '', inputActiveOptionBorder: undefined }); + const checkbox = new Checkbox({ actionClassName: 'codicon-check setting-value-checkbox', isChecked: true, title: '', inputActiveOptionBorder: undefined }); controlElement.appendChild(checkbox.domNode); toDispose.add(checkbox); toDispose.add(checkbox.onChange(() => { @@ -1212,7 +1215,7 @@ export class SettingTreeRenderers { } showContextMenu(element: SettingsTreeSettingElement, settingDOMElement: HTMLElement): void { - const toolbarElement = settingDOMElement.querySelector('.toolbar-toggle-more'); + const toolbarElement = settingDOMElement.querySelector('.monaco-toolbar'); if (toolbarElement) { this._contextMenuService.showContextMenu({ getActions: () => this.settingActions, @@ -1376,29 +1379,7 @@ export class SettingsTreeFilter implements ITreeFilter { } } -class SettingsTreeDelegate implements IListVirtualDelegate { - - private heightCache = new WeakMap(); - - getHeight(element: SettingsTreeGroupChild): number { - const cachedHeight = this.heightCache.get(element); - - if (typeof cachedHeight === 'number') { - return cachedHeight; - } - - if (element instanceof SettingsTreeGroupElement) { - if (element.isFirstGroup) { - return 31; - } - - return 40 + (7 * element.level); - } - - return element instanceof SettingsTreeSettingElement && element.valueType === SettingValueType.Boolean ? - 78 : - 104; - } +class SettingsTreeDelegate extends CachedListVirtualDelegate { getTemplateId(element: SettingsTreeGroupElement | SettingsTreeSettingElement | SettingsTreeNewExtensionsElement): string { if (element instanceof SettingsTreeGroupElement) { @@ -1444,8 +1425,16 @@ class SettingsTreeDelegate implements IListVirtualDelegate { filter: instantiationService.createInstance(SettingsTreeFilter, viewState) }); - this.disposables = []; - this.disposables.push(registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + this.disposables.clear(); + this.disposables.add(registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const activeBorderColor = theme.getColor(focusBorder); if (activeBorderColor) { // TODO@rob - why isn't this applied when added to the stylesheet from tocTree.ts? Seems like a chromium glitch. @@ -1536,21 +1525,21 @@ export class SettingsTree extends ObjectTree { this.getHTMLElement().classList.add(treeClass); - this.disposables.push(attachStyler(themeService, { - listActiveSelectionBackground: editorBackground, + this.disposables.add(attachStyler(themeService, { + listActiveSelectionBackground: transparent(Color.white, 0), listActiveSelectionForeground: foreground, - listFocusAndSelectionBackground: editorBackground, + listFocusAndSelectionBackground: transparent(Color.white, 0), listFocusAndSelectionForeground: foreground, - listFocusBackground: editorBackground, + listFocusBackground: transparent(Color.white, 0), listFocusForeground: foreground, listHoverForeground: foreground, - listHoverBackground: editorBackground, - listHoverOutline: editorBackground, - listFocusOutline: editorBackground, - listInactiveSelectionBackground: editorBackground, + listHoverBackground: transparent(Color.white, 0), + listHoverOutline: transparent(Color.white, 0), + listFocusOutline: transparent(Color.white, 0), + listInactiveSelectionBackground: transparent(Color.white, 0), listInactiveSelectionForeground: foreground, - listInactiveFocusBackground: editorBackground, - listInactiveFocusOutline: editorBackground + listInactiveFocusBackground: transparent(Color.white, 0), + listInactiveFocusOutline: transparent(Color.white, 0) }, colors => { this.style(colors); })); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index eb76fe7dbd4..5c48e7c6fe9 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -90,7 +90,7 @@ export class SettingsTreeNewExtensionsElement extends SettingsTreeElement { } export class SettingsTreeSettingElement extends SettingsTreeElement { - private static MAX_DESC_LINES = 20; + private static readonly MAX_DESC_LINES = 20; setting: ISetting; @@ -273,13 +273,7 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { return false; } - for (let extensionId of extensionFilters) { - if (extensionId.toLowerCase() === this.setting.extensionInfo.id.toLowerCase()) { - return true; - } - } - - return false; + return Array.from(extensionFilters).some(extensionId => extensionId.toLowerCase() === this.setting.extensionInfo!.id.toLowerCase()); } } @@ -409,7 +403,7 @@ function sanitizeId(id: string): string { return id.replace(/[\.\/]/, '_'); } -export function settingKeyToDisplayFormat(key: string, groupId = ''): { category: string, label: string } { +export function settingKeyToDisplayFormat(key: string, groupId = ''): { category: string, label: string; } { const lastDotIdx = key.lastIndexOf('.'); let category = ''; if (lastDotIdx >= 0) { @@ -542,12 +536,18 @@ export class SearchResultModel extends SettingsTreeModel { setResult(order: SearchResultIdx, result: ISearchResult | null): void { this.cachedUniqueSearchResults = null; + this.newExtensionSearchResults = null; + this.rawSearchResults = this.rawSearchResults || []; if (!result) { delete this.rawSearchResults[order]; return; } + if (result.exactMatch) { + this.rawSearchResults = []; + } + this.rawSearchResults[order] = result; this.updateChildren(); } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index 798a9b00514..eb1bbf865cd 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -57,6 +57,11 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox { background-color: ${checkboxBackgroundColor} !important; }`); } + const checkboxForegroundColor = theme.getColor(settingsCheckboxForeground); + if (checkboxForegroundColor) { + collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox { color: ${checkboxForegroundColor} !important; }`); + } + const checkboxBorderColor = theme.getColor(settingsCheckboxBorder); if (checkboxBorderColor) { collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox { border-color: ${checkboxBorderColor} !important; }`); @@ -352,7 +357,7 @@ export class ListSettingWidget extends Disposable { private createDeleteAction(key: string, idx: number): IAction { return { - class: 'setting-listAction-remove', + class: 'codicon-close', enabled: true, id: 'workbench.action.removeListItem', tooltip: this.getLocalizedStrings().deleteActionTooltip, @@ -362,7 +367,7 @@ export class ListSettingWidget extends Disposable { private createEditAction(idx: number): IAction { return { - class: 'setting-listAction-edit', + class: 'codicon-edit', enabled: true, id: 'workbench.action.editListItem', tooltip: this.getLocalizedStrings().editActionTooltip, diff --git a/src/vs/workbench/contrib/preferences/browser/tocTree.ts b/src/vs/workbench/contrib/preferences/browser/tocTree.ts index 0576d491913..845274f20ec 100644 --- a/src/vs/workbench/contrib/preferences/browser/tocTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/tocTree.ts @@ -211,7 +211,7 @@ export class TOCTree extends ObjectTree { this.getHTMLElement().classList.add(treeClass); - this.disposables.push(attachStyler(themeService, { + this.disposables.add(attachStyler(themeService, { listActiveSelectionBackground: editorBackground, listActiveSelectionForeground: settingsHeaderForeground, listFocusAndSelectionBackground: editorBackground, diff --git a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts index a0090bae844..66b5f574bdb 100644 --- a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import * as arrays from 'vs/base/common/arrays'; -import * as types from 'vs/base/common/types'; +import { localize } from 'vs/nls'; +import { distinct } from 'vs/base/common/arrays'; +import { withNullAsUndefined, isFunction } from 'vs/base/common/types'; import { Language } from 'vs/base/common/platform'; import { Action, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { Mode, IEntryRunContext, IAutoFocus, IModel, IQuickNavigateConfiguration } from 'vs/base/parts/quickopen/common/quickOpen'; @@ -32,29 +32,15 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { Disposable, DisposableStore, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; import { timeout } from 'vs/base/common/async'; +import { isFirefox } from 'vs/base/browser/browser'; export const ALL_COMMANDS_PREFIX = '>'; -let lastCommandPaletteInput: string; -let commandHistory: LRUCache; -let commandCounter = 1; - interface ISerializedCommandHistory { usesLRU?: boolean; entries: { key: string; value: number }[]; } -function resolveCommandHistory(configurationService: IConfigurationService): number { - const config = configurationService.getValue(); - - let commandHistory = config.workbench && config.workbench.commandPalette && config.workbench.commandPalette.history; - if (typeof commandHistory !== 'number') { - commandHistory = CommandsHistory.DEFAULT_COMMANDS_HISTORY_LENGTH; - } - - return commandHistory; -} - class CommandsHistory extends Disposable { static readonly DEFAULT_COMMANDS_HISTORY_LENGTH = 50; @@ -62,7 +48,10 @@ class CommandsHistory extends Disposable { private static readonly PREF_KEY_CACHE = 'commandPalette.mru.cache'; private static readonly PREF_KEY_COUNTER = 'commandPalette.mru.counter'; - private commandHistoryLength = 0; + private static cache: LRUCache | undefined; + private static counter = 1; + + private configuredCommandsHistoryLength = 0; constructor( @IStorageService private readonly storageService: IStorageService, @@ -81,10 +70,10 @@ class CommandsHistory extends Disposable { } private updateConfiguration(): void { - this.commandHistoryLength = resolveCommandHistory(this.configurationService); + this.configuredCommandsHistoryLength = CommandsHistory.getConfiguredCommandHistoryLength(this.configurationService); - if (commandHistory && commandHistory.limit !== this.commandHistoryLength) { - commandHistory.limit = this.commandHistoryLength; + if (CommandsHistory.cache && CommandsHistory.cache.limit !== this.configuredCommandsHistoryLength) { + CommandsHistory.cache.limit = this.configuredCommandsHistoryLength; CommandsHistory.saveState(this.storageService); } @@ -101,7 +90,7 @@ class CommandsHistory extends Disposable { } } - commandHistory = new LRUCache(this.commandHistoryLength, 1); + const cache = CommandsHistory.cache = new LRUCache(this.configuredCommandsHistoryLength, 1); if (serializedCache) { let entries: { key: string; value: number }[]; if (serializedCache.usesLRU) { @@ -109,35 +98,64 @@ class CommandsHistory extends Disposable { } else { entries = serializedCache.entries.sort((a, b) => a.value - b.value); } - entries.forEach(entry => commandHistory.set(entry.key, entry.value)); + entries.forEach(entry => cache.set(entry.key, entry.value)); } - commandCounter = this.storageService.getNumber(CommandsHistory.PREF_KEY_COUNTER, StorageScope.GLOBAL, commandCounter); + CommandsHistory.counter = this.storageService.getNumber(CommandsHistory.PREF_KEY_COUNTER, StorageScope.GLOBAL, CommandsHistory.counter); } push(commandId: string): void { - commandHistory.set(commandId, commandCounter++); // set counter to command + if (!CommandsHistory.cache) { + return; + } + + CommandsHistory.cache.set(commandId, CommandsHistory.counter++); // set counter to command CommandsHistory.saveState(this.storageService); } peek(commandId: string): number | undefined { - return commandHistory.peek(commandId); + return CommandsHistory.cache?.peek(commandId); } static saveState(storageService: IStorageService): void { + if (!CommandsHistory.cache) { + return; + } + const serializedCache: ISerializedCommandHistory = { usesLRU: true, entries: [] }; - commandHistory.forEach((value, key) => serializedCache.entries.push({ key, value })); + CommandsHistory.cache.forEach((value, key) => serializedCache.entries.push({ key, value })); storageService.store(CommandsHistory.PREF_KEY_CACHE, JSON.stringify(serializedCache), StorageScope.GLOBAL); - storageService.store(CommandsHistory.PREF_KEY_COUNTER, commandCounter, StorageScope.GLOBAL); + storageService.store(CommandsHistory.PREF_KEY_COUNTER, CommandsHistory.counter, StorageScope.GLOBAL); + } + + static getConfiguredCommandHistoryLength(configurationService: IConfigurationService): number { + const config = configurationService.getValue(); + + const configuredCommandHistoryLength = config.workbench?.commandPalette?.history; + if (typeof configuredCommandHistoryLength === 'number') { + return configuredCommandHistoryLength; + } + + return CommandsHistory.DEFAULT_COMMANDS_HISTORY_LENGTH; + } + + static clearHistory(configurationService: IConfigurationService, storageService: IStorageService): void { + const commandHistoryLength = CommandsHistory.getConfiguredCommandHistoryLength(configurationService); + CommandsHistory.cache = new LRUCache(commandHistoryLength); + CommandsHistory.counter = 1; + + CommandsHistory.saveState(storageService); } } +let lastCommandPaletteInput: string | undefined = undefined; + export class ShowAllCommandsAction extends Action { static readonly ID = 'workbench.action.showCommands'; - static readonly LABEL = nls.localize('showTriggerActions', "Show All Commands"); + static readonly LABEL = localize('showTriggerActions', "Show All Commands"); constructor( id: string, @@ -150,7 +168,7 @@ export class ShowAllCommandsAction extends Action { run(): Promise { const config = this.configurationService.getValue(); - const restoreInput = config.workbench && config.workbench.commandPalette && config.workbench.commandPalette.preserveInput === true; + const restoreInput = config.workbench?.commandPalette?.preserveInput === true; // Show with last command palette input if any and configured let value = ALL_COMMANDS_PREFIX; @@ -167,7 +185,7 @@ export class ShowAllCommandsAction extends Action { export class ClearCommandHistoryAction extends Action { static readonly ID = 'workbench.action.clearCommandHistory'; - static readonly LABEL = nls.localize('clearCommandHistory', "Clear Command History"); + static readonly LABEL = localize('clearCommandHistory', "Clear Command History"); constructor( id: string, @@ -179,12 +197,9 @@ export class ClearCommandHistoryAction extends Action { } run(): Promise { - const commandHistoryLength = resolveCommandHistory(this.configurationService); + const commandHistoryLength = CommandsHistory.getConfiguredCommandHistoryLength(this.configurationService); if (commandHistoryLength > 0) { - commandHistory = new LRUCache(commandHistoryLength); - commandCounter = 1; - - CommandsHistory.saveState(this.storageService); + CommandsHistory.clearHistory(this.configurationService, this.storageService); } return Promise.resolve(undefined); @@ -196,7 +211,7 @@ class CommandPaletteEditorAction extends EditorAction { constructor() { super({ id: ShowAllCommandsAction.ID, - label: nls.localize('showCommands.label', "Command Palette..."), + label: localize('showCommands.label', "Command Palette..."), alias: 'Command Palette', precondition: undefined, menuOpts: { @@ -224,10 +239,10 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { constructor( private commandId: string, - private keybinding: ResolvedKeybinding, + private keybinding: ResolvedKeybinding | undefined, private label: string, - alias: string, - highlights: { label: IHighlight[], alias?: IHighlight[] }, + alias: string | undefined, + highlights: { label: IHighlight[] | null, alias: IHighlight[] | null }, private onBeforeRun: (commandId: string) => void, @INotificationService private readonly notificationService: INotificationService, @ITelemetryService protected telemetryService: ITelemetryService @@ -240,10 +255,10 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { if (this.label !== alias) { this.alias = alias; } else { - highlights.alias = undefined; + highlights.alias = null; } - this.setHighlights(highlights.label, undefined, highlights.alias); + this.setHighlights(withNullAsUndefined(highlights.label), undefined, withNullAsUndefined(highlights.alias)); } getCommandId(): string { @@ -266,7 +281,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { this.description = description; } - getKeybinding(): ResolvedKeybinding { + getKeybinding(): ResolvedKeybinding | undefined { return this.keybinding; } @@ -276,10 +291,10 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { getAriaLabel(): string { if (this.keybindingAriaLabel) { - return nls.localize('entryAriaLabelWithKey', "{0}, {1}, commands", this.getLabel(), this.keybindingAriaLabel); + return localize('entryAriaLabelWithKey', "{0}, {1}, commands", this.getLabel(), this.keybindingAriaLabel); } - return nls.localize('entryAriaLabel', "{0}, commands", this.getLabel()); + return localize('entryAriaLabel', "{0}, commands", this.getLabel()); } run(mode: Mode, context: IEntryRunContext): boolean { @@ -299,8 +314,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { // Indicate onBeforeRun this.onBeforeRun(this.commandId); - // Use a timeout to give the quick open widget a chance to close itself first - setTimeout(async () => { + const commandRunner = (async () => { if (action && (!(action instanceof Action) || action.enabled)) { try { this.telemetryService.publicLog2('workbenchActionExecuted', { id: action.id, from: 'quick open' }); @@ -319,9 +333,18 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { this.onError(error); } } else { - this.notificationService.info(nls.localize('actionNotEnabled', "Command '{0}' is not enabled in the current context.", this.getLabel())); + this.notificationService.info(localize('actionNotEnabled', "Command '{0}' is not enabled in the current context.", this.getLabel())); } - }, 50); + }); + + // Use a timeout to give the quick open widget a chance to close itself first + // Firefox: since the browser is quite picky for certain commands, we do not + // use a timeout (https://github.com/microsoft/vscode/issues/83288) + if (!isFirefox) { + setTimeout(() => commandRunner(), 50); + } else { + commandRunner(); + } } private onError(error?: Error): void { @@ -329,7 +352,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { return; } - this.notificationService.error(error || nls.localize('canNotRun', "Command '{0}' resulted in an error.", this.label)); + this.notificationService.error(error || localize('canNotRun', "Command '{0}' resulted in an error.", this.label)); } } @@ -337,10 +360,10 @@ class EditorActionCommandEntry extends BaseCommandEntry { constructor( commandId: string, - keybinding: ResolvedKeybinding, + keybinding: ResolvedKeybinding | undefined, label: string, - meta: string, - highlights: { label: IHighlight[], alias: IHighlight[] }, + meta: string | undefined, + highlights: { label: IHighlight[] | null, alias: IHighlight[] | null }, private action: IEditorAction, onBeforeRun: (commandId: string) => void, @INotificationService notificationService: INotificationService, @@ -358,10 +381,10 @@ class ActionCommandEntry extends BaseCommandEntry { constructor( commandId: string, - keybinding: ResolvedKeybinding, + keybinding: ResolvedKeybinding | undefined, label: string, - alias: string, - highlights: { label: IHighlight[], alias: IHighlight[] }, + alias: string | undefined, + highlights: { label: IHighlight[] | null, alias: IHighlight[] | null }, private action: Action, onBeforeRun: (commandId: string) => void, @INotificationService notificationService: INotificationService, @@ -408,7 +431,7 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { } private updateConfiguration(): void { - this.commandHistoryEnabled = resolveCommandHistory(this.configurationService) > 0; + this.commandHistoryEnabled = CommandsHistory.getConfiguredCommandHistoryLength(this.configurationService) > 0; } async getResults(searchValue: string, token: CancellationToken): Promise { @@ -439,7 +462,7 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { // Editor Actions const activeTextEditorWidget = this.editorService.activeTextEditorWidget; let editorActions: IEditorAction[] = []; - if (activeTextEditorWidget && types.isFunction(activeTextEditorWidget.getSupportedActions)) { + if (activeTextEditorWidget && isFunction(activeTextEditorWidget.getSupportedActions)) { editorActions = activeTextEditorWidget.getSupportedActions(); } @@ -456,7 +479,7 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { let entries = [...editorEntries, ...commandEntries]; // Remove duplicates - entries = arrays.distinct(entries, entry => `${entry.getLabel()}${entry.getGroupLabel()}${entry.getCommandId()}`); + entries = distinct(entries, entry => `${entry.getLabel()}${entry.getGroupLabel()}${entry.getCommandId()}`); // Handle label clashes const commandLabels = new Set(); @@ -494,12 +517,12 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { // only if we have recently used commands in the result set const firstEntry = entries[0]; if (firstEntry && this.commandsHistory.peek(firstEntry.getCommandId())) { - firstEntry.setGroupLabel(nls.localize('recentlyUsed', "recently used")); + firstEntry.setGroupLabel(localize('recentlyUsed', "recently used")); for (let i = 1; i < entries.length; i++) { const entry = entries[i]; if (!this.commandsHistory.peek(entry.getCommandId())) { entry.setShowBorder(true); - entry.setGroupLabel(nls.localize('morecCommands', "other commands")); + entry.setGroupLabel(localize('morecCommands', "other commands")); break; } } @@ -520,7 +543,7 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { if (label) { // Alias for non default languages - const alias = !Language.isDefaultVariant() ? action.alias : null; + const alias = !Language.isDefaultVariant() ? action.alias : undefined; const labelHighlights = wordFilter(searchValue, label); const aliasHighlights = alias ? wordFilter(searchValue, alias) : null; @@ -547,15 +570,15 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { let category, label = title; if (action.item.category) { category = typeof action.item.category === 'string' ? action.item.category : action.item.category.value; - label = nls.localize('cat.title', "{0}: {1}", category, title); + label = localize('cat.title', "{0}: {1}", category, title); } if (label) { const labelHighlights = wordFilter(searchValue, label); // Add an 'alias' in original language when running in different locale - const aliasTitle = (!Language.isDefaultVariant() && typeof action.item.title !== 'string') ? action.item.title.original : null; - const aliasCategory = (!Language.isDefaultVariant() && category && action.item.category && typeof action.item.category !== 'string') ? action.item.category.original : null; + const aliasTitle = (!Language.isDefaultVariant() && typeof action.item.title !== 'string') ? action.item.title.original : undefined; + const aliasCategory = (!Language.isDefaultVariant() && category && action.item.category && typeof action.item.category !== 'string') ? action.item.category.original : undefined; let alias; if (aliasTitle && category) { alias = aliasCategory ? `${aliasCategory}: ${aliasTitle}` : `${category}: ${aliasTitle}`; @@ -590,7 +613,7 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { } getEmptyLabel(searchString: string): string { - return nls.localize('noCommandsMatching', "No commands matching"); + return localize('noCommandsMatching', "No commands matching"); } onClose(canceled: boolean): void { diff --git a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts index 60a0a3da383..16ef00ee8b7 100644 --- a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts @@ -16,7 +16,7 @@ import { IModelDecorationsChangeAccessor, OverviewRulerLane, IModelDeltaDecorati import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen'; -import { DocumentSymbolProviderRegistry, DocumentSymbol, symbolKindToCssClass, SymbolKind, SymbolTag } from 'vs/editor/common/modes'; +import { DocumentSymbolProviderRegistry, DocumentSymbol, SymbolKinds, SymbolKind, SymbolTag } from 'vs/editor/common/modes'; import { IRange, Range } from 'vs/editor/common/core/range'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; import { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry'; @@ -195,7 +195,7 @@ class SymbolEntry extends EditorQuickOpenEntryGroup { return this.deprecated ? { extraClasses: ['deprecated'] } : undefined; } - getHighlights(): [IHighlight[], IHighlight[] | undefined, IHighlight[] | undefined] { + getHighlights(): [IHighlight[] | undefined, IHighlight[] | undefined, IHighlight[] | undefined] { return [ this.deprecated ? [] : filters.createMatches(this.score), undefined, @@ -425,7 +425,7 @@ export class GotoSymbolHandler extends QuickOpenHandler { // Show parent scope as description const description = element.containerName || ''; - const icon = symbolKindToCssClass(element.kind); + const icon = SymbolKinds.toCssClassName(element.kind); // Add results.push(new SymbolEntry(i, diff --git a/src/vs/workbench/contrib/quickopen/browser/helpHandler.ts b/src/vs/workbench/contrib/quickopen/browser/helpHandler.ts index ac714337b35..8d8aaafcca2 100644 --- a/src/vs/workbench/contrib/quickopen/browser/helpHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/helpHandler.ts @@ -17,11 +17,11 @@ export const HELP_PREFIX = '?'; class HelpEntry extends QuickOpenEntryGroup { private prefixLabel: string; private prefix: string; - private description: string; + private description: string | undefined; private quickOpenService: IQuickOpenService; private openOnPreview: boolean; - constructor(prefix: string, description: string, quickOpenService: IQuickOpenService, openOnPreview: boolean) { + constructor(prefix: string, description: string | undefined, openOnPreview: boolean, quickOpenService: IQuickOpenService) { super(); if (!prefix) { @@ -44,7 +44,7 @@ class HelpEntry extends QuickOpenEntryGroup { return nls.localize('entryAriaLabel', "{0}, picker help", this.getLabel()); } - getDescription(): string { + getDescription(): string | undefined { return this.description; } @@ -101,9 +101,9 @@ export class HelpHandler extends QuickOpenHandler { matchingHandlers.forEach(handler => { if (handler instanceof QuickOpenHandlerDescriptor) { - workbenchScoped.push(new HelpEntry(handler.prefix, handler.description, this.quickOpenService, matchingHandlers.length === 1)); + workbenchScoped.push(new HelpEntry(handler.prefix, handler.description, matchingHandlers.length === 1, this.quickOpenService)); } else { - const entry = new HelpEntry(handler.prefix, handler.description, this.quickOpenService, matchingHandlers.length === 1); + const entry = new HelpEntry(handler.prefix, handler.description, matchingHandlers.length === 1, this.quickOpenService); if (handler.needsEditor) { editorScoped.push(entry); } else { diff --git a/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts b/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts index 8f89d9f3444..98a93b09c37 100644 --- a/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts +++ b/src/vs/workbench/contrib/quickopen/browser/quickopen.contribution.ts @@ -191,4 +191,4 @@ MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { title: nls.localize('commandPalette', "Command Palette...") }, order: 1 -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/quickopen/browser/viewPickerHandler.ts b/src/vs/workbench/contrib/quickopen/browser/viewPickerHandler.ts index 2d09e3264f6..587dc075b24 100644 --- a/src/vs/workbench/contrib/quickopen/browser/viewPickerHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/viewPickerHandler.ts @@ -196,7 +196,7 @@ export class ViewPickerHandler extends QuickOpenHandler { private hasToShowViewlet(viewlet: ViewletDescriptor): boolean { const viewContainer = Registry.as(ViewExtensions.ViewContainersRegistry).get(viewlet.id); - if (viewContainer && viewContainer.hideIfEmpty) { + if (viewContainer?.hideIfEmpty) { const viewsCollection = this.viewsService.getViewDescriptors(viewContainer); return !!viewsCollection && viewsCollection.activeViewDescriptors.length > 0; } diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index 8b376218f2e..dbdd3ef369c 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -6,11 +6,10 @@ import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IWindowService, IWindowsConfiguration } from 'vs/platform/windows/common/windows'; +import { IWindowsConfiguration } from 'vs/platform/windows/common/windows'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { RunOnceScheduler } from 'vs/base/common/async'; @@ -20,12 +19,14 @@ import { isMacintosh, isNative } from 'vs/base/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IProductService } from 'vs/platform/product/common/productService'; interface IConfiguration extends IWindowsConfiguration { update: { mode: string; }; telemetry: { enableCrashReporter: boolean }; workbench: { list: { horizontalScrolling: boolean } }; debug: { console: { wordWrap: boolean } }; + configurationSync: { enableAuth: boolean }; } export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution { @@ -38,12 +39,12 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private enableCrashReporter: boolean | undefined; private treeHorizontalScrolling: boolean | undefined; private debugConsoleWordWrap: boolean | undefined; + private enableConfigSyncAuth: boolean | undefined; constructor( @IHostService private readonly hostService: IHostService, - @IWindowService private readonly windowService: IWindowService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IEnvironmentService private readonly envService: IEnvironmentService, + @IProductService private readonly productService: IProductService, @IDialogService private readonly dialogService: IDialogService ) { super(); @@ -56,13 +57,13 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo let changed = false; // Tree horizontal scrolling support - if (config.workbench && config.workbench.list && typeof config.workbench.list.horizontalScrolling === 'boolean' && config.workbench.list.horizontalScrolling !== this.treeHorizontalScrolling) { + if (typeof config.workbench?.list?.horizontalScrolling === 'boolean' && config.workbench.list.horizontalScrolling !== this.treeHorizontalScrolling) { this.treeHorizontalScrolling = config.workbench.list.horizontalScrolling; changed = true; } // Debug console word wrap - if (config.debug && typeof config.debug.console.wordWrap === 'boolean' && config.debug.console.wordWrap !== this.debugConsoleWordWrap) { + if (typeof config.debug?.console.wordWrap === 'boolean' && config.debug.console.wordWrap !== this.debugConsoleWordWrap) { this.debugConsoleWordWrap = config.debug.console.wordWrap; changed = true; } @@ -70,42 +71,48 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo if (isNative) { // Titlebar style - if (config.window && config.window.titleBarStyle !== this.titleBarStyle && (config.window.titleBarStyle === 'native' || config.window.titleBarStyle === 'custom')) { + if (typeof config.window?.titleBarStyle === 'string' && config.window?.titleBarStyle !== this.titleBarStyle && (config.window.titleBarStyle === 'native' || config.window.titleBarStyle === 'custom')) { this.titleBarStyle = config.window.titleBarStyle; changed = true; } // macOS: Native tabs - if (isMacintosh && config.window && typeof config.window.nativeTabs === 'boolean' && config.window.nativeTabs !== this.nativeTabs) { + if (isMacintosh && typeof config.window?.nativeTabs === 'boolean' && config.window.nativeTabs !== this.nativeTabs) { this.nativeTabs = config.window.nativeTabs; changed = true; } // macOS: Native fullscreen - if (isMacintosh && config.window && typeof config.window.nativeFullScreen === 'boolean' && config.window.nativeFullScreen !== this.nativeFullScreen) { + if (isMacintosh && typeof config.window?.nativeFullScreen === 'boolean' && config.window.nativeFullScreen !== this.nativeFullScreen) { this.nativeFullScreen = config.window.nativeFullScreen; changed = true; } // macOS: Click through (accept first mouse) - if (isMacintosh && config.window && typeof config.window.clickThroughInactive === 'boolean' && config.window.clickThroughInactive !== this.clickThroughInactive) { + if (isMacintosh && typeof config.window?.clickThroughInactive === 'boolean' && config.window.clickThroughInactive !== this.clickThroughInactive) { this.clickThroughInactive = config.window.clickThroughInactive; changed = true; } // Update channel - if (config.update && typeof config.update.mode === 'string' && config.update.mode !== this.updateMode) { + if (typeof config.update?.mode === 'string' && config.update.mode !== this.updateMode) { this.updateMode = config.update.mode; changed = true; } // Crash reporter - if (config.telemetry && typeof config.telemetry.enableCrashReporter === 'boolean' && config.telemetry.enableCrashReporter !== this.enableCrashReporter) { + if (typeof config.telemetry?.enableCrashReporter === 'boolean' && config.telemetry.enableCrashReporter !== this.enableCrashReporter) { this.enableCrashReporter = config.telemetry.enableCrashReporter; changed = true; } } + // Configuration Sync Auth + if (typeof config.configurationSync?.enableAuth === 'boolean' && config.configurationSync.enableAuth !== this.enableConfigSyncAuth) { + this.enableConfigSyncAuth = config.configurationSync.enableAuth; + changed = true; + } + // Notify only when changed and we are the focused window (avoids notification spam across windows) if (notify && changed) { this.doConfirm( @@ -113,8 +120,8 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo localize('relaunchSettingMessage', "A setting has changed that requires a restart to take effect.") : localize('relaunchSettingMessageWeb', "A setting has changed that requires a reload to take effect."), isNative ? - localize('relaunchSettingDetail', "Press the restart button to restart {0} and enable the setting.", this.envService.appNameLong) : - localize('relaunchSettingDetailWeb', "Press the reload button to reload {0} and enable the setting.", this.envService.appNameLong), + localize('relaunchSettingDetail', "Press the restart button to restart {0} and enable the setting.", this.productService.nameLong) : + localize('relaunchSettingDetailWeb', "Press the reload button to reload {0} and enable the setting.", this.productService.nameLong), isNative ? localize('restart', "&&Restart") : localize('restartWeb', "&&Reload"), @@ -123,23 +130,13 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo } } - private doConfirm(message: string, detail: string, primaryButton: string, confirmed: () => void): void { - this.windowService.isFocused().then(focused => { - if (focused) { - return this.dialogService.confirm({ - type: 'info', - message, - detail, - primaryButton - }).then(res => { - if (res.confirmed) { - confirmed(); - } - }); + private async doConfirm(message: string, detail: string, primaryButton: string, confirmed: () => void): Promise { + if (this.hostService.hasFocus) { + const res = await this.dialogService.confirm({ type: 'info', message, detail, primaryButton }); + if (res.confirmed) { + confirmed(); } - - return undefined; - }); + } } } diff --git a/src/vs/workbench/contrib/remote/browser/remote-activity-bar.svg b/src/vs/workbench/contrib/remote/browser/remote-activity-bar.svg deleted file mode 100644 index 029e6b051c2..00000000000 --- a/src/vs/workbench/contrib/remote/browser/remote-activity-bar.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index 0002bb19824..4d17af30bd3 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -172,7 +172,7 @@ class HelpItem implements IHelpItem { const action = await this.quickInputService.pick(actions, { placeHolder: nls.localize('pickRemoteExtension', "Select url to open") }); if (action) { - await this.openerService.open(URI.parse(action.label)); + await this.openerService.open(URI.parse(action.description)); } } else { await this.openerService.open(URI.parse(this.values[0].url)); @@ -432,13 +432,18 @@ export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { return; } - if (typeof descriptor.viewDescriptor.remoteAuthority === 'undefined' || - descriptor.viewDescriptor.remoteAuthority === actualRemoteAuthority || - descriptor.viewDescriptor.id === HelpPanel.ID - ) { + const descriptorAuthority = descriptor.viewDescriptor.remoteAuthority; + if (typeof descriptorAuthority === 'undefined') { panel.setExpanded(true); + } else if (descriptor.viewDescriptor.id === HelpPanel.ID) { + // Do nothing, keep the default behavior for Help } else { - panel.setExpanded(false); + const descriptorAuthorityArr = Array.isArray(descriptorAuthority) ? descriptorAuthority : [descriptorAuthority]; + if (descriptorAuthorityArr.indexOf(actualRemoteAuthority) >= 0) { + panel.setExpanded(true); + } else { + panel.setExpanded(false); + } } }); } @@ -456,14 +461,14 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie RemoteViewlet, VIEWLET_ID, nls.localize('remote.explorer', "Remote Explorer"), - 'remote', + 'codicon-remote-explorer', 4 )); class OpenRemoteViewletAction extends ShowViewletAction { static readonly ID = VIEWLET_ID; - static LABEL = nls.localize('toggleRemoteViewlet', "Show Remote Explorer"); + static readonly LABEL = nls.localize('toggleRemoteViewlet', "Show Remote Explorer"); constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService) { super(id, label, VIEWLET_ID, viewletService, editorGroupService, layoutService); @@ -520,7 +525,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { let reconnectWaitEvent: ReconnectionWaitEvent | null = null; let disposableListener: IDisposable | null = null; - function showProgress(location: ProgressLocation, buttons?: string[]) { + function showProgress(location: ProgressLocation, buttons: { label: string, callback: () => void }[]) { if (currentProgressPromiseResolve) { currentProgressPromiseResolve(); } @@ -531,12 +536,12 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { if (location === ProgressLocation.Dialog) { // Show dialog progressService!.withProgress( - { location: ProgressLocation.Dialog, buttons }, + { location: ProgressLocation.Dialog, buttons: buttons.map(button => button.label) }, (progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; }, (choice?) => { // Handle choice from dialog - if (choice === 0 && buttons && reconnectWaitEvent) { - reconnectWaitEvent.skipWait(); + if (buttons[choice]) { + buttons[choice].callback(); } else { showProgress(ProgressLocation.Notification, buttons); } @@ -546,12 +551,12 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { } else { // Show notification progressService!.withProgress( - { location: ProgressLocation.Notification, buttons }, + { location: ProgressLocation.Notification, buttons: buttons.map(button => button.label) }, (progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; }, (choice?) => { - // Handle choice from notification - if (choice === 0 && buttons && reconnectWaitEvent) { - reconnectWaitEvent.skipWait(); + // Handle choice from dialog + if (buttons[choice]) { + buttons[choice].callback(); } else { hideProgress(); } @@ -567,6 +572,22 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { currentProgressPromiseResolve = null; } + const reconnectButton = { + label: nls.localize('reconnectNow', "Reconnect Now"), + callback: () => { + if (reconnectWaitEvent) { + reconnectWaitEvent.skipWait(); + } + } + }; + + const reloadButton = { + label: nls.localize('reloadWindow', "Reload Window"), + callback: () => { + commandService.executeCommand(ReloadWindowAction.ID); + } + }; + connection.onDidStateChange((e) => { if (currentTimer) { currentTimer.dispose(); @@ -581,7 +602,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { case PersistentConnectionEventType.ConnectionLost: if (!currentProgressPromiseResolve) { progressReporter = new ProgressReporter(null); - showProgress(ProgressLocation.Dialog, [nls.localize('reconnectNow', "Reconnect Now")]); + showProgress(ProgressLocation.Dialog, [reconnectButton, reloadButton]); } progressReporter!.report(nls.localize('connectionLost', "Connection Lost")); @@ -589,12 +610,12 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { case PersistentConnectionEventType.ReconnectionWait: hideProgress(); reconnectWaitEvent = e; - showProgress(lastLocation || ProgressLocation.Notification, [nls.localize('reconnectNow', "Reconnect Now")]); + showProgress(lastLocation || ProgressLocation.Notification, [reconnectButton, reloadButton]); currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds); break; case PersistentConnectionEventType.ReconnectionRunning: hideProgress(); - showProgress(lastLocation || ProgressLocation.Notification); + showProgress(lastLocation || ProgressLocation.Notification, [reloadButton]); progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect...")); // Register to listen for quick input is opened @@ -604,7 +625,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { // Need to move from dialog if being shown and user needs to type in a prompt if (lastLocation === ProgressLocation.Dialog && progressReporter !== null) { hideProgress(); - showProgress(ProgressLocation.Notification); + showProgress(ProgressLocation.Notification, [reloadButton]); progressReporter.report(); } } diff --git a/src/vs/workbench/contrib/remote/browser/remoteViewlet.css b/src/vs/workbench/contrib/remote/browser/remoteViewlet.css index 86bd4b76dc9..6f6908846c3 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteViewlet.css +++ b/src/vs/workbench/contrib/remote/browser/remoteViewlet.css @@ -3,10 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .activitybar>.content .monaco-action-bar .action-label.remote { - -webkit-mask: url('remote-activity-bar.svg') no-repeat 50% 50%; -} - .remote-help-content .monaco-list .monaco-list-row .remote-help-tree-node-item { display: flex; height: 22px; @@ -25,6 +21,7 @@ width: 16px; height: 22px; -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } .remote-help-content .monaco-list .monaco-list-row .monaco-tl-twistie { diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 1f4297c039f..43671fbda5e 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -6,7 +6,7 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { ILabelService } from 'vs/platform/label/common/label'; +import { ILabelService, ResourceLabelFormatting } from 'vs/platform/label/common/label'; import { OperatingSystem, isWeb } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; @@ -55,15 +55,20 @@ export class LabelContribution implements IWorkbenchContribution { private registerFormatters(): void { this.remoteAgentService.getEnvironment().then(remoteEnvironment => { if (remoteEnvironment) { + const formatting: ResourceLabelFormatting = { + label: '${path}', + separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/', + tildify: remoteEnvironment.os !== OperatingSystem.Windows, + normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows, + workspaceSuffix: isWeb ? undefined : Schemas.vscodeRemote + }; this.labelService.registerFormatter({ scheme: Schemas.vscodeRemote, - formatting: { - label: '${path}', - separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/', - tildify: remoteEnvironment.os !== OperatingSystem.Windows, - normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows, - workspaceSuffix: isWeb ? undefined : Schemas.vscodeRemote - } + formatting + }); + this.labelService.registerFormatter({ + scheme: Schemas.userData, + formatting }); } }); diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index d2f8c0bcd5f..c427c47df26 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -15,7 +15,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { MenuId, IMenuService, MenuItemAction, IMenu, MenuRegistry, registerAction } from 'vs/platform/actions/common/actions'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchContributionsExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { ILabelService } from 'vs/platform/label/common/label'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -91,11 +91,11 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc menu: { menuId: MenuId.CommandPalette }, - handler: (_accessor) => this.remoteAuthority && hostService.openEmptyWindow({ reuse: true }) + handler: (_accessor) => this.remoteAuthority && hostService.openWindow({ forceReuseWindow: true }) }); // Pending entry until extensions are ready - this.renderWindowIndicator(nls.localize('host.open', "$(sync~spin) Opening Remote..."), undefined, WINDOW_ACTIONS_COMMAND_ID); + this.renderWindowIndicator('$(sync~spin) ' + nls.localize('host.open', "Opening Remote..."), undefined, WINDOW_ACTIONS_COMMAND_ID); this.connectionState = 'initializing'; RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState); @@ -365,6 +365,18 @@ workbenchContributionsRegistry.registerWorkbenchContribution(RemoteWindowActiveI workbenchContributionsRegistry.registerWorkbenchContribution(RemoteTelemetryEnablementUpdater, LifecyclePhase.Ready); workbenchContributionsRegistry.registerWorkbenchContribution(RemoteEmptyWorkbenchPresentation, LifecyclePhase.Starting); +const extensionKindSchema = { + 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.") + ], +}; + Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ id: 'remote', @@ -376,16 +388,8 @@ Registry.as(ConfigurationExtensions.Configuration) markdownDescription: nls.localize('remote.extensionKind', "Override the kind of an extension. `ui` extensions are installed and run on the local machine while `workspace` extensions are run on the remote. By overriding an extension's default kind using this setting, you specify if that extension should be installed and enabled locally or remotely."), patternProperties: { '([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$': { - 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: 'ui' + oneOf: [{ type: 'array', items: extensionKindSchema }, extensionKindSchema], + default: 'ui', }, }, default: { diff --git a/src/vs/workbench/contrib/scm/browser/activity.ts b/src/vs/workbench/contrib/scm/browser/activity.ts index a76d60e0e0e..d1447fb30d3 100644 --- a/src/vs/workbench/contrib/scm/browser/activity.ts +++ b/src/vs/workbench/contrib/scm/browser/activity.ts @@ -4,16 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { basename } from 'vs/base/common/resources'; +import { basename, relativePath } from 'vs/base/common/resources'; import { IDisposable, dispose, Disposable, DisposableStore, combinedDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { VIEWLET_ID, ISCMService, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/workbench/services/statusbar/common/statusbar'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { commonPrefixLength } from 'vs/base/common/strings'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; function getCount(repository: ISCMRepository): number { @@ -51,23 +50,23 @@ export class SCMStatusController implements IWorkbenchContribution { this.onDidAddRepository(repository); } - editorService.onDidActiveEditorChange(this.onDidActiveEditorChange, this, this.disposables); + editorService.onDidActiveEditorChange(this.tryFocusRepositoryBasedOnActiveEditor, this, this.disposables); this.renderActivityCount(); } - private onDidActiveEditorChange(): void { + private tryFocusRepositoryBasedOnActiveEditor(): boolean { if (!this.editorService.activeEditor) { - return; + return false; } const resource = this.editorService.activeEditor.getResource(); - if (!resource || resource.scheme !== 'file') { - return; + if (!resource) { + return false; } let bestRepository: ISCMRepository | null = null; - let bestMatchLength = Number.NEGATIVE_INFINITY; + let bestMatchLength = Number.POSITIVE_INFINITY; for (const repository of this.scmService.repositories) { const root = repository.provider.rootUri; @@ -76,22 +75,24 @@ export class SCMStatusController implements IWorkbenchContribution { continue; } - const rootFSPath = root.fsPath; - const prefixLength = commonPrefixLength(rootFSPath, resource.fsPath); + const path = relativePath(root, resource); - if (prefixLength === rootFSPath.length && prefixLength > bestMatchLength) { + if (path && !/^\.\./.test(path) && path.length < bestMatchLength) { bestRepository = repository; - bestMatchLength = prefixLength; + bestMatchLength = path.length; } } - if (bestRepository) { - this.onDidFocusRepository(bestRepository); + if (!bestRepository) { + return false; } + + this.focusRepository(bestRepository); + return true; } private onDidAddRepository(repository: ISCMRepository): void { - const focusDisposable = repository.onDidFocus(() => this.onDidFocusRepository(repository)); + const focusDisposable = repository.onDidFocus(() => this.focusRepository(repository)); const onDidChange = Event.any(repository.provider.onDidChange, repository.provider.onDidChangeResources); const changeDisposable = onDidChange(() => this.renderActivityCount()); @@ -102,7 +103,7 @@ export class SCMStatusController implements IWorkbenchContribution { this.disposables = this.disposables.filter(d => d !== removeDisposable); if (this.scmService.repositories.length === 0) { - this.onDidFocusRepository(undefined); + this.focusRepository(undefined); } else if (this.focusedRepository === repository) { this.scmService.repositories[0].focus(); } @@ -113,12 +114,18 @@ export class SCMStatusController implements IWorkbenchContribution { const disposable = combinedDisposable(focusDisposable, changeDisposable, removeDisposable); this.disposables.push(disposable); - if (!this.focusedRepository) { - this.onDidFocusRepository(repository); + if (this.focusedRepository) { + return; } + + if (this.tryFocusRepositoryBasedOnActiveEditor()) { + return; + } + + this.focusRepository(repository); } - private onDidFocusRepository(repository: ISCMRepository | undefined): void { + private focusRepository(repository: ISCMRepository | undefined): void { if (this.focusedRepository === repository) { return; } diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index c7aec31036f..b5492376035 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -17,7 +17,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { URI } from 'vs/base/common/uri'; -import { ISCMService, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm'; +import { ISCMService, ISCMRepository, ISCMProvider } from 'vs/workbench/contrib/scm/common/scm'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromId, IThemeService } from 'vs/platform/theme/common/themeService'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; @@ -37,7 +37,7 @@ import { IDiffEditorOptions, EditorOption } from 'vs/editor/common/config/editor import { Action, IAction, ActionRunner } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { basename } from 'vs/base/common/resources'; +import { basename, isEqualOrParent } from 'vs/base/common/resources'; import { MenuId, IMenuService, IMenu, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { createAndFillInActionBarActions, ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IChange, IEditorModel, ScrollType, IEditorContribution, IDiffEditorModel } from 'vs/editor/common/editorCommon'; @@ -149,7 +149,7 @@ function getChangeTypeColor(theme: ITheme, changeType: ChangeType): Color | unde } } -function getOuterEditorFromDiffEditor(accessor: ServicesAccessor): ICodeEditor | undefined { +function getOuterEditorFromDiffEditor(accessor: ServicesAccessor): ICodeEditor | null { const diffEditors = accessor.get(ICodeEditorService).listDiffEditors(); for (const diffEditor of diffEditors) { @@ -163,11 +163,11 @@ function getOuterEditorFromDiffEditor(accessor: ServicesAccessor): ICodeEditor | class DirtyDiffWidget extends PeekViewWidget { - private diffEditor: EmbeddedDiffEditorWidget; + private diffEditor!: EmbeddedDiffEditorWidget; private title: string; private menu: IMenu; - private index: number; - private change: IChange; + private index: number = 0; + private change: IChange | undefined; private height: number | undefined = undefined; private contextKeyService: IContextKeyService; @@ -320,7 +320,7 @@ class DirtyDiffWidget extends PeekViewWidget { super._doLayoutBody(height, width); this.diffEditor.layout({ height, width }); - if (typeof this.height === 'undefined') { + if (typeof this.height === 'undefined' && this.change) { this.revealChange(this.change); } @@ -556,7 +556,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ export class DirtyDiffController extends Disposable implements IEditorContribution { - private static readonly ID = 'editor.contrib.dirtydiff'; + public static readonly ID = 'editor.contrib.dirtydiff'; static get(editor: ICodeEditor): DirtyDiffController { return editor.getContribution(DirtyDiffController.ID); @@ -567,7 +567,7 @@ export class DirtyDiffController extends Disposable implements IEditorContributi private model: DirtyDiffModel | null = null; private widget: DirtyDiffWidget | null = null; private currentIndex: number = -1; - private readonly isDirtyDiffVisible: IContextKey; + private readonly isDirtyDiffVisible!: IContextKey; private session: IDisposable = Disposable.None; private mouseDownInfo: { lineNumber: number } | null = null; private enabled = false; @@ -588,10 +588,6 @@ export class DirtyDiffController extends Disposable implements IEditorContributi } } - getId(): string { - return DirtyDiffController.ID; - } - canNavigate(): boolean { return this.currentIndex === -1 || (!!this.model && this.model.changes.length > 1); } @@ -676,7 +672,10 @@ export class DirtyDiffController extends Disposable implements IEditorContributi const disposables = new DisposableStore(); disposables.add(Event.once(this.widget.onDidClose)(this.close, this)); - disposables.add(model.onDidChange(this.onDidModelChange, this)); + Event.chain(model.onDidChange) + .filter(e => e.diff.length > 0) + .map(e => e.diff) + .event(this.onDidModelChange, this, disposables); disposables.add(this.widget); disposables.add(toDisposable(() => { @@ -951,9 +950,26 @@ function compareChanges(a: IChange, b: IChange): number { return a.originalEndLineNumber - b.originalEndLineNumber; } +function createProviderComparer(uri: URI): (a: ISCMProvider, b: ISCMProvider) => number { + return (a, b) => { + const aIsParent = isEqualOrParent(uri, a.rootUri!); + const bIsParent = isEqualOrParent(uri, b.rootUri!); + + if (aIsParent && bIsParent) { + return a.rootUri!.fsPath.length - b.rootUri!.fsPath.length; + } else if (aIsParent) { + return -1; + } else if (bIsParent) { + return 1; + } else { + return 0; + } + }; +} + export class DirtyDiffModel extends Disposable { - private _originalModel: ITextModel | null; + private _originalModel: ITextModel | null = null; get original(): ITextModel | null { return this._originalModel; } get modified(): ITextModel | null { return this._editorModel; } @@ -962,13 +978,11 @@ export class DirtyDiffModel extends Disposable { private repositoryDisposables = new Set(); private readonly originalModelDisposables = this._register(new DisposableStore()); - private readonly _onDidChange = new Emitter[]>(); - readonly onDidChange: Event[]> = this._onDidChange.event; + private readonly _onDidChange = new Emitter<{ changes: IChange[], diff: ISplice[] }>(); + readonly onDidChange: Event<{ changes: IChange[], diff: ISplice[] }> = this._onDidChange.event; private _changes: IChange[] = []; - get changes(): IChange[] { - return this._changes; - } + get changes(): IChange[] { return this._changes; } private _editorModel: ITextModel | null; @@ -1022,10 +1036,7 @@ export class DirtyDiffModel extends Disposable { const diff = sortedDiff(this._changes, changes, compareChanges); this._changes = changes; - - if (diff.length > 0) { - this._onDidChange.fire(diff); - } + this._onDidChange.fire({ changes, diff }); }); } @@ -1082,13 +1093,25 @@ export class DirtyDiffModel extends Disposable { }); } - private getOriginalResource(): Promise { + private async getOriginalResource(): Promise { if (!this._editorModel) { return Promise.resolve(null); } const uri = this._editorModel.uri; - return first(this.scmService.repositories.map(r => () => r.provider.getOriginalResource(uri))); + const providers = this.scmService.repositories.map(r => r.provider); + const rootedProviders = providers.filter(p => !!p.rootUri); + + rootedProviders.sort(createProviderComparer(uri)); + + const result = await first(rootedProviders.map(p => () => p.getOriginalResource(uri))); + + if (result) { + return result; + } + + const nonRootedProviders = providers.filter(p => !p.rootUri); + return first(nonRootedProviders.map(p => () => p.getOriginalResource(uri))); } findNextClosestChange(lineNumber: number, inclusive = true): number { @@ -1177,6 +1200,10 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor const onDidChangeDiffWidthConfiguration = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.diffDecorationsGutterWidth')); onDidChangeDiffWidthConfiguration(this.onDidChangeDiffWidthConfiguration, this); this.onDidChangeDiffWidthConfiguration(); + + const onDidChangeDiffVisibilityConfiguration = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.diffDecorationsGutterVisibility')); + onDidChangeDiffVisibilityConfiguration(this.onDidChangeDiffVisibiltiyConfiguration, this); + this.onDidChangeDiffVisibiltiyConfiguration(); } private onDidChangeConfiguration(): void { @@ -1199,6 +1226,16 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor this.stylesheet.innerHTML = `.monaco-editor .dirty-diff-modified,.monaco-editor .dirty-diff-added{border-left-width:${width}px;}`; } + private onDidChangeDiffVisibiltiyConfiguration(): void { + const visibility = this.configurationService.getValue('scm.diffDecorationsGutterVisibility'); + + this.stylesheet.innerHTML = ` + .monaco-editor .dirty-diff-modified, .monaco-editor .dirty-diff-added, .monaco-editor .dirty-diff-deleted { + opacity: ${visibility === 'always' ? 1 : 0}; + } + `; + } + private enable(): void { if (this.enabled) { this.disable(); @@ -1278,7 +1315,7 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor } } -registerEditorContribution(DirtyDiffController); +registerEditorContribution(DirtyDiffController.ID, DirtyDiffController); registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const editorGutterModifiedBackgroundColor = theme.getColor(editorGutterModifiedBackground); @@ -1286,10 +1323,14 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { collector.addRule(` .monaco-editor .dirty-diff-modified { border-left: 3px solid ${editorGutterModifiedBackgroundColor}; + transition: opacity 0.5s; } .monaco-editor .dirty-diff-modified:before { background: ${editorGutterModifiedBackgroundColor}; } + .monaco-editor .margin:hover .dirty-diff-modified { + opacity: 1; + } `); } @@ -1298,10 +1339,14 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { collector.addRule(` .monaco-editor .dirty-diff-added { border-left: 3px solid ${editorGutterAddedBackgroundColor}; + transition: opacity 0.5s; } .monaco-editor .dirty-diff-added:before { background: ${editorGutterAddedBackgroundColor}; } + .monaco-editor .margin:hover .dirty-diff-added { + opacity: 1; + } `); } @@ -1310,10 +1355,14 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { collector.addRule(` .monaco-editor .dirty-diff-deleted:after { border-left: 4px solid ${editorGutteDeletedBackgroundColor}; + transition: opacity 0.5s; } .monaco-editor .dirty-diff-deleted:before { background: ${editorGutteDeletedBackgroundColor}; } + .monaco-editor .margin:hover .dirty-diff-added { + opacity: 1; + } `); } }); diff --git a/src/vs/workbench/contrib/scm/browser/mainPanel.ts b/src/vs/workbench/contrib/scm/browser/mainPanel.ts index 134f70ce0ba..d45bdb1b57c 100644 --- a/src/vs/workbench/contrib/scm/browser/mainPanel.ts +++ b/src/vs/workbench/contrib/scm/browser/mainPanel.ts @@ -10,7 +10,6 @@ import { basename } from 'vs/base/common/resources'; import { IDisposable, dispose, Disposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { append, $, toggleClass } from 'vs/base/browser/dom'; -import { List } from 'vs/base/browser/ui/list/listWidget'; import { IListVirtualDelegate, IListRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list'; import { ISCMService, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; @@ -26,7 +25,7 @@ import { ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionba import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; import { Command } from 'vs/editor/common/modes'; -import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; +import { renderCodicons } from 'vs/base/browser/ui/codiconLabel/codiconLabel'; import { WorkbenchList } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewDescriptor } from 'vs/workbench/common/views'; @@ -82,8 +81,8 @@ class StatusBarActionViewItem extends ActionViewItem { } updateLabel(): void { - if (this.options.label) { - this.label.innerHTML = renderOcticons(this.getAction().label); + if (this.options.label && this.label) { + this.label.innerHTML = renderCodicons(this.getAction().label); } } } @@ -173,7 +172,7 @@ export class MainPanel extends ViewletPanel { static readonly ID = 'scm.mainPanel'; static readonly TITLE = localize('scm providers', "Source Control Providers"); - private list: List; + private list!: WorkbenchList; constructor( protected viewModel: IViewModel, @@ -194,7 +193,7 @@ export class MainPanel extends ViewletPanel { const renderer = this.instantiationService.createInstance(ProviderRenderer); const identityProvider = { getId: (r: ISCMRepository) => r.provider.id }; - this.list = this.instantiationService.createInstance(WorkbenchList, `SCM Main`, container, delegate, [renderer], { + this.list = this.instantiationService.createInstance>(WorkbenchList, `SCM Main`, container, delegate, [renderer], { identityProvider, horizontalScrolling: false }); diff --git a/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg b/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg deleted file mode 100644 index 5092b857329..00000000000 --- a/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css index bf3ca36d286..b629bb08c18 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css +++ b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css @@ -3,10 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .activitybar > .content .monaco-action-bar .action-label.scm { - -webkit-mask: url('scm-activity-bar.svg') no-repeat 50% 50%; -} - .monaco-workbench .viewlet.scm-viewlet .collapsible.header .actions { width: initial; flex: 1; @@ -41,8 +37,30 @@ } .scm-viewlet .monaco-list-row > .scm-provider > .monaco-action-bar .action-item { + padding: 0 4px; overflow: hidden; text-overflow: ellipsis; + display: flex; + align-items: center; +} + +.scm-viewlet .monaco-list-row > .scm-provider > .monaco-action-bar .action-label { + text-overflow: ellipsis; + overflow: hidden; +} + +.scm-viewlet .monaco-list-row > .scm-provider > .monaco-action-bar .action-label .codicon { + font-size: 14px; +} + +.scm-viewlet .monaco-list-row > .scm-provider > .monaco-action-bar .action-item:last-of-type { + padding-right: 0; +} + +.scm-viewlet .scm-provider > .name, +.scm-viewlet .scm-provider > .count { + display: flex; + align-items: center; } .scm-viewlet .scm-provider > .count { @@ -96,12 +114,8 @@ text-decoration: line-through; } -.scm-viewlet .monaco-list-row .resource > .name > .monaco-icon-label::after { - padding: 0 8px; -} - .scm-viewlet .monaco-list-row .resource-group > .count { - padding: 0 8px; + padding: 0 12px 0 8px; display: flex; } @@ -110,6 +124,7 @@ height: 100%; background-repeat: no-repeat; background-position: 50% 50%; + margin-right: 8px; } .scm-viewlet .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions { @@ -146,7 +161,7 @@ .scm-viewlet .scm-editor { box-sizing: border-box; - padding: 5px 9px 5px 16px; + padding: 5px 12px 5px 16px; } .scm-viewlet .scm-editor.hidden { @@ -174,3 +189,7 @@ width: 8px !important; margin-right: 0 !important; } + +.scm-viewlet .scm-status.show-file-icons.hide-arrows.tree-view-mode .monaco-tl-indent .indent-guide:first-child { + border: none; +} diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPanel.ts b/src/vs/workbench/contrib/scm/browser/repositoryPanel.ts index 6a2e94d07da..a1c746e55cb 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPanel.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPanel.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/scmViewlet'; import { Event, Emitter } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; -import { basename } from 'vs/base/common/resources'; +import { basename, isEqual } from 'vs/base/common/resources'; import { IDisposable, Disposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { append, $, addClass, toggleClass, trackFocus, removeClass } from 'vs/base/browser/dom'; @@ -32,12 +32,12 @@ import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import { format } from 'vs/base/common/strings'; import { WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ThrottledDelayer } from 'vs/base/common/async'; +import { ThrottledDelayer, disposableTimeout } from 'vs/base/common/async'; import { INotificationService } from 'vs/platform/notification/common/notification'; import * as platform from 'vs/base/common/platform'; import { ITreeNode, ITreeFilter, ITreeSorter, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; +import { ResourceTree, IResourceNode } from 'vs/base/common/resourceTree'; import { ISequence, ISplice } from 'vs/base/common/sequence'; -import { ResourceTree, IBranchNode, INode } from 'vs/base/common/resourceTree'; import { ObjectTree, ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/tree/objectTree'; import { Iterator } from 'vs/base/common/iterator'; import { ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; @@ -47,11 +47,13 @@ import { compareFileNames } from 'vs/base/common/comparers'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { IViewDescriptor } from 'vs/workbench/common/views'; import { localize } from 'vs/nls'; -import { flatten } from 'vs/base/common/arrays'; +import { flatten, find } from 'vs/base/common/arrays'; import { memoize } from 'vs/base/common/decorators'; import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; -type TreeElement = ISCMResourceGroup | IBranchNode | ISCMResource; +type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; interface ResourceGroupTemplate { readonly name: HTMLElement; @@ -63,7 +65,7 @@ interface ResourceGroupTemplate { class ResourceGroupRenderer implements ICompressibleTreeRenderer { - static TEMPLATE_ID = 'resource group'; + static readonly TEMPLATE_ID = 'resource group'; get templateId(): string { return ResourceGroupRenderer.TEMPLATE_ID; } constructor( @@ -130,11 +132,11 @@ interface ResourceTemplate { class MultipleSelectionActionRunner extends ActionRunner { - constructor(private getSelectedResources: () => (ISCMResource | IBranchNode)[]) { + constructor(private getSelectedResources: () => (ISCMResource | IResourceNode)[]) { super(); } - runAction(action: IAction, context: ISCMResource | IBranchNode): Promise { + runAction(action: IAction, context: ISCMResource | IResourceNode): Promise { if (!(action instanceof MenuItemAction)) { return super.runAction(action, context); } @@ -142,21 +144,21 @@ class MultipleSelectionActionRunner extends ActionRunner { const selection = this.getSelectedResources(); const contextIsSelected = selection.some(s => s === context); const actualContext = contextIsSelected ? selection : [context]; - const args = flatten(actualContext.map(e => ResourceTree.isBranchNode(e) ? ResourceTree.collect(e) : [e])); + const args = flatten(actualContext.map(e => ResourceTree.isResourceNode(e) ? ResourceTree.collect(e) : [e])); return action.run(...args); } } -class ResourceRenderer implements ICompressibleTreeRenderer, FuzzyScore, ResourceTemplate> { +class ResourceRenderer implements ICompressibleTreeRenderer, FuzzyScore, ResourceTemplate> { - static TEMPLATE_ID = 'resource'; + static readonly TEMPLATE_ID = 'resource'; get templateId(): string { return ResourceRenderer.TEMPLATE_ID; } constructor( private viewModelProvider: () => ViewModel, private labels: ResourceLabels, private actionViewItemProvider: IActionViewItemProvider, - private getSelectedResources: () => (ISCMResource | IBranchNode)[], + private getSelectedResources: () => (ISCMResource | IResourceNode)[], private themeService: IThemeService, private menus: SCMMenus ) { } @@ -177,16 +179,17 @@ class ResourceRenderer implements ICompressibleTreeRenderer | ITreeNode, FuzzyScore>, index: number, template: ResourceTemplate): void { + renderElement(node: ITreeNode | ITreeNode, FuzzyScore>, index: number, template: ResourceTemplate): void { template.elementDisposables.dispose(); const elementDisposables = new DisposableStore(); const resourceOrFolder = node.element; const theme = this.themeService.getTheme(); - const icon = !ResourceTree.isBranchNode(resourceOrFolder) && (theme.type === LIGHT ? resourceOrFolder.decorations.icon : resourceOrFolder.decorations.iconDark); + const iconResource = ResourceTree.isResourceNode(resourceOrFolder) ? resourceOrFolder.element : resourceOrFolder; + const icon = iconResource && (theme.type === LIGHT ? iconResource.decorations.icon : iconResource.decorations.iconDark); - const uri = ResourceTree.isBranchNode(resourceOrFolder) ? resourceOrFolder.uri : resourceOrFolder.sourceUri; - const fileKind = ResourceTree.isBranchNode(resourceOrFolder) ? FileKind.FOLDER : FileKind.FILE; + const uri = ResourceTree.isResourceNode(resourceOrFolder) ? resourceOrFolder.uri : resourceOrFolder.sourceUri; + const fileKind = ResourceTree.isResourceNode(resourceOrFolder) ? FileKind.FOLDER : FileKind.FILE; const viewModel = this.viewModelProvider(); template.fileLabel.setFile(uri, { @@ -199,17 +202,23 @@ class ResourceRenderer implements ICompressibleTreeRenderer | ITreeNode, FuzzyScore>, index: number, template: ResourceTemplate): void { + disposeElement(resource: ITreeNode | ITreeNode, FuzzyScore>, index: number, template: ResourceTemplate): void { template.elementDisposables.dispose(); } - renderCompressedElements(node: ITreeNode | ICompressedTreeNode>, FuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void { + renderCompressedElements(node: ITreeNode | ICompressedTreeNode>, FuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void { template.elementDisposables.dispose(); const elementDisposables = new DisposableStore(); - const compressed = node.element as ICompressedTreeNode>; + const compressed = node.element as ICompressedTreeNode>; const folder = compressed.elements[compressed.elements.length - 1]; const label = compressed.elements.map(e => e.name).join('/'); @@ -259,7 +268,7 @@ class ResourceRenderer implements ICompressibleTreeRenderer | ICompressedTreeNode>, FuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void { + disposeCompressedElements(node: ITreeNode | ICompressedTreeNode>, FuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void { template.elementDisposables.dispose(); } @@ -274,7 +283,7 @@ class ProviderListDelegate implements IListVirtualDelegate { getHeight() { return 22; } getTemplateId(element: TreeElement) { - if (ResourceTree.isBranchNode(element) || isSCMResource(element)) { + if (ResourceTree.isResourceNode(element) || isSCMResource(element)) { return ResourceRenderer.TEMPLATE_ID; } else { return ResourceGroupRenderer.TEMPLATE_ID; @@ -285,7 +294,7 @@ class ProviderListDelegate implements IListVirtualDelegate { class SCMTreeFilter implements ITreeFilter { filter(element: TreeElement): boolean { - if (ResourceTree.isBranchNode(element)) { + if (ResourceTree.isResourceNode(element)) { return true; } else if (isSCMResourceGroup(element)) { return element.elements.length > 0 || !element.hideWhenEmpty; @@ -311,15 +320,15 @@ export class SCMTreeSorter implements ITreeSorter { return 0; } - const oneIsDirectory = ResourceTree.isBranchNode(one); - const otherIsDirectory = ResourceTree.isBranchNode(other); + const oneIsDirectory = ResourceTree.isResourceNode(one); + const otherIsDirectory = ResourceTree.isResourceNode(other); if (oneIsDirectory !== otherIsDirectory) { return oneIsDirectory ? -1 : 1; } - const oneName = ResourceTree.isBranchNode(one) ? one.name : basename((one as ISCMResource).sourceUri); - const otherName = ResourceTree.isBranchNode(other) ? other.name : basename((other as ISCMResource).sourceUri); + const oneName = ResourceTree.isResourceNode(one) ? one.name : basename((one as ISCMResource).sourceUri); + const otherName = ResourceTree.isResourceNode(other) ? other.name : basename((other as ISCMResource).sourceUri); return compareFileNames(oneName, otherName); } @@ -328,7 +337,7 @@ export class SCMTreeSorter implements ITreeSorter { export class SCMTreeKeyboardNavigationLabelProvider implements ICompressibleKeyboardNavigationLabelProvider { getKeyboardNavigationLabel(element: TreeElement): { toString(): string; } | undefined { - if (ResourceTree.isBranchNode(element)) { + if (ResourceTree.isResourceNode(element)) { return element.name; } else if (isSCMResourceGroup(element)) { return element.label; @@ -338,7 +347,7 @@ export class SCMTreeKeyboardNavigationLabelProvider implements ICompressibleKeyb } getCompressedNodeKeyboardNavigationLabel(elements: TreeElement[]): { toString(): string | undefined; } | undefined { - const folders = elements as IBranchNode[]; + const folders = elements as IResourceNode[]; return folders.map(e => e.name).join('/'); } } @@ -346,7 +355,7 @@ export class SCMTreeKeyboardNavigationLabelProvider implements ICompressibleKeyb class SCMResourceIdentityProvider implements IIdentityProvider { getId(element: TreeElement): string { - if (ResourceTree.isBranchNode(element)) { + if (ResourceTree.isResourceNode(element)) { const group = element.context; return `${group.provider.contextValue}/${group.id}/$FOLDER/${element.uri.toString()}`; } else if (isSCMResource(element)) { @@ -372,36 +381,41 @@ function groupItemAsTreeElement(item: IGroupItem, mode: ViewModelMode): ICompres ? Iterator.map(Iterator.fromArray(item.resources), element => ({ element, incompressible: true })) : Iterator.map(item.tree.root.children, node => asTreeElement(node, true)); - return { element: item.group, children, incompressible: true }; + return { element: item.group, children, incompressible: true, collapsible: true }; } -function asTreeElement(node: INode, incompressible: boolean): ICompressedTreeElement { - if (ResourceTree.isBranchNode(node)) { - return { - element: node, - children: Iterator.map(node.children, node => asTreeElement(node, false)), - incompressible, - collapsed: false - }; - } - - return { element: node.element, incompressible: true }; +function asTreeElement(node: IResourceNode, forceIncompressible: boolean): ICompressedTreeElement { + return { + element: (node.childrenCount === 0 && node.element) ? node.element : node, + children: Iterator.map(node.children, node => asTreeElement(node, false)), + incompressible: !!node.element || forceIncompressible + }; } const enum ViewModelMode { - List = 'codicon-filter', - Tree = 'codicon-selection' + List = 'list', + Tree = 'tree' } class ViewModel { - private _mode = ViewModelMode.Tree; private readonly _onDidChangeMode = new Emitter(); readonly onDidChangeMode = this._onDidChangeMode.event; get mode(): ViewModelMode { return this._mode; } set mode(mode: ViewModelMode) { this._mode = mode; + + for (const item of this.items) { + item.tree.clear(); + + if (mode === ViewModelMode.Tree) { + for (const resource of item.resources) { + item.tree.add(resource.sourceUri, resource); + } + } + } + this.refresh(); this._onDidChangeMode.fire(mode); } @@ -409,11 +423,15 @@ class ViewModel { private items: IGroupItem[] = []; private visibilityDisposables = new DisposableStore(); private scrollTop: number | undefined; + private firstVisible = true; private disposables = new DisposableStore(); constructor( private groups: ISequence, - private tree: ObjectTree + private tree: ObjectTree, + private _mode: ViewModelMode, + @IEditorService protected editorService: IEditorService, + @IConfigurationService protected configurationService: IConfigurationService, ) { } private onDidSpliceGroups({ start, deleteCount, toInsert }: ISplice): void { @@ -427,10 +445,12 @@ class ViewModel { group.onDidSplice(splice => this.onDidSpliceGroup(item, splice)) ); - const item = { group, resources, tree, disposable }; + const item: IGroupItem = { group, resources, tree, disposable }; - for (const resource of resources) { - item.tree.add(resource.sourceUri, resource); + if (this._mode === ViewModelMode.Tree) { + for (const resource of resources) { + item.tree.add(resource.sourceUri, resource); + } } itemsToInsert.push(item); @@ -446,14 +466,16 @@ class ViewModel { } private onDidSpliceGroup(item: IGroupItem, { start, deleteCount, toInsert }: ISplice): void { - for (const resource of toInsert) { - item.tree.add(resource.sourceUri, resource); - } - const deleted = item.resources.splice(start, deleteCount, ...toInsert); - for (const resource of deleted) { - item.tree.delete(resource.sourceUri); + if (this._mode === ViewModelMode.Tree) { + for (const resource of deleted) { + item.tree.delete(resource.sourceUri); + } + + for (const resource of toInsert) { + item.tree.add(resource.sourceUri, resource); + } } this.refresh(item); @@ -469,6 +491,9 @@ class ViewModel { this.tree.scrollTop = this.scrollTop; this.scrollTop = undefined; } + + this.editorService.onDidActiveEditorChange(this.onDidActiveEditorChange, this, this.visibilityDisposables); + this.onDidActiveEditorChange(); } else { this.visibilityDisposables.dispose(); this.onDidSpliceGroups({ start: 0, deleteCount: this.items.length, toInsert: [] }); @@ -484,6 +509,45 @@ class ViewModel { } } + private onDidActiveEditorChange(): void { + if (!this.configurationService.getValue('scm.autoReveal')) { + return; + } + + if (this.firstVisible) { + this.firstVisible = false; + this.visibilityDisposables.add(disposableTimeout(() => this.onDidActiveEditorChange(), 250)); + return; + } + + const editor = this.editorService.activeEditor; + + if (!editor) { + return; + } + + const uri = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); + + if (!uri) { + return; + } + + // go backwards from last group + for (let i = this.items.length - 1; i >= 0; i--) { + const item = this.items[i]; + const resource = this.mode === ViewModelMode.Tree + ? item.tree.getNode(uri)?.element + : find(item.resources, r => isEqual(r.sourceUri, uri)); + + if (resource) { + this.tree.reveal(resource); + this.tree.setSelection([resource]); + this.tree.setFocus([resource]); + return; + } + } + } + dispose(): void { this.visibilityDisposables.dispose(); this.disposables.dispose(); @@ -507,7 +571,8 @@ export class ToggleViewModeAction extends Action { } private onDidChangeMode(mode: ViewModelMode): void { - this.class = `scm-action toggle-view-mode ${mode}`; + const iconClass = mode === ViewModelMode.List ? 'codicon-filter' : 'codicon-selection'; + this.class = `scm-action toggle-view-mode ${iconClass}`; } } @@ -523,15 +588,16 @@ export class RepositoryPanel extends ViewletPanel { private cachedHeight: number | undefined = undefined; private cachedWidth: number | undefined = undefined; - private inputBoxContainer: HTMLElement; - private inputBox: InputBox; - private listContainer: HTMLElement; - private tree: ObjectTree; - private viewModel: ViewModel; - private listLabels: ResourceLabels; + private inputBoxContainer!: HTMLElement; + private inputBox!: InputBox; + private listContainer!: HTMLElement; + private tree!: ObjectTree; + private viewModel!: ViewModel; + private listLabels!: ResourceLabels; private menus: SCMMenus; private toggleViewModelModeAction: ToggleViewModeAction | undefined; protected contextKeyService: IContextKeyService; + private commitTemplate = ''; constructor( readonly repository: ISCMRepository, @@ -546,7 +612,8 @@ export class RepositoryPanel extends ViewletPanel { @IInstantiationService protected instantiationService: IInstantiationService, @IConfigurationService protected configurationService: IConfigurationService, @IContextKeyService contextKeyService: IContextKeyService, - @IMenuService protected menuService: IMenuService + @IMenuService protected menuService: IMenuService, + @IStorageService private storageService: IStorageService ) { super(options, keybindingService, contextMenuService, configurationService, contextKeyService); @@ -633,10 +700,10 @@ export class RepositoryPanel extends ViewletPanel { this._register(this.inputBox.onDidHeightChange(() => this.layoutBody())); if (this.repository.provider.onDidChangeCommitTemplate) { - this._register(this.repository.provider.onDidChangeCommitTemplate(this.updateInputBox, this)); + this._register(this.repository.provider.onDidChangeCommitTemplate(this.onDidChangeCommitTemplate, this)); } - this.updateInputBox(); + this.onDidChangeCommitTemplate(); // Input box visibility this._register(this.repository.input.onDidChangeVisibility(this.updateInputBoxVisibility, this)); @@ -666,7 +733,7 @@ export class RepositoryPanel extends ViewletPanel { const keyboardNavigationLabelProvider = new SCMTreeKeyboardNavigationLabelProvider(); const identityProvider = new SCMResourceIdentityProvider(); - this.tree = this.instantiationService.createInstance( + this.tree = this.instantiationService.createInstance>( WorkbenchCompressibleObjectTree, 'SCM Tree Repo', this.listContainer, @@ -682,32 +749,38 @@ export class RepositoryPanel extends ViewletPanel { this._register(Event.chain(this.tree.onDidOpen) .map(e => e.elements[0]) - .filter(e => !!e && !ResourceTree.isBranchNode(e) && isSCMResource(e)) + .filter(e => !!e && !isSCMResourceGroup(e) && !ResourceTree.isResourceNode(e)) .on(this.open, this)); this._register(Event.chain(this.tree.onDidPin) .map(e => e.elements[0]) - .filter(e => !!e && !ResourceTree.isBranchNode(e) && isSCMResource(e)) + .filter(e => !!e && !isSCMResourceGroup(e) && !ResourceTree.isResourceNode(e)) .on(this.pin, this)); this._register(this.tree.onContextMenu(this.onListContextMenu, this)); this._register(this.tree); - this.viewModel = new ViewModel(this.repository.provider.groups, this.tree); + let mode = this.configurationService.getValue<'tree' | 'list'>('scm.defaultViewMode') === 'list' ? ViewModelMode.List : ViewModelMode.Tree; + + const rootUri = this.repository.provider.rootUri; + + if (typeof rootUri !== 'undefined') { + const storageMode = this.storageService.get(`scm.repository.viewMode:${rootUri.toString()}`, StorageScope.WORKSPACE) as ViewModelMode; + + if (typeof storageMode === 'string') { + mode = storageMode; + } + } + + this.viewModel = this.instantiationService.createInstance(ViewModel, this.repository.provider.groups, this.tree, mode); this._register(this.viewModel); addClass(this.listContainer, 'file-icon-themable-tree'); addClass(this.listContainer, 'show-file-icons'); - const updateIndentStyles = (theme: IFileIconTheme) => { - toggleClass(this.listContainer, 'list-view-mode', this.viewModel.mode === ViewModelMode.List); - toggleClass(this.listContainer, 'align-icons-and-twisties', this.viewModel.mode === ViewModelMode.Tree && theme.hasFileIcons && !theme.hasFolderIcons); - toggleClass(this.listContainer, 'hide-arrows', this.viewModel.mode === ViewModelMode.Tree && theme.hidesExplorerArrows === true); - }; - - updateIndentStyles(this.themeService.getFileIconTheme()); - this._register(this.themeService.onDidFileIconThemeChange(updateIndentStyles)); - this._register(this.viewModel.onDidChangeMode(() => updateIndentStyles(this.themeService.getFileIconTheme()))); + this.updateIndentStyles(this.themeService.getFileIconTheme()); + this._register(this.themeService.onDidFileIconThemeChange(this.updateIndentStyles, this)); + this._register(this.viewModel.onDidChangeMode(this.onDidChangeMode, this)); this.toggleViewModelModeAction = new ToggleViewModeAction(this.viewModel); this._register(this.toggleViewModelModeAction); @@ -717,6 +790,25 @@ export class RepositoryPanel extends ViewletPanel { this.updateActions(); } + private updateIndentStyles(theme: IFileIconTheme): void { + toggleClass(this.listContainer, 'list-view-mode', this.viewModel.mode === ViewModelMode.List); + toggleClass(this.listContainer, 'tree-view-mode', this.viewModel.mode === ViewModelMode.Tree); + toggleClass(this.listContainer, 'align-icons-and-twisties', this.viewModel.mode === ViewModelMode.Tree && theme.hasFileIcons && !theme.hasFolderIcons); + toggleClass(this.listContainer, 'hide-arrows', this.viewModel.mode === ViewModelMode.Tree && theme.hidesExplorerArrows === true); + } + + private onDidChangeMode(): void { + this.updateIndentStyles(this.themeService.getFileIconTheme()); + + const rootUri = this.repository.provider.rootUri; + + if (typeof rootUri === 'undefined') { + return; + } + + this.storageService.store(`scm.repository.viewMode:${rootUri.toString()}`, this.viewModel.mode, StorageScope.WORKSPACE); + } + layoutBody(height: number | undefined = this.cachedHeight, width: number | undefined = this.cachedWidth): void { if (height === undefined) { return; @@ -807,12 +899,16 @@ export class RepositoryPanel extends ViewletPanel { const element = e.element; let actions: IAction[] = []; - if (ResourceTree.isBranchNode(element)) { - actions = this.menus.getResourceFolderContextActions(element.context); - } else if (isSCMResource(element)) { - actions = this.menus.getResourceContextActions(element); - } else { + if (isSCMResourceGroup(element)) { actions = this.menus.getResourceGroupContextActions(element); + } else if (ResourceTree.isResourceNode(element)) { + if (element.element) { + actions = this.menus.getResourceContextActions(element.element); + } else { + actions = this.menus.getResourceFolderContextActions(element.context); + } + } else { + actions = this.menus.getResourceContextActions(element); } this.contextMenuService.showContextMenu({ @@ -823,17 +919,24 @@ export class RepositoryPanel extends ViewletPanel { }); } - private getSelectedResources(): (ISCMResource | IBranchNode)[] { + private getSelectedResources(): (ISCMResource | IResourceNode)[] { return this.tree.getSelection() .filter(r => !!r && !isSCMResourceGroup(r))! as any; } - private updateInputBox(): void { - if (typeof this.repository.provider.commitTemplate === 'undefined' || !this.repository.input.visible || this.inputBox.value) { + private onDidChangeCommitTemplate(): void { + if (typeof this.repository.provider.commitTemplate === 'undefined' || !this.repository.input.visible) { return; } - this.inputBox.value = this.repository.provider.commitTemplate; + const oldCommitTemplate = this.commitTemplate; + this.commitTemplate = this.repository.provider.commitTemplate; + + if (this.inputBox.value && this.inputBox.value !== oldCommitTemplate) { + return; + } + + this.inputBox.value = this.commitTemplate; } private updateInputBoxVisibility(): void { diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index bacb6796fa8..080c81d7fcd 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -28,7 +28,7 @@ import { SCMService } from 'vs/workbench/contrib/scm/common/scmService'; class OpenSCMViewletAction extends ShowViewletAction { static readonly ID = VIEWLET_ID; - static LABEL = localize('toggleGitViewlet', "Show Git"); + static readonly LABEL = localize('toggleGitViewlet', "Show Git"); constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService) { super(id, label, VIEWLET_ID, viewletService, editorGroupService, layoutService); @@ -42,7 +42,7 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie SCMViewlet, VIEWLET_ID, localize('source control', "Source Control"), - 'scm', + 'codicon-source-control', 2 )); @@ -90,6 +90,16 @@ Registry.as(ConfigurationExtensions.Configuration).regis default: 3, description: localize('diffGutterWidth', "Controls the width(px) of diff decorations in gutter (added & modified).") }, + 'scm.diffDecorationsGutterVisibility': { + type: 'string', + enum: ['always', 'hover'], + enumDescriptions: [ + localize('scm.diffDecorationsGutterVisibility.always', "Show the diff decorator in the gutter at all times."), + localize('scm.diffDecorationsGutterVisibility.hover', "Show the diff decorator in the gutter only on hover.") + ], + description: localize('scm.diffDecorationsGutterVisibility', "Controls the visibility of the Source Control diff decorator in the gutter."), + default: 'always' + }, 'scm.alwaysShowActions': { type: 'boolean', description: localize('alwaysShowActions', "Controls whether inline actions are always visible in the Source Control view."), @@ -105,7 +115,22 @@ Registry.as(ConfigurationExtensions.Configuration).regis ], description: localize('scm.countBadge', "Controls the Source Control count badge."), default: 'all' - } + }, + 'scm.defaultViewMode': { + type: 'string', + enum: ['tree', 'list'], + enumDescriptions: [ + localize('scm.defaultViewMode.tree', "Show the repository changes as a tree."), + localize('scm.defaultViewMode.list', "Show the repository changes as a list.") + ], + description: localize('scm.defaultViewMode', "Controls the default Source Control repository view mode."), + default: 'list' + }, + 'scm.autoReveal': { + type: 'boolean', + description: localize('autoReveal', "Controls whether the SCM view should automatically reveal and select files when opening them."), + default: true + }, } }); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 4ce397b202f..a4207212fd4 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -54,7 +54,7 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { private static readonly STATE_KEY = 'workbench.scm.views.state'; - private el: HTMLElement; + private el!: HTMLElement; private message: HTMLElement; private menus: SCMMenus; private _repositories: ISCMRepository[] = []; diff --git a/src/vs/workbench/contrib/scm/common/scm.ts b/src/vs/workbench/contrib/scm/common/scm.ts index 106a85c5f81..9b4a7f1d103 100644 --- a/src/vs/workbench/contrib/scm/common/scm.ts +++ b/src/vs/workbench/contrib/scm/common/scm.ts @@ -56,8 +56,8 @@ export interface ISCMProvider extends IDisposable { readonly rootUri?: URI; readonly count?: number; - readonly commitTemplate?: string; - readonly onDidChangeCommitTemplate?: Event; + readonly commitTemplate: string; + readonly onDidChangeCommitTemplate: Event; readonly onDidChangeStatusBarCommands?: Event; readonly acceptInputCommand?: Command; readonly statusBarCommands?: Command[]; diff --git a/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg b/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg deleted file mode 100644 index a7ea9ab29ab..00000000000 --- a/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/search/browser/media/search.contribution.css b/src/vs/workbench/contrib/search/browser/media/search.contribution.css deleted file mode 100644 index d0c241f8fb5..00000000000 --- a/src/vs/workbench/contrib/search/browser/media/search.contribution.css +++ /dev/null @@ -1,9 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* Activity Bar */ -.monaco-workbench .activitybar .monaco-action-bar .action-label.search { - -webkit-mask: url('search-activity-bar.svg') no-repeat 50% 50%; -} \ No newline at end of file diff --git a/src/vs/workbench/contrib/search/browser/media/searchview.css b/src/vs/workbench/contrib/search/browser/media/searchview.css index 1505caa8e6a..60b35d5ce92 100644 --- a/src/vs/workbench/contrib/search/browser/media/searchview.css +++ b/src/vs/workbench/contrib/search/browser/media/searchview.css @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ .search-view .search-widgets-container { - margin: 0px 9px 0 2px; + margin: 0px 12px 0 2px; padding-top: 6px; } @@ -25,7 +25,7 @@ .search-view .search-widget .search-container, .search-view .search-widget .replace-container { - margin-left: 17px; + margin-left: 18px; } .search-view .search-widget .monaco-inputbox > .wrapper { @@ -66,7 +66,6 @@ .search-view .search-widget .replace-input { position: relative; display: flex; - display: -webkit-flex; vertical-align: middle; width: auto !important; } @@ -82,7 +81,7 @@ } .search-view .search-widget .replace-container .monaco-action-bar { - margin-left: 3px; + margin-left: 0; } .search-view .search-widget .replace-container .monaco-action-bar { @@ -91,8 +90,12 @@ .search-view .search-widget .replace-container .monaco-action-bar .action-item .codicon { background-repeat: no-repeat; - width: 20px; + width: 25px; height: 25px; + margin-right: 0; + display: flex; + align-items: center; + justify-content: center; } .search-view .query-details { @@ -103,10 +106,9 @@ .search-view .query-details .more { position: absolute; - margin-right: 0.3em; - right: 0; + right: -2px; cursor: pointer; - width: 16px; + width: 25px; height: 16px; z-index: 2; /* Force it above the search results message, which has a negative top margin */ } @@ -154,6 +156,7 @@ margin-bottom: 0px; padding-bottom: 4px; user-select: text; + -webkit-user-select: text; } .search-view .foldermatch, @@ -245,6 +248,7 @@ background-repeat: no-repeat; width: 16px; height: 16px; + color: inherit; } /* Adjusts spacing in high contrast mode so that actions are vertically centered */ diff --git a/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts b/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts index 86adf6381f3..7b3f04acbd6 100644 --- a/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts @@ -68,7 +68,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { } private updateHandlers(configuration: IWorkbenchSearchConfiguration): void { - this.includeSymbols = configuration && configuration.search && configuration.search.quickOpen && configuration.search.quickOpen.includeSymbols; + this.includeSymbols = configuration?.search?.quickOpen?.includeSymbols; // Files this.openFileHandler.setOptions({ diff --git a/src/vs/workbench/contrib/search/browser/openFileHandler.ts b/src/vs/workbench/contrib/search/browser/openFileHandler.ts index 0374b69749f..ffb54bbfa76 100644 --- a/src/vs/workbench/contrib/search/browser/openFileHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openFileHandler.ts @@ -8,10 +8,8 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import { untildify } from 'vs/base/common/labels'; -import { Schemas } from 'vs/base/common/network'; import * as objects from 'vs/base/common/objects'; -import { isAbsolute } from 'vs/base/common/path'; -import { basename, dirname } from 'vs/base/common/resources'; +import { basename, dirname, toLocalResource } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { QuickOpenEntry, QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { IAutoFocus } from 'vs/base/parts/quickopen/common/quickOpen'; @@ -33,6 +31,8 @@ import { EditorInput, IWorkbenchEditorConfiguration } from 'vs/workbench/common/ import { IFileQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder'; import { getOutOfWorkspaceEditorResources } from 'vs/workbench/contrib/search/common/search'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService'; import { IFileQuery, IFileSearchStats, ISearchComplete, ISearchService } from 'vs/workbench/services/search/common/search'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; @@ -50,7 +50,7 @@ export class FileEntry extends EditorQuickOpenEntry { private resource: URI, private name: string, private description: string, - private icon: string, + private icon: string | undefined, @IEditorService editorService: IEditorService, @IModeService private readonly modeService: IModeService, @IModelService private readonly modelService: IModelService, @@ -78,7 +78,7 @@ export class FileEntry extends EditorQuickOpenEntry { return this.description; } - getIcon(): string { + getIcon(): string | undefined { return this.icon; } @@ -122,8 +122,10 @@ export class OpenFileHandler extends QuickOpenHandler { @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @ISearchService private readonly searchService: ISearchService, @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, @IFileService private readonly fileService: IFileService, - @ILabelService private readonly labelService: ILabelService + @ILabelService private readonly labelService: ILabelService, + @IRemotePathService private readonly remotePathService: IRemotePathService, ) { super(); @@ -186,15 +188,13 @@ export class OpenFileHandler extends QuickOpenHandler { private async getAbsolutePathResult(query: IPreparedQuery): Promise { const detildifiedQuery = untildify(query.original, this.environmentService.userHome); - if (isAbsolute(detildifiedQuery)) { - const workspaceFolders = this.contextService.getWorkspace().folders; - const resource = workspaceFolders[0] && workspaceFolders[0].uri.scheme !== Schemas.file ? - workspaceFolders[0].uri.with({ path: detildifiedQuery }) : - URI.file(detildifiedQuery); + if ((await this.remotePathService.path).isAbsolute(detildifiedQuery)) { + const resource = toLocalResource( + await this.remotePathService.fileURI(detildifiedQuery), + this.workbenchEnvironmentService.configuration.remoteAuthority); try { const stat = await this.fileService.resolve(resource); - return stat.isDirectory ? undefined : resource; } catch (error) { // ignore diff --git a/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts b/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts index c0bcedcb221..0f44a755c54 100644 --- a/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts @@ -14,7 +14,7 @@ import * as filters from 'vs/base/common/filters'; import * as strings from 'vs/base/common/strings'; import { Range } from 'vs/editor/common/core/range'; import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; -import { symbolKindToCssClass, SymbolTag } from 'vs/editor/common/modes'; +import { SymbolKinds, SymbolTag } from 'vs/editor/common/modes'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -47,7 +47,7 @@ class SymbolEntry extends EditorQuickOpenEntry { this.score = score; } - getHighlights(): [IHighlight[] /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] { + getHighlights(): [IHighlight[] | undefined /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] { return [this.isDeprecated() ? [] : filters.createMatches(this.score), undefined, undefined]; } @@ -73,7 +73,7 @@ class SymbolEntry extends EditorQuickOpenEntry { } getIcon(): string { - return symbolKindToCssClass(this.bearing.kind); + return SymbolKinds.toCssClassName(this.bearing.kind); } getLabelOptions(): IIconLabelValueOptions | undefined { @@ -104,7 +104,7 @@ class SymbolEntry extends EditorQuickOpenEntry { const scheme = this.bearing.location.uri ? this.bearing.location.uri.scheme : undefined; if (scheme === Schemas.http || scheme === Schemas.https) { if (mode === Mode.OPEN || mode === Mode.OPEN_IN_BACKGROUND) { - this.openerService.open(this.bearing.location.uri); // support http/https resources (https://github.com/Microsoft/vscode/issues/58924)) + this.openerService.open(this.bearing.location.uri, { fromUserGesture: true }); // support http/https resources (https://github.com/Microsoft/vscode/issues/58924)) } } else { super.run(mode, context); @@ -145,8 +145,8 @@ class SymbolEntry extends EditorQuickOpenEntry { if (res !== 0) { return res; } - let aKind = symbolKindToCssClass(a.bearing.kind); - let bKind = symbolKindToCssClass(b.bearing.kind); + let aKind = SymbolKinds.toCssClassName(a.bearing.kind); + let bKind = SymbolKinds.toCssClassName(b.bearing.kind); return aKind.localeCompare(bKind); } } diff --git a/src/vs/workbench/contrib/search/browser/replaceService.ts b/src/vs/workbench/contrib/search/browser/replaceService.ts index 502e32a326c..bc7e14ab2e2 100644 --- a/src/vs/workbench/contrib/search/browser/replaceService.ts +++ b/src/vs/workbench/contrib/search/browser/replaceService.ts @@ -130,7 +130,7 @@ export class ReplaceService implements IReplaceService { this.updateReplacePreview(fileMatch).then(() => { if (editor) { const editorControl = editor.getControl(); - if (element instanceof Match) { + if (element instanceof Match && editorControl) { editorControl.revealLineInCenter(element.range().startLineNumber, ScrollType.Immediate); } } diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 87140d0b464..697ceeb031a 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -11,7 +11,6 @@ import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { dirname } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import 'vs/css!./media/search.contribution'; import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { getSelectionSearchString } from 'vs/editor/contrib/find/findController'; @@ -50,7 +49,7 @@ import { registerContributions as searchWidgetContributions } from 'vs/workbench import * as Constants from 'vs/workbench/contrib/search/common/constants'; import { getWorkspaceSymbols } from 'vs/workbench/contrib/search/common/search'; import { ISearchHistoryService, SearchHistoryService } from 'vs/workbench/contrib/search/common/searchHistoryService'; -import { FileMatchOrMatch, ISearchWorkbenchService, RenderableMatch, SearchWorkbenchService, FileMatch } from 'vs/workbench/contrib/search/common/searchModel'; +import { FileMatchOrMatch, ISearchWorkbenchService, RenderableMatch, SearchWorkbenchService, FileMatch, Match, FolderMatch } from 'vs/workbench/contrib/search/common/searchModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ISearchConfiguration, ISearchConfigurationProperties, PANEL_ID, VIEWLET_ID, VIEW_CONTAINER, VIEW_ID } from 'vs/workbench/services/search/common/search'; @@ -134,7 +133,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService)); if (searchView) { const tree: WorkbenchObjectTree = searchView.getControl(); - accessor.get(IInstantiationService).createInstance(RemoveAction, tree, tree.getFocus()[0]).run(); + accessor.get(IInstantiationService).createInstance(RemoveAction, tree, tree.getFocus()[0]!).run(); } } }); @@ -148,7 +147,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService)); if (searchView) { const tree: WorkbenchObjectTree = searchView.getControl(); - accessor.get(IInstantiationService).createInstance(ReplaceAction, tree, tree.getFocus()[0], searchView).run(); + accessor.get(IInstantiationService).createInstance(ReplaceAction, tree, tree.getFocus()[0] as Match, searchView).run(); } } }); @@ -163,7 +162,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService)); if (searchView) { const tree: WorkbenchObjectTree = searchView.getControl(); - accessor.get(IInstantiationService).createInstance(ReplaceAllAction, searchView, tree.getFocus()[0]).run(); + accessor.get(IInstantiationService).createInstance(ReplaceAllAction, searchView, tree.getFocus()[0] as FileMatch).run(); } } }); @@ -178,7 +177,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService)); if (searchView) { const tree: WorkbenchObjectTree = searchView.getControl(); - accessor.get(IInstantiationService).createInstance(ReplaceAllInFolderAction, tree, tree.getFocus()[0]).run(); + accessor.get(IInstantiationService).createInstance(ReplaceAllInFolderAction, tree, tree.getFocus()[0] as FolderMatch).run(); } } }); @@ -507,7 +506,7 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie SearchViewlet, VIEWLET_ID, nls.localize('name', "Search"), - 'search', + 'codicon-search', 1 )); @@ -760,17 +759,6 @@ configurationRegistry.registerConfiguration({ default: false, description: nls.localize('search.showLineNumbers', "Controls whether to show line numbers for search results."), }, - 'searchRipgrep.enable': { - type: 'boolean', - default: false, - deprecationMessage: nls.localize('search.searchRipgrepEnableDeprecated', "Deprecated. Use \"search.runInExtensionHost\" instead"), - description: nls.localize('search.searchRipgrepEnable', "Whether to run search in the extension host") - }, - 'search.runInExtensionHost': { - type: 'boolean', - default: false, - description: nls.localize('search.runInExtensionHost', "Whether to run search in the extension host. Requires a restart to take effect.") - }, 'search.usePCRE2': { type: 'boolean', default: false, diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index 099312d3d98..c1dc5804ba3 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -494,7 +494,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action { export class RemoveAction extends AbstractSearchAndReplaceAction { - static LABEL = nls.localize('RemoveAction.label', "Dismiss"); + static readonly LABEL = nls.localize('RemoveAction.label', "Dismiss"); constructor( private viewer: WorkbenchObjectTree, diff --git a/src/vs/workbench/contrib/search/browser/searchPanel.ts b/src/vs/workbench/contrib/search/browser/searchPanel.ts index 55037157026..0c0def10162 100644 --- a/src/vs/workbench/contrib/search/browser/searchPanel.ts +++ b/src/vs/workbench/contrib/search/browser/searchPanel.ts @@ -67,4 +67,4 @@ export class SearchPanel extends Panel { getSearchView(): SearchView { return this.searchView; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index a35d362067d..0e0a0adb48c 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -245,7 +245,7 @@ export class SearchView extends ViewletPanel { if (this.searchWidget.isReplaceActive()) { this.searchWidget.focusReplaceAllAction(); } else { - this.searchWidget.focusRegexAction(); + this.searchWidget.isReplaceShown() ? this.searchWidget.replaceInput.focusOnPreserve() : this.searchWidget.focusRegexAction(); } dom.EventHelper.stop(e); } @@ -554,7 +554,7 @@ export class SearchView extends ViewletPanel { return nls.localize('replaceAll.occurrence.file.message', "Replaced {0} occurrence across {1} file with '{2}'.", occurrences, fileCount, replaceValue); } - return nls.localize('removeAll.occurrence.file.message', "Replaced {0} occurrence across {1} file'.", occurrences, fileCount); + return nls.localize('removeAll.occurrence.file.message', "Replaced {0} occurrence across {1} file.", occurrences, fileCount); } if (replaceValue) { @@ -569,7 +569,7 @@ export class SearchView extends ViewletPanel { return nls.localize('replaceAll.occurrences.file.message', "Replaced {0} occurrences across {1} file with '{2}'.", occurrences, fileCount, replaceValue); } - return nls.localize('removeAll.occurrences.file.message', "Replaced {0} occurrences across {1} file'.", occurrences, fileCount); + return nls.localize('removeAll.occurrences.file.message', "Replaced {0} occurrences across {1} file.", occurrences, fileCount); } if (replaceValue) { @@ -586,7 +586,7 @@ export class SearchView extends ViewletPanel { return nls.localize('removeAll.occurrence.file.confirmation.message', "Replace {0} occurrence across {1} file with '{2}'?", occurrences, fileCount, replaceValue); } - return nls.localize('replaceAll.occurrence.file.confirmation.message', "Replace {0} occurrence across {1} file'?", occurrences, fileCount); + return nls.localize('replaceAll.occurrence.file.confirmation.message', "Replace {0} occurrence across {1} file?", occurrences, fileCount); } if (replaceValue) { @@ -601,7 +601,7 @@ export class SearchView extends ViewletPanel { return nls.localize('removeAll.occurrences.file.confirmation.message', "Replace {0} occurrences across {1} file with '{2}'?", occurrences, fileCount, replaceValue); } - return nls.localize('replaceAll.occurrences.file.confirmation.message', "Replace {0} occurrences across {1} file'?", occurrences, fileCount); + return nls.localize('replaceAll.occurrences.file.confirmation.message', "Replace {0} occurrences across {1} file?", occurrences, fileCount); } if (replaceValue) { @@ -930,6 +930,8 @@ export class SearchView extends ViewletPanel { this.searchWidget.clear(); this.viewModel.cancelSearch(); this.updateActions(); + + aria.status(nls.localize('ariaSearchResultsClearStatus', "The search results have been cleared")); } cancelSearch(): boolean { @@ -1484,8 +1486,10 @@ export class SearchView extends ViewletPanel { this.messageDisposables.push(dom.addDisposableListener(openFolderLink, dom.EventType.CLICK, (e: MouseEvent) => { dom.EventHelper.stop(e, false); - const actionClass = env.isMacintosh ? OpenFileFolderAction : OpenFolderAction; - const action = this.instantiationService.createInstance(actionClass, actionClass.ID, actionClass.LABEL); + const action = env.isMacintosh ? + this.instantiationService.createInstance(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL) : + this.instantiationService.createInstance(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL); + this.actionRunner!.run(action).then(() => { action.dispose(); }, err => { diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 96631434ff1..263b79b88f7 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -389,6 +389,7 @@ export class SearchWidget extends Widget { this.replaceInputFocusTracker = this._register(dom.trackFocus(this.replaceInput.inputBox.inputElement)); this._register(this.replaceInputFocusTracker.onDidFocus(() => this.replaceInputBoxFocused.set(true))); this._register(this.replaceInputFocusTracker.onDidBlur(() => this.replaceInputBoxFocused.set(false))); + this._register(this.replaceInput.onPreserveCaseKeyDown((keyboardEvent: IKeyboardEvent) => this.onPreserveCaseKeyDown(keyboardEvent))); } triggerReplaceAll(): Promise { @@ -495,6 +496,15 @@ export class SearchWidget extends Widget { } private onRegexKeyDown(keyboardEvent: IKeyboardEvent) { + if (keyboardEvent.equals(KeyCode.Tab)) { + if (this.isReplaceShown()) { + this.replaceInput.focusOnPreserve(); + keyboardEvent.preventDefault(); + } + } + } + + private onPreserveCaseKeyDown(keyboardEvent: IKeyboardEvent) { if (keyboardEvent.equals(KeyCode.Tab)) { if (this.isReplaceActive()) { this.focusReplaceAllAction(); @@ -503,6 +513,10 @@ export class SearchWidget extends Widget { } keyboardEvent.preventDefault(); } + else if (KeyMod.Shift | KeyCode.Tab) { + this.focusRegexAction(); + keyboardEvent.preventDefault(); + } } private onReplaceInputKeyDown(keyboardEvent: IKeyboardEvent) { diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 6f0c6917460..e6c7b51588e 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -196,7 +196,7 @@ export class FileMatch extends Disposable implements IFileMatch { private _updateScheduler: RunOnceScheduler; private _modelDecorations: string[] = []; - constructor(private _query: IPatternInfo, private _previewOptions: ITextSearchPreviewOptions, private _maxResults: number, private _parent: FolderMatch, private rawMatch: IFileMatch, + constructor(private _query: IPatternInfo, private _previewOptions: ITextSearchPreviewOptions | undefined, private _maxResults: number | undefined, private _parent: FolderMatch, private rawMatch: IFileMatch, @IModelService private readonly modelService: IModelService, @IReplaceService private readonly replaceService: IReplaceService ) { super(); diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts index 75fd94e45a6..b1deb3354ba 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { parse as jsonParse } from 'vs/base/common/json'; +import { parse as jsonParse, getNodeType } from 'vs/base/common/json'; import { forEach } from 'vs/base/common/collections'; import { localize } from 'vs/nls'; import { extname, basename } from 'vs/base/common/path'; @@ -14,6 +14,7 @@ import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IdleValue } from 'vs/base/common/async'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; class SnippetBodyInsights { @@ -153,7 +154,8 @@ export class SnippetFile { readonly location: URI, public defaultScopes: string[] | undefined, private readonly _extension: IExtensionDescription | undefined, - private readonly _fileService: IFileService + private readonly _fileService: IFileService, + private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService ) { this.isGlobalSnippets = extname(location.path) === '.code-snippets'; this.isUserSnippets = !this._extension; @@ -199,11 +201,20 @@ export class SnippetFile { } } + private async _load(): Promise { + if (this._extension) { + return this._extensionResourceLoaderService.readExtensionResource(this.location); + } else { + const content = await this._fileService.readFile(this.location); + return content.value.toString(); + } + } + load(): Promise { if (!this._loadPromise) { - this._loadPromise = Promise.resolve(this._fileService.readFile(this.location)).then(content => { - const data = jsonParse(content.value.toString()); - if (typeof data === 'object') { + this._loadPromise = Promise.resolve(this._load()).then(content => { + const data = jsonParse(content); + if (getNodeType(data) === 'object') { forEach(data, entry => { const { key: name, value: scopeOrTemplate } = entry; if (isJsonSerializedSnippet(scopeOrTemplate)) { diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts index 241f485ed28..21a1107e650 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts @@ -25,6 +25,7 @@ import { Snippet, SnippetFile, SnippetSource } from 'vs/workbench/contrib/snippe import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService'; import { SnippetCompletionProvider } from './snippetCompletionProvider'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; namespace snippetExt { @@ -139,6 +140,7 @@ class SnippetsService implements ISnippetsService { @IModeService private readonly _modeService: IModeService, @ILogService private readonly _logService: ILogService, @IFileService private readonly _fileService: IFileService, + @IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService, @ILifecycleService lifecycleService: ILifecycleService, ) { this._pendingWork.push(Promise.resolve(lifecycleService.when(LifecyclePhase.Restored).then(() => { @@ -225,7 +227,7 @@ class SnippetsService implements ISnippetsService { file.defaultScopes = []; } } else { - const file = new SnippetFile(SnippetSource.Extension, validContribution.location, validContribution.language ? [validContribution.language] : undefined, extension.description, this._fileService); + const file = new SnippetFile(SnippetSource.Extension, validContribution.location, validContribution.language ? [validContribution.language] : undefined, extension.description, this._fileService, this._extensionResourceLoaderService); this._files.set(file.location.toString(), file); if (this._environmentService.isExtensionDevelopment) { @@ -318,9 +320,9 @@ class SnippetsService implements ISnippetsService { const key = uri.toString(); if (source === SnippetSource.User && ext === '.json') { const langName = resources.basename(uri).replace(/\.json/, ''); - this._files.set(key, new SnippetFile(source, uri, [langName], undefined, this._fileService)); + this._files.set(key, new SnippetFile(source, uri, [langName], undefined, this._fileService, this._extensionResourceLoaderService)); } else if (ext === '.code-snippets') { - this._files.set(key, new SnippetFile(source, uri, undefined, undefined, this._fileService)); + this._files.set(key, new SnippetFile(source, uri, undefined, undefined, this._fileService, this._extensionResourceLoaderService)); } return { dispose: () => this._files.delete(key) diff --git a/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts b/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts index 20f06e31a9e..4f54adf2301 100644 --- a/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts +++ b/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts @@ -23,8 +23,8 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions'; export class TabCompletionController implements editorCommon.IEditorContribution { - private static readonly ID = 'editor.tabCompletionController'; - static ContextKey = new RawContextKey('hasSnippetCompletions', undefined); + public static readonly ID = 'editor.tabCompletionController'; + static readonly ContextKey = new RawContextKey('hasSnippetCompletions', undefined); public static get(editor: ICodeEditor): TabCompletionController { return editor.getContribution(TabCompletionController.ID); @@ -50,10 +50,6 @@ export class TabCompletionController implements editorCommon.IEditorContribution this._update(); } - getId(): string { - return TabCompletionController.ID; - } - dispose(): void { dispose(this._configListener); dispose(this._selectionListener); @@ -143,7 +139,7 @@ export class TabCompletionController implements editorCommon.IEditorContribution } } -registerEditorContribution(TabCompletionController); +registerEditorContribution(TabCompletionController.ID, TabCompletionController); const TabCompletionCommand = EditorCommand.bindToContribution(TabCompletionController.get); diff --git a/src/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts index 83c1292c0a6..a804f261f37 100644 --- a/src/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts @@ -11,7 +11,7 @@ suite('Snippets', function () { class TestSnippetFile extends SnippetFile { constructor(filepath: URI, snippets: Snippet[]) { - super(SnippetSource.Extension, filepath, undefined, undefined, undefined!); + super(SnippetSource.Extension, filepath, undefined, undefined, undefined!, undefined!); this.data.push(...snippets); } } diff --git a/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts index 298f9a71b6c..f120a12e2d9 100644 --- a/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts @@ -84,7 +84,7 @@ suite('SnippetsService', function () { assert.equal(result.incomplete, undefined); assert.equal(result.suggestions.length, 1); assert.equal(result.suggestions[0].label, 'bar'); - assert.equal(result.suggestions[0].range.startColumn, 1); + assert.equal((result.suggestions[0].range as any).startColumn, 1); assert.equal(result.suggestions[0].insertText, 'barCodeSnippet'); }); }); @@ -117,10 +117,10 @@ suite('SnippetsService', function () { assert.equal(result.suggestions.length, 2); assert.equal(result.suggestions[0].label, 'bar'); assert.equal(result.suggestions[0].insertText, 's1'); - assert.equal(result.suggestions[0].range.startColumn, 1); + assert.equal((result.suggestions[0].range as any).startColumn, 1); assert.equal(result.suggestions[1].label, 'bar-bar'); assert.equal(result.suggestions[1].insertText, 's2'); - assert.equal(result.suggestions[1].range.startColumn, 1); + assert.equal((result.suggestions[1].range as any).startColumn, 1); }); await provider.provideCompletionItems(model, new Position(1, 5), context)!.then(result => { @@ -128,7 +128,7 @@ suite('SnippetsService', function () { assert.equal(result.suggestions.length, 1); assert.equal(result.suggestions[0].label, 'bar-bar'); assert.equal(result.suggestions[0].insertText, 's2'); - assert.equal(result.suggestions[0].range.startColumn, 1); + assert.equal((result.suggestions[0].range as any).startColumn, 1); }); await provider.provideCompletionItems(model, new Position(1, 6), context)!.then(result => { @@ -136,10 +136,10 @@ suite('SnippetsService', function () { assert.equal(result.suggestions.length, 2); assert.equal(result.suggestions[0].label, 'bar'); assert.equal(result.suggestions[0].insertText, 's1'); - assert.equal(result.suggestions[0].range.startColumn, 5); + assert.equal((result.suggestions[0].range as any).startColumn, 5); assert.equal(result.suggestions[1].label, 'bar-bar'); assert.equal(result.suggestions[1].insertText, 's2'); - assert.equal(result.suggestions[1].range.startColumn, 1); + assert.equal((result.suggestions[1].range as any).startColumn, 1); }); }); @@ -165,14 +165,14 @@ suite('SnippetsService', function () { return provider.provideCompletionItems(model, new Position(1, 4), context)!; }).then(result => { assert.equal(result.suggestions.length, 1); - assert.equal(result.suggestions[0].range.startColumn, 2); + assert.equal((result.suggestions[0].range as any).startColumn, 2); model.dispose(); model = TextModel.createFromString('a { assert.equal(result.suggestions.length, 1); - assert.equal(result.suggestions[0].range.startColumn, 2); + assert.equal((result.suggestions[0].range as any).startColumn, 2); model.dispose(); }); }); @@ -400,13 +400,13 @@ suite('SnippetsService', function () { assert.equal(result.suggestions.length, 1); let [first] = result.suggestions; - assert.equal(first.range.startColumn, 2); + assert.equal((first.range as any).startColumn, 2); model = TextModel.createFromString('1', undefined, modeService.getLanguageIdentifier('fooLang')); result = await provider.provideCompletionItems(model, new Position(1, 2), context)!; assert.equal(result.suggestions.length, 1); [first] = result.suggestions; - assert.equal(first.range.startColumn, 1); + assert.equal((first.range as any).startColumn, 1); }); }); diff --git a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts index 011b14816fb..7e511a8449d 100644 --- a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts @@ -18,13 +18,14 @@ import { DEFAULT_EDITOR_MIN_DIMENSIONS } from 'vs/workbench/browser/parts/editor import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import * as themes from 'vs/workbench/common/theme'; import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { URI } from 'vs/base/common/uri'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import * as perf from 'vs/base/common/performance'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; +import { assertIsDefined } from 'vs/base/common/types'; class PartsSplash { @@ -40,8 +41,8 @@ class PartsSplash { @IThemeService private readonly _themeService: IThemeService, @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, @ITextFileService private readonly _textFileService: ITextFileService, - @IEnvironmentService private readonly _envService: IEnvironmentService, - @IWindowService private readonly windowService: IWindowService, + @IWorkbenchEnvironmentService private readonly _envService: IWorkbenchEnvironmentService, + @IElectronEnvironmentService private readonly _electronEnvService: IElectronEnvironmentService, @ILifecycleService lifecycleService: ILifecycleService, @IEditorGroupsService editorGroupsService: IEditorGroupsService, @IConfigurationService configService: IConfigurationService, @@ -59,6 +60,8 @@ class PartsSplash { if (e.affectsConfiguration('window.titleBarStyle')) { this._didChangeTitleBarStyle = true; this._savePartsSplash(); + } else if (e.affectsConfiguration('workbench.colorTheme') || e.affectsConfiguration('workbench.colorCustomizations')) { + this._savePartsSplash(); } }, this, this._disposables); } @@ -77,14 +80,17 @@ class PartsSplash { sideBarBackground: this._getThemeColor(themes.SIDE_BAR_BACKGROUND), statusBarBackground: this._getThemeColor(themes.STATUS_BAR_BACKGROUND), statusBarNoFolderBackground: this._getThemeColor(themes.STATUS_BAR_NO_FOLDER_BACKGROUND), + windowBorder: this._getThemeColor(themes.WINDOW_ACTIVE_BORDER) ?? this._getThemeColor(themes.WINDOW_INACTIVE_BORDER) }; const layoutInfo = !this._shouldSaveLayoutInfo() ? undefined : { sideBarSide: this._layoutService.getSideBarPosition() === Position.RIGHT ? 'right' : 'left', editorPartMinWidth: DEFAULT_EDITOR_MIN_DIMENSIONS.width, - titleBarHeight: this._layoutService.isVisible(Parts.TITLEBAR_PART) ? getTotalHeight(this._layoutService.getContainer(Parts.TITLEBAR_PART)) : 0, - activityBarWidth: this._layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? getTotalWidth(this._layoutService.getContainer(Parts.ACTIVITYBAR_PART)) : 0, - sideBarWidth: this._layoutService.isVisible(Parts.SIDEBAR_PART) ? getTotalWidth(this._layoutService.getContainer(Parts.SIDEBAR_PART)) : 0, - statusBarHeight: this._layoutService.isVisible(Parts.STATUSBAR_PART) ? getTotalHeight(this._layoutService.getContainer(Parts.STATUSBAR_PART)) : 0, + titleBarHeight: this._layoutService.isVisible(Parts.TITLEBAR_PART) ? getTotalHeight(assertIsDefined(this._layoutService.getContainer(Parts.TITLEBAR_PART))) : 0, + activityBarWidth: this._layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? getTotalWidth(assertIsDefined(this._layoutService.getContainer(Parts.ACTIVITYBAR_PART))) : 0, + sideBarWidth: this._layoutService.isVisible(Parts.SIDEBAR_PART) ? getTotalWidth(assertIsDefined(this._layoutService.getContainer(Parts.SIDEBAR_PART))) : 0, + statusBarHeight: this._layoutService.isVisible(Parts.STATUSBAR_PART) ? getTotalHeight(assertIsDefined(this._layoutService.getContainer(Parts.STATUSBAR_PART))) : 0, + windowBorder: this._layoutService.hasWindowBorder(), + windowBorderRadius: this._layoutService.getWindowBorderRadius() }; this._textFileService.write( URI.file(join(this._envService.userDataPath, 'rapid_render.json')), @@ -105,7 +111,7 @@ class PartsSplash { // the color needs to be in hex const backgroundColor = this._themeService.getTheme().getColor(editorBackground) || themes.WORKBENCH_BACKGROUND(this._themeService.getTheme()); const payload = JSON.stringify({ baseTheme, background: Color.Format.CSS.formatHex(backgroundColor) }); - ipc.send('vscode:changeColorTheme', this.windowService.windowId, payload); + ipc.send('vscode:changeColorTheme', this._electronEnvService.windowId, payload); } } diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts index f4f8c3bc578..c72c8fb8b5f 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts @@ -16,6 +16,7 @@ import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedPr import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; import { IWorkspaceInformation } from 'vs/platform/diagnostics/common/diagnostics'; import { IRequestService } from 'vs/platform/request/common/request'; +import { isWindows } from 'vs/base/common/platform'; const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/; const SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/; @@ -152,7 +153,9 @@ export class WorkspaceStats implements IWorkbenchContribution { } } - private report(): void { + private async report(): Promise { + // Windows-only Edition Event + this.reportWindowsEdition(); // Workspace Stats this.workspaceStatsService.getTags() @@ -164,19 +167,41 @@ export class WorkspaceStats implements IWorkbenchContribution { this.reportProxyStats(); const diagnosticsChannel = this.sharedProcessService.getChannel('diagnostics'); - diagnosticsChannel.call('reportWorkspaceStats', this.getWorkspaceInformation()); + this.getWorkspaceInformation().then(stats => diagnosticsChannel.call('reportWorkspaceStats', stats)); } - private getWorkspaceInformation(): IWorkspaceInformation { + async reportWindowsEdition(): Promise { + if (!isWindows) { + return; + } + + const Registry = await import('vscode-windows-registry'); + + let value; + try { + value = Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion', 'EditionID'); + } catch { } + + if (value === undefined) { + value = 'Unknown'; + } + + this.telemetryService.publicLog2<{ edition: string }, { edition: { classification: 'SystemMetaData', purpose: 'BusinessInsight' } }>('windowsEdition', { edition: value }); + } + + private async getWorkspaceInformation(): Promise { const workspace = this.contextService.getWorkspace(); const state = this.contextService.getWorkbenchState(); - const id = this.workspaceStatsService.getTelemetryWorkspaceId(workspace, state); - return { - id: workspace.id, - telemetryId: id, - folders: workspace.folders, - configuration: workspace.configuration - }; + const telemetryId = this.workspaceStatsService.getTelemetryWorkspaceId(workspace, state); + return this.telemetryService.getTelemetryInfo().then(info => { + return { + id: workspace.id, + telemetryId, + rendererSessionId: info.sessionId, + folders: workspace.folders, + configuration: workspace.configuration + }; + }); } private reportWorkspaceTags(tags: Tags): void { diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts index a8e512b8508..f92507edb76 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts @@ -21,6 +21,7 @@ import { joinPath } from 'vs/base/common/resources'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; import { getHashedRemotesFromConfig } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats'; +import { IProductService } from 'vs/platform/product/common/productService'; const ModulesToLookFor = [ // Packages that suggest a node server @@ -98,6 +99,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { @IFileService private readonly fileService: IFileService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IProductService private readonly productService: IProductService, @IHostService private readonly hostService: IHostService, @INotificationService private readonly notificationService: INotificationService, @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -260,7 +262,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { tags['workspace.roots'] = isEmpty ? 0 : workspace.folders.length; tags['workspace.empty'] = isEmpty; - const folders = !isEmpty ? workspace.folders.map(folder => folder.uri) : this.environmentService.appQuality !== 'stable' && this.findFolders(configuration); + const folders = !isEmpty ? workspace.folders.map(folder => folder.uri) : this.productService.quality !== 'stable' && this.findFolders(configuration); if (!folders || !folders.length || !this.fileService) { return Promise.resolve(tags); } @@ -454,7 +456,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { this.notificationService.prompt(Severity.Info, localize('workspaceFound', "This folder contains a workspace file '{0}'. Do you want to open it? [Learn more]({1}) about workspace files.", workspaceFile, 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{ label: localize('openWorkspace', "Open Workspace"), - run: () => this.hostService.openInWindow([{ workspaceUri: joinPath(folder, workspaceFile) }]) + run: () => this.hostService.openWindow([{ workspaceUri: joinPath(folder, workspaceFile) }]) }], { neverShowAgain }); } @@ -467,7 +469,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { workspaces.map(workspace => ({ label: workspace } as IQuickPickItem)), { placeHolder: localize('selectToOpen', "Select a workspace to open") }).then(pick => { if (pick) { - this.hostService.openInWindow([{ workspaceUri: joinPath(folder, pick.label) }]); + this.hostService.openWindow([{ workspaceUri: joinPath(folder, pick.label) }]); } }); } diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 294c1b216a9..92628430560 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -6,19 +6,19 @@ import * as nls from 'vs/nls'; import Severity from 'vs/base/common/severity'; import * as Objects from 'vs/base/common/objects'; +import * as resources from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { IStringDictionary } from 'vs/base/common/collections'; import { Action } from 'vs/base/common/actions'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as Types from 'vs/base/common/types'; -import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { TerminateResponseCode } from 'vs/base/common/processes'; import * as strings from 'vs/base/common/strings'; import { ValidationStatus, ValidationState } from 'vs/base/common/parsers'; import * as UUID from 'vs/base/common/uuid'; import * as Platform from 'vs/base/common/platform'; -import { LinkedMap, Touch } from 'vs/base/common/map'; +import { LRUCache } from 'vs/base/common/map'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IMarkerService } from 'vs/platform/markers/common/markers'; @@ -27,14 +27,13 @@ import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configur import { IFileService, IFileStat } from 'vs/platform/files/common/files'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ProblemMatcherRegistry, NamedProblemMatcher } from 'vs/workbench/contrib/tasks/common/problemMatcher'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IProgressService, IProgressOptions, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification'; import { IDialogService, IConfirmationResult } from 'vs/platform/dialogs/common/dialogs'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -44,7 +43,7 @@ import Constants from 'vs/workbench/contrib/markers/browser/constants'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IOutputService, IOutputChannel } from 'vs/workbench/contrib/output/common/output'; @@ -77,12 +76,22 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { ITextEditor } from 'vs/workbench/common/editor'; import { ITextEditorSelection } from 'vs/platform/editor/common/editor'; +import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; +import { find } from 'vs/base/common/arrays'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; + +const QUICKOPEN_HISTORY_LIMIT_CONFIG = 'task.quickOpen.history'; +const QUICKOPEN_DETAIL_CONFIG = 'task.quickOpen.detail'; +const PROBLEM_MATCHER_NEVER_CONFIG = 'task.problemMatchers.neverPrompt'; +const QUICKOPEN_SKIP_CONFIG = 'task.quickOpen.skip'; export namespace ConfigureTaskAction { export const ID = 'workbench.action.tasks.configureTaskRunner'; export const TEXT = nls.localize('ConfigureTaskRunnerAction.label', "Configure Task"); } +type TaskQuickPickEntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; }); + class ProblemReporter implements TaskConfig.IProblemReporter { private _validationStatus: ValidationStatus; @@ -126,6 +135,10 @@ interface TaskCustomizationTelemetryEvent { properties: string[]; } +function isWorkspaceFolder(folder: IWorkspace | IWorkspaceFolder): folder is IWorkspaceFolder { + return 'uri' in folder; +} + class TaskMap { private _store: Map = new Map(); @@ -133,20 +146,33 @@ class TaskMap { this._store.forEach(callback); } - public get(workspaceFolder: IWorkspaceFolder | string): Task[] { - let result: Task[] | undefined = Types.isString(workspaceFolder) ? this._store.get(workspaceFolder) : this._store.get(workspaceFolder.uri.toString()); + private getKey(workspaceFolder: IWorkspace | IWorkspaceFolder | string): string { + let key: string | undefined; + if (Types.isString(workspaceFolder)) { + key = workspaceFolder; + } else { + const uri: URI | null | undefined = isWorkspaceFolder(workspaceFolder) ? workspaceFolder.uri : workspaceFolder.configuration; + key = uri ? uri.toString() : ''; + } + return key; + } + + public get(workspaceFolder: IWorkspace | IWorkspaceFolder | string): Task[] { + const key = this.getKey(workspaceFolder); + let result: Task[] | undefined = this._store.get(key); if (!result) { result = []; - Types.isString(workspaceFolder) ? this._store.set(workspaceFolder, result) : this._store.set(workspaceFolder.uri.toString(), result); + this._store.set(key, result); } return result; } - public add(workspaceFolder: IWorkspaceFolder | string, ...task: Task[]): void { - let values = Types.isString(workspaceFolder) ? this._store.get(workspaceFolder) : this._store.get(workspaceFolder.uri.toString()); + public add(workspaceFolder: IWorkspace | IWorkspaceFolder | string, ...task: Task[]): void { + const key = this.getKey(workspaceFolder); + let values = this._store.get(key); if (!values) { values = []; - Types.isString(workspaceFolder) ? this._store.set(workspaceFolder, values) : this._store.set(workspaceFolder.uri.toString(), values); + this._store.set(key, values); } values.push(...task); } @@ -162,6 +188,13 @@ interface TaskQuickPickEntry extends IQuickPickItem { task: Task | undefined | null; } +interface ProblemMatcherDisableMetrics { + type: string; +} +type ProblemMatcherDisableMetricsClassification = { + type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; +}; + export abstract class AbstractTaskService extends Disposable implements ITaskService { // private static autoDetectTelemetryName: string = 'taskServer.autoDetect'; @@ -178,6 +211,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private _schemaVersion: JsonSchemaVersion | undefined; private _executionEngine: ExecutionEngine | undefined; private _workspaceFolders: IWorkspaceFolder[] | undefined; + private _workspace: IWorkspace | undefined; private _ignoredWorkspaceFolders: IWorkspaceFolder[] | undefined; private _showIgnoreMessage?: boolean; private _providers: Map; @@ -189,7 +223,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer protected _taskSystem?: ITaskSystem; protected _taskSystemListener?: IDisposable; - private _recentlyUsedTasks: LinkedMap | undefined; + private _recentlyUsedTasks: LRUCache | undefined; protected _taskRunningState: IContextKey; @@ -223,7 +257,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @ITerminalInstanceService private readonly terminalInstanceService: ITerminalInstanceService, @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService, - @ITextModelService private readonly textModelResolverService: ITextModelService + @ITextModelService private readonly textModelResolverService: ITextModelService, + @IPreferencesService private readonly preferencesService: IPreferencesService ) { super(); @@ -269,6 +304,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (!this._taskSystem || this._taskSystem instanceof TerminalTaskSystem) { this._outputChannel.clear(); } + + this.setTaskLRUCacheLimit(); this.updateWorkspaceTasks(TaskRunSource.ConfigurationChange); })); this._taskRunningState = TASK_RUNNING_STATE.bindTo(contextKeyService); @@ -288,7 +325,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer let entry: TaskQuickPickEntry | null | undefined; if (tasks && tasks.length > 0) { - entry = await this.showQuickPick(tasks, nls.localize('TaskService.pickBuildTaskForLabel', 'Select the build task')); + entry = await this.showQuickPick(tasks, nls.localize('TaskService.pickBuildTaskForLabel', 'Select the build task (there is no default build task defined)')); } let task: Task | undefined | null = entry ? entry.task : undefined; @@ -350,13 +387,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this.runBuildCommand(); }); - KeybindingsRegistry.registerKeybindingRule({ - id: 'workbench.action.tasks.build', - weight: KeybindingWeight.WorkbenchContrib, - when: undefined, - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_B - }); - CommandsRegistry.registerCommand('workbench.action.tasks.test', () => { if (!this.canRunCommand()) { return; @@ -376,8 +406,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this.runConfigureDefaultTestTask(); }); - CommandsRegistry.registerCommand('workbench.action.tasks.showTasks', () => { - this.runShowTasks(); + CommandsRegistry.registerCommand('workbench.action.tasks.showTasks', async () => { + return this.runShowTasks(); }); CommandsRegistry.registerCommand('workbench.action.tasks.toggleProblems', () => { @@ -388,6 +418,13 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this.panelService.openPanel(Constants.MARKERS_PANEL_ID, true); } }); + + CommandsRegistry.registerCommand('workbench.action.tasks.configureUserTask', async () => { + const resource = this.getResourceForKind(TaskSourceKind.User); + if (resource) { + this.openTaskFile(resource); + } + }); } private get workspaceFolders(): IWorkspaceFolder[] { @@ -425,7 +462,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return this._showIgnoreMessage; } - private updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion]): void { + private updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined]): void { if (!setup) { setup = this.computeWorkspaceFolderSetup(); } @@ -447,6 +484,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._ignoredWorkspaceFolders = setup[1]; this._executionEngine = setup[2]; this._schemaVersion = setup[3]; + this._workspace = setup[4]; } protected showOutput(runSource: TaskRunSource = TaskRunSource.User): void { @@ -495,8 +533,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return this._taskSystem.customExecutionComplete(task, result); } - public getTask(folder: IWorkspaceFolder | string, identifier: string | TaskIdentifier, compareId: boolean = false): Promise { - const name = Types.isString(folder) ? folder : folder.name; + public getTask(folder: IWorkspace | IWorkspaceFolder | string, identifier: string | TaskIdentifier, compareId: boolean = false): Promise { + const name = Types.isString(folder) ? folder : isWorkspaceFolder(folder) ? folder.name : folder.configuration ? resources.basename(folder.configuration) : undefined; if (this.ignoredWorkspaceFolders.some(ignored => ignored.name === name)) { return Promise.reject(new Error(nls.localize('TaskServer.folderIgnored', 'The folder {0} is ignored since it uses task version 0.1.0', name))); } @@ -512,12 +550,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (!values) { return undefined; } - for (const task of values) { - if (task.matches(key, compareId)) { - return task; - } - } - return undefined; + return find(values, task => task.matches(key, compareId)); }); } @@ -570,11 +603,20 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return Promise.resolve(this._taskSystem.getActiveTasks()); } - public getRecentlyUsedTasks(): LinkedMap { + public getBusyTasks(): Promise { + if (!this._taskSystem) { + return Promise.resolve([]); + } + return Promise.resolve(this._taskSystem.getBusyTasks()); + } + + public getRecentlyUsedTasks(): LRUCache { if (this._recentlyUsedTasks) { return this._recentlyUsedTasks; } - this._recentlyUsedTasks = new LinkedMap(); + const quickOpenHistoryLimit = this.configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); + this._recentlyUsedTasks = new LRUCache(quickOpenHistoryLimit); + let storageValue = this.storageService.get(AbstractTaskService.RecentlyUsedTasks_Key, StorageScope.WORKSPACE); if (storageValue) { try { @@ -591,8 +633,15 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return this._recentlyUsedTasks; } + private setTaskLRUCacheLimit() { + const quickOpenHistoryLimit = this.configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); + if (this._recentlyUsedTasks) { + this._recentlyUsedTasks.limit = quickOpenHistoryLimit; + } + } + private setRecentlyUsedTask(key: string): void { - this.getRecentlyUsedTasks().set(key, key, Touch.AsOld); + this.getRecentlyUsedTasks().set(key, key); this.saveRecentlyUsedTasks(); } @@ -600,9 +649,14 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (!this._taskSystem || !this._recentlyUsedTasks) { return; } + const quickOpenHistoryLimit = this.configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); + // setting history limit to 0 means no LRU sorting + if (quickOpenHistoryLimit === 0) { + return; + } let values = this._recentlyUsedTasks.values(); - if (values.length > 30) { - values = values.slice(0, 30); + if (values.length > quickOpenHistoryLimit) { + values = values.slice(0, quickOpenHistoryLimit); } this.storageService.store(AbstractTaskService.RecentlyUsedTasks_Key, JSON.stringify(values), StorageScope.WORKSPACE); } @@ -674,7 +728,39 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } + private isProvideTasksEnabled(): boolean { + const settingValue = this.configurationService.getValue('task.autoDetect'); + return settingValue === 'on'; + } + + private isProblemMatcherPromptEnabled(type?: string): boolean { + const settingValue = this.configurationService.getValue(PROBLEM_MATCHER_NEVER_CONFIG); + if (Types.isBoolean(settingValue)) { + return !settingValue; + } + if (type === undefined) { + return true; + } + const settingValueMap: IStringDictionary = settingValue; + return !settingValueMap[type]; + } + + private getTypeForTask(task: Task): string { + let type: string; + if (CustomTask.is(task)) { + let configProperties: TaskConfig.ConfigurationProperties = task._source.config.element; + type = (configProperties).type; + } else { + type = task.getDefinition()!.type; + } + return type; + } + private shouldAttachProblemMatcher(task: Task): boolean { + const enabled = this.isProblemMatcherPromptEnabled(this.getTypeForTask(task)); + if (enabled === false) { + return false; + } if (!this.canCustomize(task)) { return false; } @@ -694,11 +780,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return false; } + private async updateNeverProblemMatcherSetting(type: string): Promise { + this.telemetryService.publicLog2('problemMatcherDisabled', { type }); + const current = this.configurationService.getValue(PROBLEM_MATCHER_NEVER_CONFIG); + if (current === true) { + return; + } + let newValue: IStringDictionary; + if (current !== false) { + newValue = current; + } else { + newValue = Object.create(null); + } + newValue[type] = true; + return this.configurationService.updateValue(PROBLEM_MATCHER_NEVER_CONFIG, newValue, ConfigurationTarget.USER); + } + private attachProblemMatcher(task: ContributedTask | CustomTask): Promise { interface ProblemMatcherPickEntry extends IQuickPickItem { matcher: NamedProblemMatcher | undefined; never?: boolean; learnMore?: boolean; + setting?: string; } let entries: QuickPickInput[] = []; for (let key of ProblemMatcherRegistry.keys()) { @@ -725,14 +828,22 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } }); entries.unshift({ type: 'separator', label: nls.localize('TaskService.associate', 'associate') }); + let taskType: string; + if (CustomTask.is(task)) { + let configProperties: TaskConfig.ConfigurationProperties = task._source.config.element; + taskType = (configProperties).type; + } else { + taskType = task.getDefinition().type; + } entries.unshift( { label: nls.localize('TaskService.attachProblemMatcher.continueWithout', 'Continue without scanning the task output'), matcher: undefined }, - { label: nls.localize('TaskService.attachProblemMatcher.never', 'Never scan the task output'), matcher: undefined, never: true }, + { label: nls.localize('TaskService.attachProblemMatcher.never', 'Never scan the task output for this task'), matcher: undefined, never: true }, + { label: nls.localize('TaskService.attachProblemMatcher.neverType', 'Never scan the task output for {0} tasks', taskType), matcher: undefined, setting: taskType }, { label: nls.localize('TaskService.attachProblemMatcher.learnMoreAbout', 'Learn more about scanning the task output'), matcher: undefined, learnMore: true } ); return this.quickInputService.pick(entries, { placeHolder: nls.localize('selectProblemMatcher', 'Select for which kind of errors and warnings to scan the task output'), - }).then((selected) => { + }).then(async (selected) => { if (selected) { if (selected.learnMore) { this.openDocumentation(); @@ -752,6 +863,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } this.customize(task, properties, true); return newTask; + } else if (selected.setting) { + await this.updateNeverProblemMatcherSetting(selected.setting); + return task; } else { return task; } @@ -961,10 +1075,39 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } + private getResourceForKind(kind: string): URI | undefined { + switch (kind) { + case TaskSourceKind.User: { + return resources.joinPath(resources.dirname(this.preferencesService.userSettingsResource), 'tasks.json'); + } + case TaskSourceKind.WorkspaceFile: { + if (this._workspace && this._workspace.configuration) { + return this._workspace.configuration; + } + } + default: { + return undefined; + } + } + } + + private getResourceForTask(task: CustomTask): URI { + let uri = this.getResourceForKind(task._source.kind); + if (!uri) { + const taskFolder = task.getWorkspaceFolder(); + if (taskFolder) { + uri = taskFolder.toResource(task._source.config.file); + } else { + uri = this.workspaceFolders[0].uri; + } + } + return uri; + } + public openConfig(task: CustomTask | undefined): Promise { let resource: URI | undefined; if (task) { - resource = task.getWorkspaceFolder().toResource(task._source.config.file); + resource = this.getResourceForTask(task); } else { resource = (this._workspaceFolders && (this._workspaceFolders.length > 0)) ? this._workspaceFolders[0].toResource('.vscode/tasks.json') : undefined; } @@ -1007,8 +1150,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } }); let resolver: ITaskResolver = { - resolve: (workspaceFolder: IWorkspaceFolder, alias: string) => { - let data = resolverData.get(workspaceFolder.uri.toString()); + resolve: (uri: URI, alias: string) => { + let data = resolverData.get(uri.toString()); if (!data) { return undefined; } @@ -1039,7 +1182,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer { reevaluateOnRerun: true }, { identifier: id, - dependsOn: extensionTasks.map((extensionTask) => { return { workspaceFolder: extensionTask.getWorkspaceFolder()!, task: extensionTask._id }; }), + dependsOn: extensionTasks.map((extensionTask) => { return { uri: extensionTask.getWorkspaceFolder()!.uri, task: extensionTask._id }; }), name: id, } ); @@ -1072,9 +1215,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } }); + return { - resolve: (workspaceFolder: IWorkspaceFolder, identifier: string | TaskIdentifier | undefined) => { - let data = resolverData.get(workspaceFolder.uri.toString()); + resolve: (uri: URI, identifier: string | TaskIdentifier | undefined) => { + let data = uri ? resolverData.get(uri.toString()) : undefined; if (!data || !identifier) { return undefined; } @@ -1184,6 +1328,39 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer protected abstract getTaskSystem(): ITaskSystem; + private async provideTasksWithWarning(provider: ITaskProvider, type: string, validTypes: IStringDictionary): Promise { + return new Promise(async (resolve, reject) => { + let isDone = false; + provider.provideTasks(validTypes).then((value) => { + isDone = true; + resolve(value); + }, (e) => { + isDone = true; + reject(e); + }); + let settingValue: boolean | string[] = this.configurationService.getValue('task.slowProviderWarning'); + if ((settingValue === true) || (Types.isStringArray(settingValue) && (settingValue.indexOf(type) < 0))) { + setTimeout(() => { + if (!isDone) { + const settings: IPromptChoice = { label: nls.localize('TaskSystem.slowProvider.settings', "Settings"), run: () => this.preferencesService.openSettings(false, undefined) }; + const disableAll: IPromptChoice = { label: nls.localize('TaskSystem.slowProvider.disableAll', "Disable All"), run: () => this.configurationService.updateValue('task.autoDetect', 'off') }; + const dontShow: IPromptChoice = { + label: nls.localize('TaskSystem.slowProvider.dontShow', "Don't warn again for {0} tasks", type), run: () => { + if (!Types.isStringArray(settingValue)) { + settingValue = []; + } + settingValue.push(type); + return this.configurationService.updateValue('task.slowProviderWarning', settingValue); + } + }; + this.notificationService.prompt(Severity.Warning, nls.localize('TaskSystem.slowProvider', "The {0} task provider is slow. The extension that provides {0} tasks may provide a setting to disable it, or you can disable all tasks providers", type), + [settings, disableAll, dontShow]); + } + }, 4000); + } + }); + } + private getGroupedTasks(type?: string): Promise { return Promise.all([this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask'), TaskDefinitionRegistry.onReady()]).then(() => { let validTypes: IStringDictionary = Object.create(null); @@ -1218,11 +1395,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } }; - if (this.schemaVersion === JsonSchemaVersion.V2_0_0 && this._providers.size > 0) { + if (this.isProvideTasksEnabled() && (this.schemaVersion === JsonSchemaVersion.V2_0_0) && (this._providers.size > 0)) { for (const [handle, provider] of this._providers) { if ((type === undefined) || (type === this._providerTypes.get(handle))) { counter++; - provider.provideTasks(validTypes).then(done, error); + this.provideTasksWithWarning(provider, this._providerTypes.get(handle)!, validTypes).then(done, error); } } } else { @@ -1402,13 +1579,21 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer for (let folder of this.workspaceFolders) { promises.push(this.computeWorkspaceFolderTasks(folder, runSource).then((value) => value, () => undefined)); } - return Promise.all(promises).then((values) => { + return Promise.all(promises).then(async (values) => { let result = new Map(); for (let value of values) { if (value) { result.set(value.workspaceFolder.uri.toString(), value); } } + const userTasks = await this.computeUserTasks(this.workspaceFolders[0], runSource).then((value) => value, () => undefined); + if (userTasks) { + result.set('settings', userTasks); + } + const workspaceFileTasks = await this.computeWorkspaceFileTasks(this.workspaceFolders[0], runSource).then((value) => value, () => undefined); + if (workspaceFileTasks && this._workspace && this._workspace.configuration) { + result.set(this._workspace.configuration.toString(), workspaceFileTasks); + } return result; }); } @@ -1429,7 +1614,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return ProblemMatcherRegistry.onReady().then(async (): Promise => { let taskSystemInfo: TaskSystemInfo | undefined = this._taskSystemInfos.get(workspaceFolder.uri.scheme); let problemReporter = new ProblemReporter(this._outputChannel); - let parseResult = TaskConfig.parse(workspaceFolder, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, workspaceFolderConfiguration.config!, problemReporter); + let parseResult = TaskConfig.parse(workspaceFolder, undefined, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, workspaceFolderConfiguration.config!, problemReporter, TaskConfig.TaskConfigSource.TasksJson); let hasErrors = false; if (!parseResult.validationStatus.isOK()) { hasErrors = true; @@ -1456,6 +1641,101 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } + private testParseExternalConfig(config: TaskConfig.ExternalTaskRunnerConfiguration | undefined, location: string): { config: TaskConfig.ExternalTaskRunnerConfiguration | undefined, hasParseErrors: boolean } { + if (!config) { + return { config: undefined, hasParseErrors: false }; + } + let parseErrors: string[] = (config as any).$parseErrors; + if (parseErrors) { + let isAffected = false; + for (const parseError of parseErrors) { + if (/tasks\.json$/.test(parseError)) { + isAffected = true; + break; + } + } + if (isAffected) { + this._outputChannel.append(nls.localize('TaskSystem.invalidTaskJsonOther', 'Error: The content of the tasks json in {0} has syntax errors. Please correct them before executing a task.\n', location)); + this.showOutput(); + return { config, hasParseErrors: true }; + } + } + return { config, hasParseErrors: false }; + } + + private async computeWorkspaceFileTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise { + if (this.executionEngine === ExecutionEngine.Process) { + return this.emptyWorkspaceTaskResults(workspaceFolder); + } + const configuration = this.testParseExternalConfig(this.configurationService.inspect('tasks').workspace, nls.localize('TasksSystem.locationWorkspaceConfig', 'workspace file')); + let customizedTasks: { byIdentifier: IStringDictionary; } = { + byIdentifier: Object.create(null) + }; + + const custom: CustomTask[] = []; + await this.computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.WorkspaceFile); + const engine = configuration.config ? TaskConfig.ExecutionEngine.from(configuration.config) : ExecutionEngine.Terminal; + if (engine === ExecutionEngine.Process) { + this.notificationService.warn(nls.localize('TaskSystem.versionWorkspaceFile', 'Only tasks version 2.0.0 permitted in .codeworkspace.')); + return this.emptyWorkspaceTaskResults(workspaceFolder); + } + return { workspaceFolder, set: { tasks: custom }, configurations: customizedTasks, hasErrors: configuration.hasParseErrors }; + } + + private async computeUserTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise { + if (this.executionEngine === ExecutionEngine.Process) { + return this.emptyWorkspaceTaskResults(workspaceFolder); + } + const configuration = this.testParseExternalConfig(this.configurationService.inspect('tasks').user, nls.localize('TasksSystem.locationUserConfig', 'user settings')); + let customizedTasks: { byIdentifier: IStringDictionary; } = { + byIdentifier: Object.create(null) + }; + + const custom: CustomTask[] = []; + await this.computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.User); + const engine = configuration.config ? TaskConfig.ExecutionEngine.from(configuration.config) : ExecutionEngine.Terminal; + if (engine === ExecutionEngine.Process) { + this.notificationService.warn(nls.localize('TaskSystem.versionSettings', 'Only tasks version 2.0.0 permitted in user settings.')); + return this.emptyWorkspaceTaskResults(workspaceFolder); + } + return { workspaceFolder, set: { tasks: custom }, configurations: customizedTasks, hasErrors: configuration.hasParseErrors }; + } + + private emptyWorkspaceTaskResults(workspaceFolder: IWorkspaceFolder): WorkspaceFolderTaskResult { + return { workspaceFolder, set: undefined, configurations: undefined, hasErrors: false }; + } + + private async computeTasksForSingleConfig(workspaceFolder: IWorkspaceFolder, config: TaskConfig.ExternalTaskRunnerConfiguration | undefined, runSource: TaskRunSource, custom: CustomTask[], customized: IStringDictionary, source: TaskConfig.TaskConfigSource): Promise { + if (!config) { + return false; + } + let taskSystemInfo: TaskSystemInfo | undefined = workspaceFolder ? this._taskSystemInfos.get(workspaceFolder.uri.scheme) : undefined; + let problemReporter = new ProblemReporter(this._outputChannel); + let parseResult = TaskConfig.parse(workspaceFolder, this._workspace, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, config, problemReporter, source); + let hasErrors = false; + if (!parseResult.validationStatus.isOK()) { + this.showOutput(runSource); + hasErrors = true; + } + if (problemReporter.status.isFatal()) { + problemReporter.fatal(nls.localize('TaskSystem.configurationErrors', 'Error: the provided task configuration has validation errors and can\'t not be used. Please correct the errors first.')); + return hasErrors; + } + if (parseResult.configured && parseResult.configured.length > 0) { + for (let task of parseResult.configured) { + customized[task.configures._key] = task; + } + } + if (!(await this._areJsonTasksSupportedPromise) && (parseResult.custom.length > 0)) { + console.warn('Custom workspace tasks are not supported.'); + } else { + for (let task of parseResult.custom) { + custom.push(task); + } + } + return hasErrors; + } + private computeConfiguration(workspaceFolder: IWorkspaceFolder): Promise { let { config, hasParseErrors } = this.getConfiguration(workspaceFolder); return Promise.resolve({ workspaceFolder, config, hasErrors: hasParseErrors }); @@ -1463,18 +1743,19 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer protected abstract computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): Promise; - private computeWorkspaceFolderSetup(): [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion] { + private computeWorkspaceFolderSetup(): [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined] { let workspaceFolders: IWorkspaceFolder[] = []; let ignoredWorkspaceFolders: IWorkspaceFolder[] = []; let executionEngine = ExecutionEngine.Terminal; let schemaVersion = JsonSchemaVersion.V2_0_0; - + let workspace: IWorkspace | undefined; if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { let workspaceFolder: IWorkspaceFolder = this.contextService.getWorkspace().folders[0]; workspaceFolders.push(workspaceFolder); executionEngine = this.computeExecutionEngine(workspaceFolder); schemaVersion = this.computeJsonSchemaVersion(workspaceFolder); } else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + workspace = this.contextService.getWorkspace(); for (let workspaceFolder of this.contextService.getWorkspace().folders) { if (schemaVersion === this.computeJsonSchemaVersion(workspaceFolder)) { workspaceFolders.push(workspaceFolder); @@ -1487,7 +1768,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } } - return [workspaceFolders, ignoredWorkspaceFolders, executionEngine, schemaVersion]; + return [workspaceFolders, ignoredWorkspaceFolders, executionEngine, schemaVersion, workspace]; } private computeExecutionEngine(workspaceFolder: IWorkspaceFolder): ExecutionEngine { @@ -1508,7 +1789,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer protected getConfiguration(workspaceFolder: IWorkspaceFolder): { config: TaskConfig.ExternalTaskRunnerConfiguration | undefined; hasParseErrors: boolean } { let result = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY - ? Objects.deepClone(this.configurationService.getValue('tasks', { resource: workspaceFolder.uri })) + ? Objects.deepClone(this.configurationService.inspect('tasks', { resource: workspaceFolder.uri }).workspaceFolder) : undefined; if (!result) { return { config: undefined, hasParseErrors: false }; @@ -1654,19 +1935,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return true; } + private showDetail(): boolean { + return this.configurationService.getValue(QUICKOPEN_DETAIL_CONFIG); + } + private createTaskQuickPickEntries(tasks: Task[], group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry): TaskQuickPickEntry[] { if (tasks === undefined || tasks === null || tasks.length === 0) { return []; } const TaskQuickPickEntry = (task: Task): TaskQuickPickEntry => { let description: string | undefined; - if (this.needsFolderQualification()) { + if (task._source.kind === TaskSourceKind.User) { + description = nls.localize('taskQuickPick.userSettings', 'User Settings'); + } else if (task._source.kind === TaskSourceKind.WorkspaceFile) { + description = task.getWorkspaceFileName(); + } else if (this.needsFolderQualification()) { let workspaceFolder = task.getWorkspaceFolder(); if (workspaceFolder) { description = workspaceFolder.name; } } - return { label: task._label, description, task }; + + return { label: task._label, description, task, detail: this.showDetail() ? task.configurationProperties.detail : undefined }; }; function fillEntries(entries: QuickPickInput[], tasks: Task[], groupLabel: string): void { if (tasks.length) { @@ -1674,7 +1964,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } for (let task of tasks) { let entry: TaskQuickPickEntry = TaskQuickPickEntry(task); - entry.buttons = [{ iconClass: 'quick-open-task-configure', tooltip: nls.localize('configureTask', "Configure Task") }]; + entry.buttons = [{ iconClass: 'codicon-gear', tooltip: nls.localize('configureTask', "Configure Task") }]; if (selectedEntry && (task === selectedEntry.task)) { entries.unshift(selectedEntry); } else { @@ -1699,7 +1989,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer taskMap[key] = task; } }); - recentlyUsedTasks.keys().forEach(key => { + recentlyUsedTasks.keys().reverse().forEach(key => { let task = taskMap[key]; if (task) { recent.push(task); @@ -1708,7 +1998,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer for (let task of tasks) { let key = task.getRecentlyUsedKey(); if (!key || !recentlyUsedTasks.has(key)) { - if (task._source.kind === TaskSourceKind.Workspace) { + if ((task._source.kind === TaskSourceKind.Workspace) || (task._source.kind === TaskSourceKind.User)) { configured.push(task); } else { detected.push(task); @@ -1732,23 +2022,43 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return entries; } - private showQuickPick(tasks: Promise | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise { - let _createEntries = (): Promise[]> => { + private async showQuickPick(tasks: Promise | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise { + const tokenSource = new CancellationTokenSource(); + const cancellationToken: CancellationToken = tokenSource.token; + let _createEntries = new Promise[]>((resolve) => { if (Array.isArray(tasks)) { - return Promise.resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry)); + resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry)); } else { - return tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry)); + resolve(tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry))); } - }; - return this.quickInputService.pick(_createEntries().then((entries) => { - if ((entries.length === 0) && defaultEntry) { + }); + + const timeout: boolean = await Promise.race([new Promise(async (resolve) => { + await _createEntries; + resolve(false); + }), new Promise((resolve) => { + const timer = setTimeout(() => { + clearTimeout(timer); + resolve(true); + }, 200); + })]); + + if (!timeout && ((await _createEntries).length === 1) && this.configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { + return ((await _createEntries)[0]); + } + + const pickEntries = _createEntries.then((entries) => { + if ((entries.length === 1) && this.configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { + tokenSource.cancel(); + } else if ((entries.length === 0) && defaultEntry) { entries.push(defaultEntry); } else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) { entries.push({ type: 'separator', label: '' }); entries.push(additionalEntries[0]); } return entries; - }), { + }); + return this.quickInputService.pick(pickEntries, { placeHolder, matchOnDescription: true, onDidTriggerItemButton: context => { @@ -1760,6 +2070,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this.openConfig(task); } } + }, cancellationToken).then(async (selection) => { + if (cancellationToken.isCancellationRequested) { + // canceled when there's only one task + const task = (await pickEntries)[0]; + if ((task).task) { + selection = task; + } + } + if (!selection) { + return; + } + return selection; }); } @@ -1794,7 +2116,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer let resolver = this.createResolver(grouped); let folders = this.contextService.getWorkspace().folders; for (let folder of folders) { - let task = resolver.resolve(folder, identifier); + let task = resolver.resolve(folder.uri, identifier); if (task) { this.run(task).then(undefined, reason => { // eat the error, it has already been surfaced to the user and we don't care about it here @@ -2096,7 +2418,78 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return result; } - private runConfigureTasks(): void { + private openTaskFile(resource: URI) { + let configFileCreated = false; + this.fileService.resolve(resource).then((stat) => stat, () => undefined).then((stat) => { + if (stat) { + return stat.resource; + } + return this.quickInputService.pick(getTaskTemplates(), { placeHolder: nls.localize('TaskService.template', 'Select a Task Template') }).then((selection) => { + if (!selection) { + return Promise.resolve(undefined); + } + let content = selection.content; + let editorConfig = this.configurationService.getValue(); + if (editorConfig.editor.insertSpaces) { + content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); + } + configFileCreated = true; + type TaskServiceTemplateClassification = { + templateId?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + autoDetect: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type TaskServiceEvent = { + templateId?: string; + autoDetect: boolean; + }; + return this.textFileService.create(resource, content).then((result): URI => { + this.telemetryService.publicLog2('taskService.template', { + templateId: selection.id, + autoDetect: selection.autoDetect + }); + return result.resource; + }); + }); + }).then((resource) => { + if (!resource) { + return; + } + this.editorService.openEditor({ + resource, + options: { + pinned: configFileCreated // pin only if config file is created #8727 + } + }); + }); + } + + private isTaskEntry(value: IQuickPickItem): value is IQuickPickItem & { task: Task } { + let candidate: IQuickPickItem & { task: Task } = value as any; + return candidate && !!candidate.task; + } + + private configureTask(task: Task) { + if (ContributedTask.is(task)) { + this.customize(task, undefined, true); + } else if (CustomTask.is(task)) { + this.openConfig(task); + } else if (ConfiguringTask.is(task)) { + // Do nothing. + } + } + + private handleSelection(selection: TaskQuickPickEntryType) { + if (!selection) { + return; + } + if (this.isTaskEntry(selection)) { + this.configureTask(selection.task); + } else { + this.openTaskFile(selection.folder.toResource('.vscode/tasks.json')); + } + } + + private async runConfigureTasks(): Promise { if (!this.canRunCommand()) { return undefined; } @@ -2107,80 +2500,20 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer taskPromise = Promise.resolve(new TaskMap()); } - let openTaskFile = (workspaceFolder: IWorkspaceFolder): void => { - let resource = workspaceFolder.toResource('.vscode/tasks.json'); - let configFileCreated = false; - this.fileService.resolve(resource).then((stat) => stat, () => undefined).then((stat) => { - if (stat) { - return stat.resource; - } - return this.quickInputService.pick(getTaskTemplates(), { placeHolder: nls.localize('TaskService.template', 'Select a Task Template') }).then((selection) => { - if (!selection) { - return Promise.resolve(undefined); - } - let content = selection.content; - let editorConfig = this.configurationService.getValue(); - if (editorConfig.editor.insertSpaces) { - content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); - } - configFileCreated = true; - type TaskServiceTemplateClassification = { - templateId?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - autoDetect: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - }; - type TaskServiceEvent = { - templateId?: string; - autoDetect: boolean; - }; - return this.textFileService.create(resource, content).then((result): URI => { - this.telemetryService.publicLog2('taskService.template', { - templateId: selection.id, - autoDetect: selection.autoDetect - }); - return result.resource; - }); - }); - }).then((resource) => { - if (!resource) { - return; - } - this.editorService.openEditor({ - resource, - options: { - pinned: configFileCreated // pin only if config file is created #8727 - } - }); - }); - }; - - let configureTask = (task: Task): void => { - if (ContributedTask.is(task)) { - this.customize(task, undefined, true); - } else if (CustomTask.is(task)) { - this.openConfig(task); - } else if (ConfiguringTask.is(task)) { - // Do nothing. - } - }; - - function isTaskEntry(value: IQuickPickItem): value is IQuickPickItem & { task: Task } { - let candidate: IQuickPickItem & { task: Task } = value as any; - return candidate && !!candidate.task; - } - let stats = this.contextService.getWorkspace().folders.map>((folder) => { return this.fileService.resolve(folder.toResource('.vscode/tasks.json')).then(stat => stat, () => undefined); }); let createLabel = nls.localize('TaskService.createJsonFile', 'Create tasks.json file from template'); let openLabel = nls.localize('TaskService.openJsonFile', 'Open tasks.json file'); + const tokenSource = new CancellationTokenSource(); + const cancellationToken: CancellationToken = tokenSource.token; let entries = Promise.all(stats).then((stats) => { return taskPromise.then((taskMap) => { - type EntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; }); - let entries: QuickPickInput[] = []; + let entries: QuickPickInput[] = []; + let needsCreateOrOpen: boolean = true; if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY) { let tasks = taskMap.all(); - let needsCreateOrOpen: boolean = true; if (tasks.length > 0) { tasks = tasks.sort((a, b) => a._label.localeCompare(b._label)); for (let task of tasks) { @@ -2205,7 +2538,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (tasks.length > 0) { tasks = tasks.slice().sort((a, b) => a._label.localeCompare(b._label)); for (let i = 0; i < tasks.length; i++) { - let entry: EntryType = { label: tasks[i]._label, task: tasks[i], description: folder.name }; + let entry: TaskQuickPickEntryType = { label: tasks[i]._label, task: tasks[i], description: folder.name }; if (i === 0) { entries.push({ type: 'separator', label: folder.name }); } @@ -2213,28 +2546,49 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } else { let label = stats[index] !== undefined ? openLabel : createLabel; - let entry: EntryType = { label, folder: folder }; + let entry: TaskQuickPickEntryType = { label, folder: folder }; entries.push({ type: 'separator', label: folder.name }); entries.push(entry); } index++; } } + if ((entries.length === 1) && !needsCreateOrOpen) { + tokenSource.cancel(); + } return entries; }); }); + const timeout: boolean = await Promise.race([new Promise(async (resolve) => { + await entries; + resolve(false); + }), new Promise((resolve) => { + const timer = setTimeout(() => { + clearTimeout(timer); + resolve(true); + }, 200); + })]); + + if (!timeout && ((await entries).length === 1) && this.configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { + const entry: any = ((await entries)[0]); + if (entry.task) { + this.handleSelection(entry); + return; + } + } + this.quickInputService.pick(entries, - { placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure') }). - then((selection) => { - if (!selection) { - return; - } - if (isTaskEntry(selection)) { - configureTask(selection.task); - } else { - openTaskFile(selection.folder); + { placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure') }, cancellationToken). + then(async (selection) => { + if (cancellationToken.isCancellationRequested) { + // canceled when there's only one task + const task = (await entries)[0]; + if ((task).task) { + selection = task; + } } + this.handleSelection(selection); }); } @@ -2339,23 +2693,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - public runShowTasks(): void { + public async runShowTasks(): Promise { if (!this.canRunCommand()) { return; } - this.showQuickPick(this.getActiveTasks(), - nls.localize('TaskService.pickShowTask', 'Select the task to show its output'), - { - label: nls.localize('TaskService.noTaskIsRunning', 'No task is running'), - task: null - }, - false, true - ).then((entry) => { - let task: Task | undefined | null = entry ? entry.task : undefined; - if (task === undefined || task === null) { - return; - } - this._taskSystem!.revealTask(task); - }); + const activeTasks: Task[] = await this.getActiveTasks(); + if (activeTasks.length === 1) { + this._taskSystem!.revealTask(activeTasks[0]); + } else { + this.showQuickPick(this.getActiveTasks(), + nls.localize('TaskService.pickShowTask', 'Select the task to show its output'), + { + label: nls.localize('TaskService.noTaskIsRunning', 'No task is running'), + task: null + }, + false, true + ).then((entry) => { + let task: Task | undefined | null = entry ? entry.task : undefined; + if (task === undefined || task === null) { + return; + } + this._taskSystem!.revealTask(task); + }); + } } } diff --git a/src/vs/workbench/contrib/tasks/browser/quickOpen.ts b/src/vs/workbench/contrib/tasks/browser/quickOpen.ts index b14cc7ba44f..7863d7e66e5 100644 --- a/src/vs/workbench/contrib/tasks/browser/quickOpen.ts +++ b/src/vs/workbench/contrib/tasks/browser/quickOpen.ts @@ -173,7 +173,7 @@ class CustomizeTaskAction extends Action { } public updateClass(): void { - this.class = 'quick-open-task-configure'; + this.class = 'codicon-gear'; } public run(element: any): Promise { @@ -235,4 +235,4 @@ export class QuickOpenActionContributor extends ActionBarContributor { } return undefined; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 966902be47e..ab806797f1e 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!../common/media/task.contribution'; - import * as nls from 'vs/nls'; import { QuickOpenHandler } from 'vs/workbench/contrib/tasks/browser/taskQuickOpen'; @@ -19,7 +17,7 @@ import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/ import * as jsonContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { IOutputChannelRegistry, Extensions as OutputExt } from 'vs/workbench/contrib/output/common/output'; @@ -33,6 +31,13 @@ import { QuickOpenActionContributor } from '../browser/quickOpen'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { RunAutomaticTasks, ManageAutomaticTaskRunning } from 'vs/workbench/contrib/tasks/browser/runAutomaticTasks'; +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; +import schemaVersion1 from '../common/jsonSchema_v1'; +import schemaVersion2, { updateProblemMatchers } from '../common/jsonSchema_v2'; +import { AbstractTaskService, ConfigureTaskAction } from 'vs/workbench/contrib/tasks/browser/abstractTaskService'; +import { tasksSchemaId } from 'vs/workbench/services/configuration/common/configuration'; +import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; let tasksCategory = nls.localize('tasksCategory', "Tasks"); @@ -99,7 +104,7 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench } if (promise && (event.kind === TaskEventKind.Active) && (this.activeTasksCount === 1)) { - this.progressService.withProgress({ location: ProgressLocation.Window }, progress => { + this.progressService.withProgress({ location: ProgressLocation.Window, command: 'workbench.action.tasks.showTasks' }, progress => { progress.report({ message: nls.localize('building', 'Building...') }); return promise!; }).then(() => { @@ -233,6 +238,13 @@ MenuRegistry.addCommand({ id: 'workbench.action.tasks.configureDefaultTestTask', // MenuRegistry.addCommand( { id: 'workbench.action.tasks.rebuild', title: nls.localize('RebuildAction.label', 'Run Rebuild Task'), category: tasksCategory }); // MenuRegistry.addCommand( { id: 'workbench.action.tasks.clean', title: nls.localize('CleanAction.label', 'Run Clean Task'), category: tasksCategory }); +KeybindingsRegistry.registerKeybindingRule({ + id: 'workbench.action.tasks.build', + weight: KeybindingWeight.WorkbenchContrib, + when: undefined, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_B +}); + // Tasks Output channel. Register it before using it in Task Service. let outputChannelRegistry = Registry.as(OutputExt.OutputChannels); outputChannelRegistry.registerChannel({ id: AbstractTaskService.OutputChannelId, label: AbstractTaskService.OutputChannelLabel, log: false }); @@ -255,9 +267,8 @@ const actionBarRegistry = Registry.as(ActionBarExtensions.Ac actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionContributor); // tasks.json validation -let schemaId = 'vscode://schemas/tasks'; let schema: IJSONSchema = { - id: schemaId, + id: tasksSchemaId, description: 'Task definition file', type: 'object', allowTrailingCommas: true, @@ -280,9 +291,6 @@ let schema: IJSONSchema = { } }; -import schemaVersion1 from '../common/jsonSchema_v1'; -import schemaVersion2, { updateProblemMatchers } from '../common/jsonSchema_v2'; -import { AbstractTaskService, ConfigureTaskAction } from 'vs/workbench/contrib/tasks/browser/abstractTaskService'; schema.definitions = { ...schemaVersion1.definitions, ...schemaVersion2.definitions, @@ -290,9 +298,79 @@ schema.definitions = { schema.oneOf = [...(schemaVersion2.oneOf || []), ...(schemaVersion1.oneOf || [])]; let jsonRegistry = Registry.as(jsonContributionRegistry.Extensions.JSONContribution); -jsonRegistry.registerSchema(schemaId, schema); +jsonRegistry.registerSchema(tasksSchemaId, schema); ProblemMatcherRegistry.onMatcherChanged(() => { updateProblemMatchers(); - jsonRegistry.notifySchemaChanged(schemaId); + jsonRegistry.notifySchemaChanged(tasksSchemaId); +}); + +const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); +configurationRegistry.registerConfiguration({ + id: 'task', + order: 100, + title: nls.localize('tasksConfigurationTitle', "Tasks"), + type: 'object', + properties: { + 'task.problemMatchers.neverPrompt': { + markdownDescription: nls.localize('task.problemMatchers.neverPrompt', "Configures whether to show the problem matcher prompt when running a task. Set to `true` to never promp, or use a dictionary of task types to turn off prompting only for specific task types."), + 'oneOf': [ + { + type: 'boolean', + markdownDescription: nls.localize('task.problemMatchers.neverPrompt.boolean', 'Sets problem matcher prompting behavior for all tasks.') + }, + { + type: 'object', + patternProperties: { + '.*': { + type: 'boolean' + } + }, + markdownDescription: nls.localize('task.problemMatchers.neverPrompt.array', 'An object containing task type-boolean pairs to never prompt for problem matchers on.'), + default: { + 'shell': true + } + } + ], + default: false + }, + 'task.autoDetect': { + markdownDescription: nls.localize('task.autoDetect', "Controls enablement of `provideTasks` for all task provider extension. If the Tasks: Run Task command is slow, disabling auto detect for task providers may help. Individual extensions my provide settings to disabled auto detection."), + type: 'string', + enum: ['on', 'off'], + default: 'on' + }, + 'task.slowProviderWarning': { + markdownDescription: nls.localize('task.slowProviderWarning', "Configures whether a warning is shown when a provider is slow"), + 'oneOf': [ + { + type: 'boolean', + markdownDescription: nls.localize('task.slowProviderWarning.boolean', 'Sets the slow provider warning for all tasks.') + }, + { + type: 'array', + items: { + type: 'string', + markdownDescription: nls.localize('task.slowProviderWarning.array', 'An array of task types to never show the slow provider warning.') + } + } + ], + default: true + }, + 'task.quickOpen.history': { + markdownDescription: nls.localize('task.quickOpen.history', "Controls the number of recent items tracked in task quick open dialog."), + type: 'number', + default: 30, minimum: 0, maximum: 30 + }, + 'task.quickOpen.detail': { + markdownDescription: nls.localize('task.quickOpen.detail', "Controls whether to show the task detail for task that have a detail in the Run Task quick pick."), + type: 'boolean', + default: true + }, + 'task.quickOpen.skip': { + type: 'boolean', + description: nls.localize('task.quickOpen.skip', "Controls whether the task quick pick is skipped when there is only one task to pick from."), + default: false + } + } }); diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index ce5593930c6..e9c719a87ae 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -113,7 +113,7 @@ export class TerminalTaskSystem implements ITaskSystem { public static TelemetryEventName: string = 'taskService'; - private static ProcessVarName = '__process__'; + private static readonly ProcessVarName = '__process__'; private static shellQuotes: IStringDictionary = { 'cmd': { @@ -152,6 +152,7 @@ export class TerminalTaskSystem implements ITaskSystem { }; private activeTasks: IStringDictionary; + private busyTasks: IStringDictionary; private terminals: IStringDictionary; private idleTaskTerminals: LinkedMap; private sameTaskTerminals: IStringDictionary; @@ -180,6 +181,7 @@ export class TerminalTaskSystem implements ITaskSystem { ) { this.activeTasks = Object.create(null); + this.busyTasks = Object.create(null); this.terminals = Object.create(null); this.idleTaskTerminals = new LinkedMap(); this.sameTaskTerminals = Object.create(null); @@ -280,6 +282,10 @@ export class TerminalTaskSystem implements ITaskSystem { return Object.keys(this.activeTasks).map(key => this.activeTasks[key].task); } + public getBusyTasks(): Task[] { + return Object.keys(this.busyTasks).map(key => this.busyTasks[key]); + } + public customExecutionComplete(task: Task, result: number): Promise { let activeTerminal = this.activeTasks[task.getMapKey()]; if (!activeTerminal) { @@ -337,17 +343,18 @@ export class TerminalTaskSystem implements ITaskSystem { return Promise.all(promises); } - private async executeTask(task: Task, resolver: ITaskResolver, trigger: string): Promise { + private async executeTask(task: Task, resolver: ITaskResolver, trigger: string, alreadyResolved?: Map): Promise { + alreadyResolved = alreadyResolved ?? new Map(); let promises: Promise[] = []; if (task.configurationProperties.dependsOn) { for (const dependency of task.configurationProperties.dependsOn) { - let dependencyTask = resolver.resolve(dependency.workspaceFolder, dependency.task!); + let dependencyTask = resolver.resolve(dependency.uri, dependency.task!); if (dependencyTask) { let key = dependencyTask.getMapKey(); let promise = this.activeTasks[key] ? this.activeTasks[key].promise : undefined; if (!promise) { this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.DependsOnStarted, task)); - promise = this.executeTask(dependencyTask, resolver, trigger); + promise = this.executeTask(dependencyTask, resolver, trigger, alreadyResolved); } if (task.configurationProperties.dependsOrder === DependsOrder.sequence) { promise = Promise.resolve(await promise); @@ -357,7 +364,7 @@ export class TerminalTaskSystem implements ITaskSystem { this.log(nls.localize('dependencyFailed', 'Couldn\'t resolve dependent task \'{0}\' in workspace folder \'{1}\'', Types.isString(dependency.task) ? dependency.task : JSON.stringify(dependency.task, undefined, 0), - dependency.workspaceFolder.name + dependency.uri.toString() )); this.showOutput(); } @@ -372,9 +379,9 @@ export class TerminalTaskSystem implements ITaskSystem { } } if (this.isRerun) { - return this.reexecuteCommand(task, trigger); + return this.reexecuteCommand(task, trigger, alreadyResolved!); } else { - return this.executeCommand(task, trigger); + return this.executeCommand(task, trigger, alreadyResolved!); } }); } else { @@ -389,7 +396,36 @@ export class TerminalTaskSystem implements ITaskSystem { } } - private resolveVariablesFromSet(taskSystemInfo: TaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, variables: Set): Promise { + private resolveAndFindExecutable(workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, cwd: string | undefined, envPath: string | undefined): Promise { + return this.findExecutable( + this.configurationResolverService.resolve(workspaceFolder, CommandString.value(task.command.name!)), + cwd ? this.configurationResolverService.resolve(workspaceFolder, cwd) : undefined, + envPath ? envPath.split(path.delimiter).map(p => this.configurationResolverService.resolve(workspaceFolder, p)) : undefined + ); + } + + private findUnresolvedVariables(variables: Set, alreadyResolved: Map): Set { + if (alreadyResolved.size === 0) { + return variables; + } + const unresolved = new Set(); + for (const variable of variables) { + if (!alreadyResolved.has(variable.substring(2, variable.length - 1))) { + unresolved.add(variable); + } + } + return unresolved; + } + + private mergeMaps(mergeInto: Map, mergeFrom: Map) { + for (const entry of mergeFrom) { + if (!mergeInto.has(entry[0])) { + mergeInto.set(entry[0], entry[1]); + } + } + } + + private resolveVariablesFromSet(taskSystemInfo: TaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, variables: Set, alreadyResolved: Map): Promise { let isProcess = task.command && task.command.runtime === RuntimeType.Process; let options = task.command && task.command.options ? task.command.options : undefined; let cwd = options ? options.cwd : undefined; @@ -404,11 +440,11 @@ export class TerminalTaskSystem implements ITaskSystem { } } } - + const unresolved = this.findUnresolvedVariables(variables, alreadyResolved); let resolvedVariables: Promise; if (taskSystemInfo && workspaceFolder) { let resolveSet: ResolveSet = { - variables + variables: unresolved }; if (taskSystemInfo.platform === Platform.Platform.Windows && isProcess) { @@ -420,28 +456,32 @@ export class TerminalTaskSystem implements ITaskSystem { resolveSet.process.path = envPath; } } - resolvedVariables = taskSystemInfo.resolveVariables(workspaceFolder, resolveSet).then(resolved => { - if ((taskSystemInfo.platform !== Platform.Platform.Windows) && isProcess) { - resolved.variables.set(TerminalTaskSystem.ProcessVarName, CommandString.value(task.command.name!)); + resolvedVariables = taskSystemInfo.resolveVariables(workspaceFolder, resolveSet).then(async (resolved) => { + this.mergeMaps(alreadyResolved, resolved.variables); + resolved.variables = new Map(alreadyResolved); + if (isProcess) { + let process = CommandString.value(task.command.name!); + if (taskSystemInfo.platform === Platform.Platform.Windows) { + process = await this.resolveAndFindExecutable(workspaceFolder, task, cwd, envPath); + } + resolved.variables.set(TerminalTaskSystem.ProcessVarName, process); } return Promise.resolve(resolved); }); return resolvedVariables; } else { let variablesArray = new Array(); - variables.forEach(variable => variablesArray.push(variable)); + unresolved.forEach(variable => variablesArray.push(variable)); return new Promise((resolve, reject) => { - this.configurationResolverService.resolveWithInteraction(workspaceFolder, variablesArray, 'tasks').then(async resolvedVariablesMap => { + this.configurationResolverService.resolveWithInteraction(workspaceFolder, variablesArray, 'tasks').then(async (resolvedVariablesMap: Map | undefined) => { if (resolvedVariablesMap) { + this.mergeMaps(alreadyResolved, resolvedVariablesMap); + resolvedVariablesMap = new Map(alreadyResolved); if (isProcess) { let processVarValue: string; if (Platform.isWindows) { - processVarValue = await this.findExecutable( - this.configurationResolverService.resolve(workspaceFolder, CommandString.value(task.command.name!)), - cwd ? this.configurationResolverService.resolve(workspaceFolder, cwd) : undefined, - envPath ? envPath.split(path.delimiter).map(p => this.configurationResolverService.resolve(workspaceFolder, p)) : undefined - ); + processVarValue = await this.resolveAndFindExecutable(workspaceFolder, task, cwd, envPath); } else { processVarValue = this.configurationResolverService.resolve(workspaceFolder, CommandString.value(task.command.name!)); } @@ -461,20 +501,29 @@ export class TerminalTaskSystem implements ITaskSystem { } } - private executeCommand(task: CustomTask | ContributedTask, trigger: string): Promise { - const workspaceFolder = this.currentTask.workspaceFolder = task.getWorkspaceFolder(); + private executeCommand(task: CustomTask | ContributedTask, trigger: string, alreadyResolved: Map): Promise { + const taskWorkspaceFolder = task.getWorkspaceFolder(); + let workspaceFolder: IWorkspaceFolder | undefined; + if (taskWorkspaceFolder) { + workspaceFolder = this.currentTask.workspaceFolder = taskWorkspaceFolder; + } else { + const folders = this.contextService.getWorkspace().folders; + workspaceFolder = folders.length > 0 ? folders[0] : undefined; + } const systemInfo: TaskSystemInfo | undefined = this.currentTask.systemInfo = workspaceFolder ? this.taskSystemInfoResolver(workspaceFolder) : undefined; let variables = new Set(); this.collectTaskVariables(variables, task); - const resolvedVariables = this.resolveVariablesFromSet(systemInfo, workspaceFolder, task, variables); + const resolvedVariables = this.resolveVariablesFromSet(systemInfo, workspaceFolder, task, variables, alreadyResolved); return resolvedVariables.then((resolvedVariables) => { - const isCustomExecution = (task.command.runtime === RuntimeType.CustomExecution2); + const isCustomExecution = (task.command.runtime === RuntimeType.CustomExecution); if (resolvedVariables && (task.command !== undefined) && task.command.runtime && (isCustomExecution || (task.command.name !== undefined))) { this.currentTask.resolvedVariables = resolvedVariables; return this.executeInTerminal(task, trigger, new VariableResolver(workspaceFolder, systemInfo, resolvedVariables.variables, this.configurationResolverService), workspaceFolder); } else { + // Allows the taskExecutions array to be updated in the extension host + this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.End, task)); return Promise.resolve({ exitCode: 0 }); } }, reason => { @@ -482,7 +531,7 @@ export class TerminalTaskSystem implements ITaskSystem { }); } - private reexecuteCommand(task: CustomTask | ContributedTask, trigger: string): Promise { + private reexecuteCommand(task: CustomTask | ContributedTask, trigger: string, alreadyResolved: Map): Promise { const lastTask = this.lastTask; if (!lastTask) { return Promise.reject(new Error('No task previously run')); @@ -500,7 +549,7 @@ export class TerminalTaskSystem implements ITaskSystem { }); if (!hasAllVariables) { - return this.resolveVariablesFromSet(lastTask.getVerifiedTask().systemInfo, lastTask.getVerifiedTask().workspaceFolder, task, variables).then((resolvedVariables) => { + return this.resolveVariablesFromSet(lastTask.getVerifiedTask().systemInfo, lastTask.getVerifiedTask().workspaceFolder, task, variables, alreadyResolved).then((resolvedVariables) => { this.currentTask.resolvedVariables = resolvedVariables; return this.executeInTerminal(task, trigger, new VariableResolver(lastTask.getVerifiedTask().workspaceFolder, lastTask.getVerifiedTask().systemInfo, resolvedVariables.variables, this.configurationResolverService), workspaceFolder!); }, reason => { @@ -520,14 +569,23 @@ export class TerminalTaskSystem implements ITaskSystem { if (task.configurationProperties.isBackground) { const problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this.markerService, this.modelService, this.fileService); + if ((problemMatchers.length > 0) && !watchingProblemMatcher.isWatching()) { + this.appendOutput(nls.localize('TerminalTaskSystem.nonWatchingMatcher', 'Task {0} is a background task but uses a problem matcher without a background pattern', task._label)); + this.showOutput(); + } const toDispose = new DisposableStore(); let eventCounter: number = 0; + const mapKey = task.getMapKey(); toDispose.add(watchingProblemMatcher.onDidStateChange((event) => { if (event.kind === ProblemCollectorEventKind.BackgroundProcessingBegins) { eventCounter++; + this.busyTasks[mapKey] = task; this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Active, task)); } else if (event.kind === ProblemCollectorEventKind.BackgroundProcessingEnds) { eventCounter--; + if (this.busyTasks[mapKey]) { + delete this.busyTasks[mapKey]; + } this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Inactive, task)); if (eventCounter === 0) { if ((watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity && @@ -586,6 +644,9 @@ export class TerminalTaskSystem implements ITaskSystem { onData.dispose(); onExit.dispose(); let key = task.getMapKey(); + if (this.busyTasks[mapKey]) { + delete this.busyTasks[mapKey]; + } delete this.activeTasks[key]; this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Changed)); if (exitCode !== undefined) { @@ -645,6 +706,8 @@ export class TerminalTaskSystem implements ITaskSystem { // The process never got ready. Need to think how to handle this. }); this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Start, task, terminal.id)); + const mapKey = task.getMapKey(); + this.busyTasks[mapKey] = task; this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Active, task)); let problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService, ProblemHandlingStrategy.Clean, this.fileService); @@ -698,6 +761,9 @@ export class TerminalTaskSystem implements ITaskSystem { } this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessEnded, task, exitCode)); + if (this.busyTasks[mapKey]) { + delete this.busyTasks[mapKey]; + } this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Inactive, task)); this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.End, task)); resolve({ exitCode }); @@ -850,7 +916,7 @@ export class TerminalTaskSystem implements ITaskSystem { } } } else { - let commandExecutable = (task.command.runtime !== RuntimeType.CustomExecution2) ? CommandString.value(command) : undefined; + let commandExecutable = (task.command.runtime !== RuntimeType.CustomExecution) ? CommandString.value(command) : undefined; let executable = !isShellCommand ? this.resolveVariable(variableResolver, '${' + TerminalTaskSystem.ProcessVarName + '}') : commandExecutable; @@ -921,7 +987,7 @@ export class TerminalTaskSystem implements ITaskSystem { let args: CommandString[] | undefined; let launchConfigs: IShellLaunchConfig | undefined; - if (task.command.runtime === RuntimeType.CustomExecution2) { + if (task.command.runtime === RuntimeType.CustomExecution) { this.currentTask.shellLaunchConfig = launchConfigs = { isExtensionTerminal: true, waitOnExit, @@ -976,6 +1042,7 @@ export class TerminalTaskSystem implements ITaskSystem { throw new Error('Task shell launch configuration should not be undefined here.'); } + terminalToReuse.terminal.scrollToBottom(); terminalToReuse.terminal.reuseTerminal(launchConfigs); if (task.command.presentation && task.command.presentation.clear) { @@ -1016,7 +1083,11 @@ export class TerminalTaskSystem implements ITaskSystem { // This can happen if the terminal wasn't shutdown with an "immediate" flag and is expected. // For correct terminal re-use, the task needs to be deleted immediately. // Note that this shouldn't be a problem anymore since user initiated terminal kills are now immediate. - delete this.activeTasks[task.getMapKey()]; + const mapKey = task.getMapKey(); + delete this.activeTasks[mapKey]; + if (this.busyTasks[mapKey]) { + delete this.busyTasks[mapKey]; + } } }); this.terminals[terminalKey] = { terminal: result, lastTask: taskKey, group }; @@ -1142,7 +1213,7 @@ export class TerminalTaskSystem implements ITaskSystem { private collectCommandVariables(variables: Set, command: CommandConfiguration, task: CustomTask | ContributedTask): void { // The custom execution should have everything it needs already as it provided // the callback. - if (command.runtime === RuntimeType.CustomExecution2) { + if (command.runtime === RuntimeType.CustomExecution) { return; } @@ -1375,6 +1446,14 @@ export class TerminalTaskSystem implements ITaskSystem { } } + private async fileExists(path: string): Promise { + const uri: URI = resources.toLocalResource(URI.from({ scheme: Schemas.file, path: path }), this.environmentService.configuration.remoteAuthority); + if (await this.fileService.exists(uri)) { + return !((await this.fileService.resolve(uri)).isDirectory); + } + return false; + } + private async findExecutable(command: string, cwd?: string, paths?: string[]): Promise { // If we have an absolute path then we take it. if (path.isAbsolute(command)) { @@ -1407,15 +1486,15 @@ export class TerminalTaskSystem implements ITaskSystem { fullPath = path.join(cwd, pathEntry, command); } - if (await this.fileService.exists(resources.toLocalResource(URI.from({ scheme: Schemas.file, path: fullPath }), this.environmentService.configuration.remoteAuthority))) { + if (await this.fileExists(fullPath)) { return fullPath; } let withExtension = fullPath + '.com'; - if (await this.fileService.exists(resources.toLocalResource(URI.from({ scheme: Schemas.file, path: withExtension }), this.environmentService.configuration.remoteAuthority))) { + if (await this.fileExists(withExtension)) { return withExtension; } withExtension = fullPath + '.exe'; - if (await this.fileService.exists(resources.toLocalResource(URI.from({ scheme: Schemas.file, path: withExtension }), this.environmentService.configuration.remoteAuthority))) { + if (await this.fileExists(withExtension)) { return withExtension; } } diff --git a/src/vs/workbench/contrib/tasks/common/jsonSchemaCommon.ts b/src/vs/workbench/contrib/tasks/common/jsonSchemaCommon.ts index 89f5ef65397..70ccd46ec32 100644 --- a/src/vs/workbench/contrib/tasks/common/jsonSchemaCommon.ts +++ b/src/vs/workbench/contrib/tasks/common/jsonSchemaCommon.ts @@ -44,10 +44,10 @@ const schema: IJSONSchema = { type: 'array', items: { anyOf: [ - Schemas.LegacyProblemMatcher, { type: 'string', - } + }, + Schemas.LegacyProblemMatcher ] } } @@ -115,16 +115,52 @@ const schema: IJSONSchema = { $ref: '#/definitions/options' }, windows: { - $ref: '#/definitions/commandConfiguration', - description: nls.localize('JsonSchema.tasks.windows', 'Windows specific command configuration') + anyOf: [ + { + $ref: '#/definitions/commandConfiguration', + description: nls.localize('JsonSchema.tasks.windows', 'Windows specific command configuration'), + }, + { + properties: { + problemMatcher: { + $ref: '#/definitions/problemMatcherType', + description: nls.localize('JsonSchema.tasks.matchers', 'The problem matcher(s) to use. Can either be a string or a problem matcher definition or an array of strings and problem matchers.') + } + } + } + ] }, osx: { - $ref: '#/definitions/commandConfiguration', - description: nls.localize('JsonSchema.tasks.mac', 'Mac specific command configuration') + anyOf: [ + { + $ref: '#/definitions/commandConfiguration', + description: nls.localize('JsonSchema.tasks.mac', 'Mac specific command configuration') + }, + { + properties: { + problemMatcher: { + $ref: '#/definitions/problemMatcherType', + description: nls.localize('JsonSchema.tasks.matchers', 'The problem matcher(s) to use. Can either be a string or a problem matcher definition or an array of strings and problem matchers.') + } + } + } + ] }, linux: { - $ref: '#/definitions/commandConfiguration', - description: nls.localize('JsonSchema.tasks.linux', 'Linux specific command configuration') + anyOf: [ + { + $ref: '#/definitions/commandConfiguration', + description: nls.localize('JsonSchema.tasks.linux', 'Linux specific command configuration') + }, + { + properties: { + problemMatcher: { + $ref: '#/definitions/problemMatcherType', + description: nls.localize('JsonSchema.tasks.matchers', 'The problem matcher(s) to use. Can either be a string or a problem matcher definition or an array of strings and problem matchers.') + } + } + } + ] }, suppressTaskName: { type: 'boolean', @@ -241,4 +277,4 @@ const schema: IJSONSchema = { } }; -export default schema; \ No newline at end of file +export default schema; diff --git a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts index 58d396469d8..1fcd569b476 100644 --- a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts +++ b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts @@ -89,6 +89,11 @@ const dependsOrder: IJSONSchema = { description: nls.localize('JsonSchema.tasks.dependsOrder', 'Determines the order of the dependsOn tasks for this task. Note that this property is not recursive.') }; +const detail: IJSONSchema = { + type: 'string', + description: nls.localize('JsonSchema.tasks.detail', 'An optional description of a task that shows in the Run Task quick pick as a detail.') +}; + const presentation: IJSONSchema = { type: 'object', default: { @@ -365,7 +370,8 @@ let taskConfiguration: IJSONSchema = { }, runOptions: Objects.deepClone(runOptions), dependsOn: Objects.deepClone(dependsOn), - dependsOrder: Objects.deepClone(dependsOrder) + dependsOrder: Objects.deepClone(dependsOrder), + detail: Objects.deepClone(detail), } }; @@ -425,6 +431,7 @@ taskDescriptionProperties.presentation = Objects.deepClone(presentation); taskDescriptionProperties.terminal = terminal; taskDescriptionProperties.group = Objects.deepClone(group); taskDescriptionProperties.runOptions = Objects.deepClone(runOptions); +taskDescriptionProperties.detail = detail; taskDescriptionProperties.taskName.deprecationMessage = nls.localize( 'JsonSchema.tasks.taskName.deprecated', 'The task\'s name property is deprecated. Use the label property instead.' @@ -562,7 +569,7 @@ export function updateProblemMatchers() { try { let matcherIds = ProblemMatcherRegistry.keys().map(key => '$' + key); definitions.problemMatcherType2.oneOf![0].enum = matcherIds; - (definitions.problemMatcherType2.oneOf![2].items as IJSONSchema).anyOf![1].enum = matcherIds; + (definitions.problemMatcherType2.oneOf![2].items as IJSONSchema).anyOf![0].enum = matcherIds; } catch (err) { console.log('Installing problem matcher ids failed'); } diff --git a/src/vs/workbench/contrib/tasks/common/media/configure-dark.svg b/src/vs/workbench/contrib/tasks/common/media/configure-dark.svg deleted file mode 100644 index ace01a5ddf5..00000000000 --- a/src/vs/workbench/contrib/tasks/common/media/configure-dark.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg b/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg deleted file mode 100644 index bd59cb81f6d..00000000000 --- a/src/vs/workbench/contrib/tasks/common/media/configure-hc.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/contrib/tasks/common/media/configure-light.svg b/src/vs/workbench/contrib/tasks/common/media/configure-light.svg deleted file mode 100644 index 4194780bbaa..00000000000 --- a/src/vs/workbench/contrib/tasks/common/media/configure-light.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/contrib/tasks/common/media/task.contribution.css b/src/vs/workbench/contrib/tasks/common/media/task.contribution.css deleted file mode 100644 index 2a617741ff6..00000000000 --- a/src/vs/workbench/contrib/tasks/common/media/task.contribution.css +++ /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. - *--------------------------------------------------------------------------------------------*/ - -.monaco-workbench .quick-open-task-configure { - background-image: url('configure-light.svg'); -} - -.vs-dark .monaco-workbench .quick-open-task-configure { - background-image: url('configure-dark.svg'); -} - -.hc-black .monaco-workbench .quick-open-task-configure { - background-image: url('configure-hc.svg'); -} diff --git a/src/vs/workbench/contrib/tasks/common/problemCollectors.ts b/src/vs/workbench/contrib/tasks/common/problemCollectors.ts index 30333ecdc3d..70e9d1b1fb5 100644 --- a/src/vs/workbench/contrib/tasks/common/problemCollectors.ts +++ b/src/vs/workbench/contrib/tasks/common/problemCollectors.ts @@ -524,4 +524,8 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement }); super.done(); } + + public isWatching(): boolean { + return this.backgroundPatterns.length > 0; + } } diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index 56cc9ad1c0c..2677f6bd2ce 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -18,7 +18,7 @@ import { isNamedProblemMatcher, ProblemMatcherRegistry } from 'vs/workbench/contrib/tasks/common/problemMatcher'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import * as Tasks from './tasks'; import { TaskDefinitionRegistry } from './taskDefinitionRegistry'; import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -309,6 +309,11 @@ export interface ConfigurationProperties { */ group?: string | GroupKind; + /** + * A description of the task. + */ + detail?: string; + /** * The other tasks the task depend on */ @@ -547,7 +552,7 @@ interface MetaData { } -function _isEmpty(this: void, value: T | undefined, properties: MetaData[] | undefined): boolean { +function _isEmpty(this: void, value: T | undefined, properties: MetaData[] | undefined, allowEmptyArray: boolean = false): boolean { if (value === undefined || value === null || properties === undefined) { return true; } @@ -556,7 +561,7 @@ function _isEmpty(this: void, value: T | undefined, properties: MetaData 0) { + } else if (!Array.isArray(property) || (property.length > 0) || allowEmptyArray) { return false; } } @@ -586,11 +591,11 @@ function _assignProperties(this: void, target: T | undefined, source: T | und return target; } -function _fillProperties(this: void, target: T | undefined, source: T | undefined, properties: MetaData[] | undefined): T | undefined { +function _fillProperties(this: void, target: T | undefined, source: T | undefined, properties: MetaData[] | undefined, allowEmptyArray: boolean = false): T | undefined { if (!source || _isEmpty(source, properties)) { return target; } - if (!target || _isEmpty(target, properties)) { + if (!target || _isEmpty(target, properties, allowEmptyArray)) { return source; } for (let meta of properties!) { @@ -683,6 +688,7 @@ export namespace RunOptions { interface ParseContext { workspaceFolder: IWorkspaceFolder; + workspace: IWorkspace | undefined; problemReporter: IProblemReporter; namedProblemMatchers: IStringDictionary; uuidMap: UUIDMap; @@ -721,7 +727,7 @@ namespace ShellConfiguration { } export function isEmpty(this: void, value: Tasks.ShellConfiguration): boolean { - return _isEmpty(value, properties); + return _isEmpty(value, properties, true); } export function assignProperties(this: void, target: Tasks.ShellConfiguration | undefined, source: Tasks.ShellConfiguration | undefined): Tasks.ShellConfiguration | undefined { @@ -729,7 +735,7 @@ namespace ShellConfiguration { } export function fillProperties(this: void, target: Tasks.ShellConfiguration, source: Tasks.ShellConfiguration): Tasks.ShellConfiguration | undefined { - return _fillProperties(target, source, properties); + return _fillProperties(target, source, properties, true); } export function fillDefaults(this: void, value: Tasks.ShellConfiguration, context: ParseContext): Tasks.ShellConfiguration { @@ -1114,6 +1120,20 @@ namespace ProblemMatcherConverter { return result; } + export function fromWithOsConfig(this: void, external: ConfigurationProperties & { [key: string]: any; }, context: ParseContext): ProblemMatcher[] | undefined { + let result: ProblemMatcher[] | undefined = undefined; + if (external.windows && external.windows.problemMatcher && context.platform === Platform.Windows) { + result = from(external.windows.problemMatcher, context); + } else if (external.osx && external.osx.problemMatcher && context.platform === Platform.Mac) { + result = from(external.osx.problemMatcher, context); + } else if (external.linux && external.linux.problemMatcher && context.platform === Platform.Linux) { + result = from(external.linux.problemMatcher, context); + } else if (external.problemMatcher) { + result = from(external.problemMatcher, context); + } + return result; + } + export function from(this: void, config: ProblemMatcherConfig.ProblemMatcherType | undefined, context: ParseContext): ProblemMatcher[] { let result: ProblemMatcher[] = []; if (config === undefined) { @@ -1181,8 +1201,7 @@ namespace ProblemMatcherConverter { } } -const source: Partial = { - kind: Tasks.TaskSourceKind.Workspace, +const partialSource: Partial = { label: 'Workspace', config: undefined }; @@ -1212,9 +1231,12 @@ namespace GroupKind { namespace TaskDependency { export function from(this: void, external: string | TaskIdentifier, context: ParseContext): Tasks.TaskDependency | undefined { if (Types.isString(external)) { - return { workspaceFolder: context.workspaceFolder, task: external }; + return { uri: context.workspace && context.workspace.configuration ? context.workspace.configuration : context.workspaceFolder.uri, task: external }; } else if (TaskIdentifier.is(external)) { - return { workspaceFolder: context.workspaceFolder, task: Tasks.TaskDefinition.createTaskIdentifier(external as Tasks.TaskIdentifier, context.problemReporter) }; + return { + uri: context.workspace && context.workspace.configuration ? context.workspace.configuration : context.workspaceFolder.uri, + task: Tasks.TaskDefinition.createTaskIdentifier(external as Tasks.TaskIdentifier, context.problemReporter) + }; } else { return undefined; } @@ -1305,8 +1327,12 @@ namespace ConfigurationProperties { if (includeCommandOptions && (external.options !== undefined)) { result.options = CommandOptions.from(external.options, context); } - if (external.problemMatcher) { - result.problemMatchers = ProblemMatcherConverter.from(external.problemMatcher, context); + const configProblemMatcher = ProblemMatcherConverter.fromWithOsConfig(external, context); + if (configProblemMatcher !== undefined) { + result.problemMatchers = configProblemMatcher; + } + if (external.detail) { + result.detail = external.detail; } return isEmpty(result) ? undefined : result; } @@ -1328,7 +1354,7 @@ namespace ConfiguringTask { customize: string; } - export function from(this: void, external: ConfiguringTask, context: ParseContext, index: number): Tasks.ConfiguringTask | undefined { + export function from(this: void, external: ConfiguringTask, context: ParseContext, index: number, source: TaskConfigSource): Tasks.ConfiguringTask | undefined { if (!external) { return undefined; } @@ -1383,9 +1409,24 @@ namespace ConfiguringTask { index, element: external }; + let taskSource: Tasks.FileBasedTaskSource; + switch (source) { + case TaskConfigSource.User: { + taskSource = Objects.assign({} as Tasks.UserTaskSource, partialSource, { kind: Tasks.TaskSourceKind.User, config: configElement }); + break; + } + case TaskConfigSource.WorkspaceFile: { + taskSource = Objects.assign({} as Tasks.WorkspaceFileTaskSource, partialSource, { kind: Tasks.TaskSourceKind.WorkspaceFile, config: configElement }); + break; + } + default: { + taskSource = Objects.assign({} as Tasks.WorkspaceTaskSource, partialSource, { kind: Tasks.TaskSourceKind.Workspace, config: configElement }); + break; + } + } let result: Tasks.ConfiguringTask = new Tasks.ConfiguringTask( `${typeDeclaration.extensionId}.${taskIdentifier._key}`, - Objects.assign({} as Tasks.WorkspaceTaskSource, source, { config: configElement }), + taskSource, undefined, type, taskIdentifier, @@ -1419,7 +1460,7 @@ namespace ConfiguringTask { } namespace CustomTask { - export function from(this: void, external: CustomTask, context: ParseContext, index: number): Tasks.CustomTask | undefined { + export function from(this: void, external: CustomTask, context: ParseContext, index: number, source: TaskConfigSource): Tasks.CustomTask | undefined { if (!external) { return undefined; } @@ -1440,9 +1481,25 @@ namespace CustomTask { return undefined; } + let taskSource: Tasks.FileBasedTaskSource; + switch (source) { + case TaskConfigSource.User: { + taskSource = Objects.assign({} as Tasks.UserTaskSource, partialSource, { kind: Tasks.TaskSourceKind.User, config: { index, element: external, file: '.vscode/tasks.json', workspaceFolder: context.workspaceFolder } }); + break; + } + case TaskConfigSource.WorkspaceFile: { + taskSource = Objects.assign({} as Tasks.WorkspaceFileTaskSource, partialSource, { kind: Tasks.TaskSourceKind.WorkspaceFile, config: { index, element: external, file: '.vscode/tasks.json', workspaceFolder: context.workspaceFolder, workspace: context.workspace } }); + break; + } + default: { + taskSource = Objects.assign({} as Tasks.WorkspaceTaskSource, partialSource, { kind: Tasks.TaskSourceKind.Workspace, config: { index, element: external, file: '.vscode/tasks.json', workspaceFolder: context.workspaceFolder } }); + break; + } + } + let result: Tasks.CustomTask = new Tasks.CustomTask( context.uuidMap.getUUID(taskName), - Objects.assign({} as Tasks.WorkspaceTaskSource, source, { config: { index, element: external, file: '.vscode/tasks.json', workspaceFolder: context.workspaceFolder } }), + taskSource, taskName, Tasks.CUSTOMIZED_TASK_TYPE, undefined, @@ -1538,6 +1595,7 @@ namespace CustomTask { assignProperty(resultConfigProps, configuredProps.configurationProperties, 'dependsOn'); assignProperty(resultConfigProps, configuredProps.configurationProperties, 'problemMatchers'); assignProperty(resultConfigProps, configuredProps.configurationProperties, 'promptOnClose'); + assignProperty(resultConfigProps, configuredProps.configurationProperties, 'detail'); result.command.presentation = CommandConfiguration.PresentationOptions.assignProperties( result.command.presentation!, configuredProps.configurationProperties.presentation)!; result.command.options = CommandOptions.assignProperties(result.command.options, configuredProps.configurationProperties.options); @@ -1549,6 +1607,7 @@ namespace CustomTask { fillProperty(resultConfigProps, contributedConfigProps, 'dependsOn'); fillProperty(resultConfigProps, contributedConfigProps, 'problemMatchers'); fillProperty(resultConfigProps, contributedConfigProps, 'promptOnClose'); + fillProperty(resultConfigProps, contributedConfigProps, 'detail'); result.command.presentation = CommandConfiguration.PresentationOptions.fillProperties( result.command.presentation!, contributedConfigProps.presentation)!; result.command.options = CommandOptions.fillProperties(result.command.options, contributedConfigProps.options); @@ -1574,7 +1633,7 @@ namespace TaskParser { return customize === undefined && (type === undefined || type === null || type === Tasks.CUSTOMIZED_TASK_TYPE || type === 'shell' || type === 'process'); } - export function from(this: void, externals: Array | undefined, globals: Globals, context: ParseContext): TaskParseResult { + export function from(this: void, externals: Array | undefined, globals: Globals, context: ParseContext, source: TaskConfigSource): TaskParseResult { let result: TaskParseResult = { custom: [], configured: [] }; if (!externals) { return result; @@ -1586,7 +1645,7 @@ namespace TaskParser { for (let index = 0; index < externals.length; index++) { let external = externals[index]; if (isCustomTask(external)) { - let customTask = CustomTask.from(external, context, index); + let customTask = CustomTask.from(external, context, index, source); if (customTask) { CustomTask.fillGlobals(customTask, globals); CustomTask.fillDefaults(customTask, context); @@ -1624,7 +1683,7 @@ namespace TaskParser { result.custom.push(customTask); } } else { - let configuredTask = ConfiguringTask.from(external, context, index); + let configuredTask = ConfiguringTask.from(external, context, index, source); if (configuredTask) { configuredTask.addTaskLoadMessages(context.taskLoadIssues); result.configured.push(configuredTask); @@ -1872,25 +1931,34 @@ class UUIDMap { } } +export enum TaskConfigSource { + TasksJson, + WorkspaceFile, + User +} + class ConfigurationParser { private workspaceFolder: IWorkspaceFolder; + private workspace: IWorkspace | undefined; private problemReporter: IProblemReporter; private uuidMap: UUIDMap; private platform: Platform; - constructor(workspaceFolder: IWorkspaceFolder, platform: Platform, problemReporter: IProblemReporter, uuidMap: UUIDMap) { + constructor(workspaceFolder: IWorkspaceFolder, workspace: IWorkspace | undefined, platform: Platform, problemReporter: IProblemReporter, uuidMap: UUIDMap) { this.workspaceFolder = workspaceFolder; + this.workspace = workspace; this.platform = platform; this.problemReporter = problemReporter; this.uuidMap = uuidMap; } - public run(fileConfig: ExternalTaskRunnerConfiguration): ParseResult { + public run(fileConfig: ExternalTaskRunnerConfiguration, source: TaskConfigSource): ParseResult { let engine = ExecutionEngine.from(fileConfig); let schemaVersion = JsonSchemaVersion.from(fileConfig); let context: ParseContext = { workspaceFolder: this.workspaceFolder, + workspace: this.workspace, problemReporter: this.problemReporter, uuidMap: this.uuidMap, namedProblemMatchers: {}, @@ -1899,7 +1967,7 @@ class ConfigurationParser { platform: this.platform, taskLoadIssues: [] }; - let taskParseResult = this.createTaskRunnerConfiguration(fileConfig, context); + let taskParseResult = this.createTaskRunnerConfiguration(fileConfig, context, source); return { validationStatus: this.problemReporter.status, custom: taskParseResult.custom, @@ -1908,7 +1976,7 @@ class ConfigurationParser { }; } - private createTaskRunnerConfiguration(fileConfig: ExternalTaskRunnerConfiguration, context: ParseContext): TaskParseResult { + private createTaskRunnerConfiguration(fileConfig: ExternalTaskRunnerConfiguration, context: ParseContext, source: TaskConfigSource): TaskParseResult { let globals = Globals.from(fileConfig, context); if (this.problemReporter.status.isFatal()) { return { custom: [], configured: [] }; @@ -1917,13 +1985,13 @@ class ConfigurationParser { let globalTasks: Tasks.CustomTask[] | undefined = undefined; let externalGlobalTasks: Array | undefined = undefined; if (fileConfig.windows && context.platform === Platform.Windows) { - globalTasks = TaskParser.from(fileConfig.windows.tasks, globals, context).custom; + globalTasks = TaskParser.from(fileConfig.windows.tasks, globals, context, source).custom; externalGlobalTasks = fileConfig.windows.tasks; } else if (fileConfig.osx && context.platform === Platform.Mac) { - globalTasks = TaskParser.from(fileConfig.osx.tasks, globals, context).custom; + globalTasks = TaskParser.from(fileConfig.osx.tasks, globals, context, source).custom; externalGlobalTasks = fileConfig.osx.tasks; } else if (fileConfig.linux && context.platform === Platform.Linux) { - globalTasks = TaskParser.from(fileConfig.linux.tasks, globals, context).custom; + globalTasks = TaskParser.from(fileConfig.linux.tasks, globals, context, source).custom; externalGlobalTasks = fileConfig.linux.tasks; } if (context.schemaVersion === Tasks.JsonSchemaVersion.V2_0_0 && globalTasks && globalTasks.length > 0 && externalGlobalTasks && externalGlobalTasks.length > 0) { @@ -1940,7 +2008,7 @@ class ConfigurationParser { let result: TaskParseResult = { custom: [], configured: [] }; if (fileConfig.tasks) { - result = TaskParser.from(fileConfig.tasks, globals, context); + result = TaskParser.from(fileConfig.tasks, globals, context, source); } if (globalTasks) { result.custom = TaskParser.assignTasks(result.custom, globalTasks); @@ -1989,7 +2057,7 @@ class ConfigurationParser { } let uuidMaps: Map = new Map(); -export function parse(workspaceFolder: IWorkspaceFolder, platform: Platform, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult { +export function parse(workspaceFolder: IWorkspaceFolder, workspace: IWorkspace | undefined, platform: Platform, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter, source: TaskConfigSource): ParseResult { let uuidMap = uuidMaps.get(workspaceFolder.uri.toString()); if (!uuidMap) { uuidMap = new UUIDMap(); @@ -1997,7 +2065,7 @@ export function parse(workspaceFolder: IWorkspaceFolder, platform: Platform, con } try { uuidMap.start(); - return (new ConfigurationParser(workspaceFolder, platform, logger, uuidMap)).run(configuration); + return (new ConfigurationParser(workspaceFolder, workspace, platform, logger, uuidMap)).run(configuration, source); } finally { uuidMap.finish(); } @@ -2007,80 +2075,3 @@ export function createCustomTask(contributedTask: Tasks.ContributedTask, configu return CustomTask.createCustomTask(contributedTask, configuredProps); } -/* -class VersionConverter { - constructor(private problemReporter: IProblemReporter) { - } - - public convert(fromConfig: ExternalTaskRunnerConfiguration): ExternalTaskRunnerConfiguration { - let result: ExternalTaskRunnerConfiguration; - result.version = '2.0.0'; - if (Array.isArray(fromConfig.tasks)) { - - } else { - result.tasks = []; - } - - - return result; - } - - private convertGlobalTask(fromConfig: ExternalTaskRunnerConfiguration): TaskDescription { - let command: string = this.getGlobalCommand(fromConfig); - if (!command) { - this.problemReporter.error(nls.localize('Converter.noGlobalName', 'No global command specified. Can\'t convert to 2.0.0 version.')); - return undefined; - } - let result: TaskDescription = { - taskName: command - }; - if (fromConfig.isShellCommand) { - result.type = 'shell'; - } else { - result.type = 'process'; - result.args = fromConfig.args; - } - if (fromConfig.) - - return result; - } - - private getGlobalCommand(fromConfig: ExternalTaskRunnerConfiguration): string { - if (fromConfig.command) { - return fromConfig.command; - } else if (fromConfig.windows && fromConfig.windows.command) { - return fromConfig.windows.command; - } else if (fromConfig.osx && fromConfig.osx.command) { - return fromConfig.osx.command; - } else if (fromConfig.linux && fromConfig.linux.command) { - return fromConfig.linux.command; - } else { - return undefined; - } - } - - private createCommandLine(command: string, args: string[], isWindows: boolean): string { - let result: string[]; - let commandHasSpace = false; - let argHasSpace = false; - if (TaskDescription.hasUnescapedSpaces(command)) { - result.push(`"${command}"`); - commandHasSpace = true; - } else { - result.push(command); - } - if (args) { - for (let arg of args) { - if (TaskDescription.hasUnescapedSpaces(arg)) { - result.push(`"${arg}"`); - argHasSpace= true; - } else { - result.push(arg); - } - } - } - return result.join(' '); - } - -} -*/ diff --git a/src/vs/workbench/contrib/tasks/common/taskService.ts b/src/vs/workbench/contrib/tasks/common/taskService.ts index a8005416329..374c2e6141d 100644 --- a/src/vs/workbench/contrib/tasks/common/taskService.ts +++ b/src/vs/workbench/contrib/tasks/common/taskService.ts @@ -9,7 +9,7 @@ import { LinkedMap } from 'vs/base/common/map'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { Task, ContributedTask, CustomTask, TaskSet, TaskSorter, TaskEvent, TaskIdentifier, ConfiguringTask, TaskRunSource } from 'vs/workbench/contrib/tasks/common/tasks'; import { ITaskSummary, TaskTerminateResponse, TaskSystemInfo } from 'vs/workbench/contrib/tasks/common/taskSystem'; import { IStringDictionary } from 'vs/base/common/collections'; @@ -62,6 +62,7 @@ export interface ITaskService { inTerminal(): boolean; isActive(): Promise; getActiveTasks(): Promise; + getBusyTasks(): Promise; restart(task: Task): void; terminate(task: Task): Promise; terminateAll(): Promise; @@ -70,7 +71,7 @@ export interface ITaskService { /** * @param alias The task's name, label or defined identifier. */ - getTask(workspaceFolder: IWorkspaceFolder | string, alias: string | TaskIdentifier, compareId?: boolean): Promise; + getTask(workspaceFolder: IWorkspace | IWorkspaceFolder | string, alias: string | TaskIdentifier, compareId?: boolean): Promise; getTasksForGroup(group: string): Promise; getRecentlyUsedTasks(): LinkedMap; createSorter(): TaskSorter; diff --git a/src/vs/workbench/contrib/tasks/common/taskSystem.ts b/src/vs/workbench/contrib/tasks/common/taskSystem.ts index c844be5ec26..887c3f288bf 100644 --- a/src/vs/workbench/contrib/tasks/common/taskSystem.ts +++ b/src/vs/workbench/contrib/tasks/common/taskSystem.ts @@ -93,7 +93,7 @@ export interface ITaskExecuteResult { } export interface ITaskResolver { - resolve(workspaceFolder: IWorkspaceFolder, identifier: string | KeyedTaskIdentifier | undefined): Task | undefined; + resolve(uri: URI, identifier: string | KeyedTaskIdentifier | undefined): Task | undefined; } export interface TaskTerminateResponse extends TerminateResponse { @@ -133,6 +133,7 @@ export interface ITaskSystem { isActive(): Promise; isActiveSync(): boolean; getActiveTasks(): Task[]; + getBusyTasks(): Task[]; canAutoTerminate(): boolean; terminate(task: Task): Promise; terminateAll(): Promise; diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 24d77f427d7..6cde38187b1 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -5,12 +5,13 @@ import * as nls from 'vs/nls'; import * as Types from 'vs/base/common/types'; +import * as resources from 'vs/base/common/resources'; import { IJSONSchemaMap } from 'vs/base/common/jsonSchema'; import * as Objects from 'vs/base/common/objects'; -import { UriComponents } from 'vs/base/common/uri'; +import { UriComponents, URI } from 'vs/base/common/uri'; import { ProblemMatcher } from 'vs/workbench/contrib/tasks/common/problemMatcher'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; @@ -273,7 +274,7 @@ export namespace PresentationOptions { export enum RuntimeType { Shell = 1, Process = 2, - CustomExecution2 = 3 + CustomExecution = 3 } export namespace RuntimeType { @@ -283,8 +284,8 @@ export namespace RuntimeType { return RuntimeType.Shell; case 'process': return RuntimeType.Process; - case 'customExecution2': - return RuntimeType.CustomExecution2; + case 'customExecution': + return RuntimeType.CustomExecution; default: return RuntimeType.Process; } @@ -374,10 +375,13 @@ export namespace TaskSourceKind { export const Workspace: 'workspace' = 'workspace'; export const Extension: 'extension' = 'extension'; export const InMemory: 'inMemory' = 'inMemory'; + export const WorkspaceFile: 'workspaceFile' = 'workspaceFile'; + export const User: 'user' = 'user'; } export interface TaskSourceConfigElement { - workspaceFolder: IWorkspaceFolder; + workspaceFolder?: IWorkspaceFolder; + workspace?: IWorkspace; file: string; index: number; element: any; @@ -410,8 +414,20 @@ export interface InMemoryTaskSource extends BaseTaskSource { readonly kind: 'inMemory'; } -export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | InMemoryTaskSource; +export interface UserTaskSource extends BaseTaskSource { + readonly kind: 'user'; + readonly config: TaskSourceConfigElement; + readonly customizes?: KeyedTaskIdentifier; +} +export interface WorkspaceFileTaskSource extends BaseTaskSource { + readonly kind: 'workspaceFile'; + readonly config: TaskSourceConfigElement; + readonly customizes?: KeyedTaskIdentifier; +} + +export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | InMemoryTaskSource | UserTaskSource | WorkspaceFileTaskSource; +export type FileBasedTaskSource = WorkspaceTaskSource | UserTaskSource | WorkspaceFileTaskSource; export interface TaskIdentifier { type: string; [name: string]: any; @@ -422,7 +438,7 @@ export interface KeyedTaskIdentifier extends TaskIdentifier { } export interface TaskDependency { - workspaceFolder: IWorkspaceFolder; + uri: URI; task: string | KeyedTaskIdentifier | undefined; } @@ -488,6 +504,11 @@ export interface ConfigurationProperties { */ dependsOrder?: DependsOrder; + /** + * A description of the task. + */ + detail?: string; + /** * The problem watchers to use for this task */ @@ -566,6 +587,10 @@ export abstract class CommonTask { return undefined; } + public getWorkspaceFileName(): string | undefined { + return undefined; + } + public getTelemetryKind(): string { return 'unknown'; } @@ -619,7 +644,7 @@ export class CustomTask extends CommonTask { /** * Indicated the source of the task (e.g. tasks.json or extension) */ - _source: WorkspaceTaskSource; + _source: FileBasedTaskSource; hasDefinedMatchers: boolean; @@ -628,7 +653,7 @@ export class CustomTask extends CommonTask { */ command: CommandConfiguration = {}; - public constructor(id: string, source: WorkspaceTaskSource, label: string, type: string, command: CommandConfiguration | undefined, + public constructor(id: string, source: FileBasedTaskSource, label: string, type: string, command: CommandConfiguration | undefined, hasDefinedMatchers: boolean, runOptions: RunOptions, configurationProperties: ConfigurationProperties) { super(id, label, undefined, runOptions, configurationProperties, source); this._source = source; @@ -660,8 +685,8 @@ export class CustomTask extends CommonTask { type = 'process'; break; - case RuntimeType.CustomExecution2: - type = 'customExecution2'; + case RuntimeType.CustomExecution: + type = 'customExecution'; break; case undefined: @@ -700,14 +725,22 @@ export class CustomTask extends CommonTask { if (!workspaceFolder) { return undefined; } - let key: CustomKey = { type: CUSTOMIZED_TASK_TYPE, folder: workspaceFolder.uri.toString(), id: this.configurationProperties.identifier! }; + let id: string = this.configurationProperties.identifier!; + if (this._source.kind !== TaskSourceKind.Workspace) { + id += this._source.kind; + } + let key: CustomKey = { type: CUSTOMIZED_TASK_TYPE, folder: workspaceFolder.uri.toString(), id }; return JSON.stringify(key); } - public getWorkspaceFolder(): IWorkspaceFolder { + public getWorkspaceFolder(): IWorkspaceFolder | undefined { return this._source.config.workspaceFolder; } + public getWorkspaceFileName(): string | undefined { + return (this._source.config.workspace && this._source.config.workspace.configuration) ? resources.basename(this._source.config.workspace.configuration) : undefined; + } + public getTelemetryKind(): string { if (this._source.customizes) { return 'workspace>extension'; @@ -726,11 +759,11 @@ export class ConfiguringTask extends CommonTask { /** * Indicated the source of the task (e.g. tasks.json or extension) */ - _source: WorkspaceTaskSource; + _source: FileBasedTaskSource; configures: KeyedTaskIdentifier; - public constructor(id: string, source: WorkspaceTaskSource, label: string | undefined, type: string | undefined, + public constructor(id: string, source: FileBasedTaskSource, label: string | undefined, type: string | undefined, configures: KeyedTaskIdentifier, runOptions: RunOptions, configurationProperties: ConfigurationProperties) { super(id, label, type, runOptions, configurationProperties, source); this._source = source; @@ -748,6 +781,10 @@ export class ConfiguringTask extends CommonTask { public getDefinition(): KeyedTaskIdentifier { return this.configures; } + + public getWorkspaceFileName(): string | undefined { + return (this._source.config.workspace && this._source.config.workspace.configuration) ? resources.basename(this._source.config.workspace.configuration) : undefined; + } } export class ContributedTask extends CommonTask { diff --git a/src/vs/workbench/contrib/tasks/node/processTaskSystem.ts b/src/vs/workbench/contrib/tasks/node/processTaskSystem.ts index 8110db9d80c..ba3adbd5a48 100644 --- a/src/vs/workbench/contrib/tasks/node/processTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/node/processTaskSystem.ts @@ -90,6 +90,10 @@ export class ProcessTaskSystem implements ITaskSystem { return result; } + public getBusyTasks(): Task[] { + return this.getActiveTasks(); + } + public run(task: Task): ITaskExecuteResult { if (this.activeTask) { return { kind: TaskExecuteKind.Active, task, active: { same: this.activeTask._id === task._id, background: this.activeTask.configurationProperties.isBackground! }, promise: this.activeTaskPromise! }; diff --git a/src/vs/workbench/contrib/tasks/test/electron-browser/configuration.test.ts b/src/vs/workbench/contrib/tasks/test/electron-browser/configuration.test.ts index 9a81fcf9441..2564323b1c4 100644 --- a/src/vs/workbench/contrib/tasks/test/electron-browser/configuration.test.ts +++ b/src/vs/workbench/contrib/tasks/test/electron-browser/configuration.test.ts @@ -10,17 +10,19 @@ import * as UUID from 'vs/base/common/uuid'; import * as Platform from 'vs/base/common/platform'; import { ValidationStatus } from 'vs/base/common/parsers'; import { ProblemMatcher, FileLocationKind, ProblemPattern, ApplyToKind } from 'vs/workbench/contrib/tasks/common/problemMatcher'; -import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { WorkspaceFolder, Workspace, IWorkspace } from 'vs/platform/workspace/common/workspace'; import * as Tasks from 'vs/workbench/contrib/tasks/common/tasks'; -import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask } from 'vs/workbench/contrib/tasks/common/taskConfiguration'; +import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask, TaskConfigSource } from 'vs/workbench/contrib/tasks/common/taskConfiguration'; -const workspaceFolder: IWorkspaceFolder = new WorkspaceFolder({ +const workspaceFolder: WorkspaceFolder = new WorkspaceFolder({ uri: URI.file('/workspace/folderOne'), name: 'folderOne', index: 0 }); +const workspace: IWorkspace = new Workspace('id', [workspaceFolder]); + class ProblemReporter implements IProblemReporter { private _validationStatus: ValidationStatus = new ValidationStatus(); @@ -357,7 +359,7 @@ class PatternBuilder { function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, resolved: number) { let reporter = new ProblemReporter(); - let result = parse(workspaceFolder, Platform.platform, external, reporter); + let result = parse(workspaceFolder, workspace, Platform.platform, external, reporter, TaskConfigSource.TasksJson); assert.ok(!reporter.receivedMessage); assert.strictEqual(result.custom.length, 1); let task = result.custom[0]; @@ -368,7 +370,7 @@ function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, re function testConfiguration(external: ExternalTaskRunnerConfiguration, builder: ConfiguationBuilder): void { builder.done(); let reporter = new ProblemReporter(); - let result = parse(workspaceFolder, Platform.platform, external, reporter); + let result = parse(workspaceFolder, workspace, Platform.platform, external, reporter, TaskConfigSource.TasksJson); if (reporter.receivedMessage) { assert.ok(false, reporter.lastMessage); } @@ -1730,4 +1732,4 @@ suite('Bugs / regression tests', () => { runtime(Tasks.RuntimeType.Shell); testConfiguration(external, builder); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon.ts b/src/vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon.ts index 3c4069967ba..a0b892a1fc0 100644 --- a/src/vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon.ts @@ -64,7 +64,15 @@ export class CommandTrackerAddon implements ICommandTracker, ITerminalAddon { } let markerIndex; - if (this._currentMarker === Boundary.Bottom) { + const currentLineY = Math.min(this._getLine(this._terminal, this._currentMarker), this._terminal.buffer.baseY); + const viewportY = this._terminal.buffer.viewportY; + if (!retainSelection && currentLineY !== viewportY) { + // The user has scrolled, find the line based on the current scroll position. This only + // works when not retaining selection + const markersBelowViewport = this._terminal.markers.filter(e => e.line >= viewportY).length; + // -1 will scroll to the top + markerIndex = this._terminal.markers.length - markersBelowViewport - 1; + } else if (this._currentMarker === Boundary.Bottom) { markerIndex = this._terminal.markers.length - 1; } else if (this._currentMarker === Boundary.Top) { markerIndex = -1; @@ -95,7 +103,15 @@ export class CommandTrackerAddon implements ICommandTracker, ITerminalAddon { } let markerIndex; - if (this._currentMarker === Boundary.Bottom) { + const currentLineY = Math.min(this._getLine(this._terminal, this._currentMarker), this._terminal.buffer.baseY); + const viewportY = this._terminal.buffer.viewportY; + if (!retainSelection && currentLineY !== viewportY) { + // The user has scrolled, find the line based on the current scroll position. This only + // works when not retaining selection + const markersAboveViewport = this._terminal.markers.filter(e => e.line <= viewportY).length; + // markers.length will scroll to the bottom + markerIndex = markersAboveViewport; + } else if (this._currentMarker === Boundary.Bottom) { markerIndex = this._terminal.markers.length; } else if (this._currentMarker === Boundary.Top) { markerIndex = 0; diff --git a/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts b/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts index 6997a4dbef1..f164db48fb9 100644 --- a/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts @@ -30,7 +30,7 @@ export class NavigationModeAddon implements INavigationMode, ITerminalAddon { } focusPreviousLine(): void { - if (!this._terminal) { + if (!this._terminal || !this._terminal.element) { return; } @@ -73,7 +73,7 @@ export class NavigationModeAddon implements INavigationMode, ITerminalAddon { } focusNextLine(): void { - if (!this._terminal) { + if (!this._terminal || !this._terminal.element) { return; } diff --git a/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css b/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css index 0d28e3564d1..8dcbaa4a4ef 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css +++ b/src/vs/workbench/contrib/terminal/browser/media/scrollbar.css @@ -38,4 +38,4 @@ .monaco-workbench .panel.integrated-terminal .xterm .xterm-viewport::-webkit-scrollbar-thumb:window-inactive { background-color: inherit; -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index d50dd4b9253..b47f72fdf8c 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -10,6 +10,7 @@ flex-direction: column; background-color: transparent!important; user-select: initial; + -webkit-user-select: initial; position: relative; } @@ -104,6 +105,7 @@ bottom: 0; left: 0; user-select: none; + -webkit-user-select: none; } .monaco-workbench .panel.integrated-terminal .monaco-split-view2.vertical .split-view-view:not(:last-child) .xterm { /* When vertical and NOT the bottom terminal, align to the top instead to prevent the output jumping around erratically */ diff --git a/src/vs/workbench/contrib/terminal/browser/media/xterm.css b/src/vs/workbench/contrib/terminal/browser/media/xterm.css index bde4034f5b8..712baa284f6 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/xterm.css +++ b/src/vs/workbench/contrib/terminal/browser/media/xterm.css @@ -43,7 +43,6 @@ font-feature-settings: "liga" 0; position: relative; user-select: none; - -ms-user-select: none; -webkit-user-select: none; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index d2fd7eac30f..3dd05dcda53 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -219,10 +219,11 @@ configurationRegistry.registerConfiguration({ }, 'terminal.integrated.rightClickBehavior': { type: 'string', - enum: ['default', 'copyPaste', 'selectWord'], + enum: ['default', 'copyPaste', 'paste', 'selectWord'], enumDescriptions: [ nls.localize('terminal.integrated.rightClickBehavior.default', "Show the context menu."), nls.localize('terminal.integrated.rightClickBehavior.copyPaste', "Copy when there is a selection, otherwise paste."), + nls.localize('terminal.integrated.rightClickBehavior.paste', "Paste on right click."), nls.localize('terminal.integrated.rightClickBehavior.selectWord', "Select the word under the cursor and show the context menu.") ], default: platform.isMacintosh ? 'selectWord' : platform.isWindows ? 'copyPaste' : 'default', @@ -251,6 +252,11 @@ configurationRegistry.registerConfiguration({ }, default: [] }, + 'terminal.integrated.allowChords': { + markdownDescription: nls.localize('terminal.integrated.allowChords', "Whether or not to allow chord keybindings in the terminal. Note that when this is true and the keystroke results in a chord it will bypass `terminal.integrated.commandsToSkipShell`, setting this to false is particularly useful when you want ctrl+k to go to your shell (not VS Code)."), + type: 'boolean', + default: true + }, 'terminal.integrated.inheritEnv': { markdownDescription: nls.localize('terminal.integrated.inheritEnv', "Whether new shells should inherit their environment from VS Code. This is not supported on Windows."), type: 'boolean', @@ -310,6 +316,11 @@ configurationRegistry.registerConfiguration({ description: nls.localize('terminal.integrated.experimentalUseTitleEvent', "An experimental setting that will use the terminal title event for the dropdown title. This setting will only apply to new terminals."), type: 'boolean', default: false + }, + 'terminal.integrated.enableFileLinks': { + description: nls.localize('terminal.integrated.enableFileLinks', "Whether to enable file links in the terminal. Links can be slow when working on a network drive in particular because each file link is verified against the file system."), + type: 'boolean', + default: true } } }); @@ -351,9 +362,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextTermina actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V }, - // Don't apply to Mac since cmd+v works - mac: { primary: 0 } + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Paste into Active Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectAllTerminalAction, SelectAllTerminalAction.ID, SelectAllTerminalAction.LABEL, { // Don't use ctrl+a by default as that would override the common go to start @@ -510,28 +519,28 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEscapeSequ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID, ToggleRegexCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_R, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using regex'); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID_TERMINAL_FOCUS, ToggleRegexCommand.LABEL, { +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using regex', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRegexCommand, ToggleRegexCommand.ID, ToggleRegexCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_R, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find using regex', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID, ToggleWholeWordCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_W, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using whole word'); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID_TERMINAL_FOCUS, ToggleWholeWordCommand.LABEL, { +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using whole word', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWholeWordCommand, ToggleWholeWordCommand.ID, ToggleWholeWordCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_W, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find using whole word', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID, ToggleCaseSensitiveCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_C, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using case sensitive'); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID_TERMINAL_FOCUS, ToggleCaseSensitiveCommand.LABEL, { +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Toggle find using case sensitive', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCaseSensitiveCommand, ToggleCaseSensitiveCommand.ID, ToggleCaseSensitiveCommand.LABEL, { primary: KeyMod.Alt | KeyCode.KEY_C, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Toggle find using case sensitive', category); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID_TERMINAL_FOCUS, FindNext.LABEL, { +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, { primary: KeyCode.F3, mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category); @@ -539,8 +548,8 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNe primary: KeyCode.F3, secondary: [KeyMod.Shift | KeyCode.Enter], mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3, KeyMod.Shift | KeyCode.Enter] } -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next'); -actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID_TERMINAL_FOCUS, FindPrevious.LABEL, { +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, { primary: KeyMod.Shift | KeyCode.F3, mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] }, }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find previous', category); @@ -548,7 +557,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, Fi primary: KeyMod.Shift | KeyCode.F3, secondary: [KeyCode.Enter], mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3, KeyCode.Enter] }, -}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find previous'); +}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find previous', category); (new SendSequenceTerminalCommand({ id: SendSequenceTerminalCommand.ID, diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index f2600039f97..ddad1d88a75 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -10,7 +10,6 @@ import { IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShe import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment, Platform } from 'vs/base/common/platform'; import { Event } from 'vs/base/common/event'; -import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IDisposable } from 'vs/base/common/lifecycle'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { URI } from 'vs/base/common/uri'; @@ -65,7 +64,7 @@ export interface ITerminalTab { setVisible(visible: boolean): void; layout(width: number, height: number): void; addDisposable(disposable: IDisposable): void; - split(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance | undefined; + split(shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; } export interface ITerminalService { @@ -142,10 +141,10 @@ export interface ITerminalService { * @param path The path to be escaped and formatted. * @returns An escaped version of the path to be execuded in the terminal. */ - preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise; + preparePathForTerminalAsync(path: string, executable: string | undefined, title: string, shellType: TerminalShellType): Promise; extHostReady(remoteAuthority: string): void; - requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; } @@ -168,6 +167,14 @@ export interface ISearchOptions { incremental?: boolean; } +export enum WindowsShellType { + CommandPrompt, + PowerShell, + Wsl, + GitBash +} +export type TerminalShellType = WindowsShellType | undefined; + export interface ITerminalInstance { /** * The ID of the terminal instance, this is an arbitrary number only used to identify the @@ -227,7 +234,7 @@ export interface ITerminalInstance { * is the processes' exit code, an exit code of null means the process was killed as a result of * the ITerminalInstance being disposed. */ - onExit: Event; + onExit: Event; processReady: Promise; @@ -237,6 +244,11 @@ export interface ITerminalInstance { */ readonly title: string; + /** + * The shell type of the terminal. + */ + readonly shellType: TerminalShellType; + /** * The focus state of the terminal before exiting. */ @@ -432,6 +444,11 @@ export interface ITerminalInstance { */ setTitle(title: string, eventSource: TitleEventSource): void; + /** + * Sets the shell type of the terminal instance. + */ + setShellType(shellType: TerminalShellType): void; + waitForTitle(): Promise; setDimensions(dimensions: ITerminalDimensions): void; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 5c6c751e720..2971096e09d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -722,7 +722,7 @@ export class RunActiveFileInTerminalAction extends Action { return Promise.resolve(undefined); } - return this.terminalService.preparePathForTerminalAsync(uri.fsPath, instance.shellLaunchConfig.executable, instance.title).then(path => { + return this.terminalService.preparePathForTerminalAsync(uri.fsPath, instance.shellLaunchConfig.executable, instance.title, instance.shellType).then(path => { instance.sendText(path, true); return this.terminalService.showPanel(); }); @@ -1328,7 +1328,6 @@ abstract class ToggleFindOptionCommand extends Action { export class ToggleRegexCommand extends ToggleFindOptionCommand { public static readonly ID = TERMINAL_COMMAND_ID.TOGGLE_FIND_REGEX; - public static readonly ID_TERMINAL_FOCUS = TERMINAL_COMMAND_ID.TOGGLE_FIND_REGEX_TERMINAL_FOCUS; public static readonly LABEL = nls.localize('workbench.action.terminal.toggleFindRegex', "Toggle find using regex"); protected runInner(state: FindReplaceState): void { @@ -1338,7 +1337,6 @@ export class ToggleRegexCommand extends ToggleFindOptionCommand { export class ToggleWholeWordCommand extends ToggleFindOptionCommand { public static readonly ID = TERMINAL_COMMAND_ID.TOGGLE_FIND_WHOLE_WORD; - public static readonly ID_TERMINAL_FOCUS = TERMINAL_COMMAND_ID.TOGGLE_FIND_WHOLE_WORD_TERMINAL_FOCUS; public static readonly LABEL = nls.localize('workbench.action.terminal.toggleFindWholeWord', "Toggle find using whole word"); protected runInner(state: FindReplaceState): void { @@ -1348,7 +1346,6 @@ export class ToggleWholeWordCommand extends ToggleFindOptionCommand { export class ToggleCaseSensitiveCommand extends ToggleFindOptionCommand { public static readonly ID = TERMINAL_COMMAND_ID.TOGGLE_FIND_CASE_SENSITIVE; - public static readonly ID_TERMINAL_FOCUS = TERMINAL_COMMAND_ID.TOGGLE_FIND_CASE_SENSITIVE_TERMINAL_FOCUS; public static readonly LABEL = nls.localize('workbench.action.terminal.toggleFindCaseSensitive', "Toggle find using case sensitive"); protected runInner(state: FindReplaceState): void { @@ -1358,7 +1355,6 @@ export class ToggleCaseSensitiveCommand extends ToggleFindOptionCommand { export class FindNext extends Action { public static readonly ID = TERMINAL_COMMAND_ID.FIND_NEXT; - public static readonly ID_TERMINAL_FOCUS = TERMINAL_COMMAND_ID.FIND_NEXT_TERMINAL_FOCUS; public static readonly LABEL = nls.localize('workbench.action.terminal.findNext', "Find next"); constructor( @@ -1376,7 +1372,6 @@ export class FindNext extends Action { export class FindPrevious extends Action { public static readonly ID = TERMINAL_COMMAND_ID.FIND_PREVIOUS; - public static readonly ID_TERMINAL_FOCUS = TERMINAL_COMMAND_ID.FIND_PREVIOUS_TERMINAL_FOCUS; public static readonly LABEL = nls.localize('workbench.action.terminal.findPrevious', "Find previous"); constructor( diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index d3dde9111c4..373f4112535 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -25,19 +25,20 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; -import { IShellLaunchConfig, ITerminalDimensions, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalDimensions, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource, TERMINAL_COMMAND_ID, LEGACY_CONSOLE_MODE_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal'; import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; -import { ITerminalInstanceService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalInstanceService, ITerminalInstance, TerminalShellType } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; import { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm'; import { SearchAddon, ISearchOptions } from 'xterm-addon-search'; import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon'; import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon'; import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; +import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -53,11 +54,11 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ TERMINAL_COMMAND_ID.DELETE_WORD_RIGHT, TERMINAL_COMMAND_ID.FIND_WIDGET_FOCUS, TERMINAL_COMMAND_ID.FIND_WIDGET_HIDE, - TERMINAL_COMMAND_ID.FIND_NEXT_TERMINAL_FOCUS, - TERMINAL_COMMAND_ID.FIND_PREVIOUS_TERMINAL_FOCUS, - TERMINAL_COMMAND_ID.TOGGLE_FIND_REGEX_TERMINAL_FOCUS, - TERMINAL_COMMAND_ID.TOGGLE_FIND_WHOLE_WORD_TERMINAL_FOCUS, - TERMINAL_COMMAND_ID.TOGGLE_FIND_CASE_SENSITIVE_TERMINAL_FOCUS, + TERMINAL_COMMAND_ID.FIND_NEXT, + TERMINAL_COMMAND_ID.FIND_PREVIOUS, + TERMINAL_COMMAND_ID.TOGGLE_FIND_REGEX, + TERMINAL_COMMAND_ID.TOGGLE_FIND_WHOLE_WORD, + TERMINAL_COMMAND_ID.TOGGLE_FIND_CASE_SENSITIVE, TERMINAL_COMMAND_ID.FOCUS_NEXT_PANE, TERMINAL_COMMAND_ID.FOCUS_NEXT, TERMINAL_COMMAND_ID.FOCUS_PREVIOUS_PANE, @@ -181,6 +182,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _isVisible: boolean; private _isDisposed: boolean; private _skipTerminalCommands: string[]; + private _shellType: TerminalShellType; private _title: string = ''; private _wrapperElement: (HTMLElement & { xterm?: XTermTerminal }) | undefined; private _xterm: XTermTerminal | undefined; @@ -229,11 +231,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { public get hadFocusOnExit(): boolean { return this._hadFocusOnExit; } public get isTitleSetByProcess(): boolean { return !!this._messageTitleDisposable; } public get shellLaunchConfig(): IShellLaunchConfig { return this._shellLaunchConfig; } + public get shellType(): TerminalShellType { return this._shellType; } public get commandTracker(): CommandTrackerAddon | undefined { return this._commandTrackerAddon; } public get navigationMode(): INavigationMode | undefined { return this._navigationModeAddon; } - private readonly _onExit = new Emitter(); - public get onExit(): Event { return this._onExit.event; } + private readonly _onExit = new Emitter(); + public get onExit(): Event { return this._onExit.event; } private readonly _onDisposed = new Emitter(); public get onDisposed(): Event { return this._onDisposed.event; } private readonly _onFocused = new Emitter(); @@ -258,7 +261,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { public constructor( private readonly _terminalFocusContextKey: IContextKey, private readonly _configHelper: TerminalConfigHelper, - private _container: HTMLElement, + private _container: HTMLElement | undefined, private _shellLaunchConfig: IShellLaunchConfig, @ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService, @IContextKeyService private readonly _contextKeyService: IContextKeyService, @@ -304,7 +307,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { }); this.addDisposable(this._configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('terminal.integrated')) { + if (e.affectsConfiguration('terminal.integrated') || e.affectsConfiguration('editor.fastScrollSensitivity') || e.affectsConfiguration('editor.mouseWheelScrollSensitivity')) { this.updateConfig(); // HACK: Trigger another async layout to ensure xterm's CharMeasure is ready to use, // this hack can be removed when https://github.com/xtermjs/xterm.js/issues/702 is @@ -408,14 +411,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // The panel is minimized if (!this._isVisible) { return TerminalInstance._lastKnownCanvasDimensions; - } else { - // Trigger scroll event manually so that the viewport's scroll area is synced. This - // needs to happen otherwise its scrollTop value is invalid when the panel is toggled as - // it gets removed and then added back to the DOM (resetting scrollTop to 0). - // Upstream issue: https://github.com/sourcelair/xterm.js/issues/291 - if (this._xterm && this._xtermCore) { - this._xtermCore._onScroll.fire(this._xterm.buffer.viewportY); - } } if (!this._wrapperElement) { @@ -428,7 +423,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { const bottom = parseInt(wrapperElementStyle.bottom!.split('px')[0], 10); const innerWidth = width - marginLeft - marginRight; - const innerHeight = height - bottom; + const innerHeight = height - bottom - 1; TerminalInstance._lastKnownCanvasDimensions = new dom.Dimension(innerWidth, innerHeight); return TerminalInstance._lastKnownCanvasDimensions; @@ -455,6 +450,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { const Terminal = await this._getXtermConstructor(); const font = this._configHelper.getFont(undefined, true); const config = this._configHelper.config; + const editorOptions = this._configurationService.getValue('editor'); + const xterm = new Terminal({ scrollback: config.scrollback, theme: this._getXtermTheme(), @@ -469,7 +466,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { macOptionIsMeta: config.macOptionIsMeta, macOptionClickForcesSelection: config.macOptionClickForcesSelection, rightClickSelectsWord: config.rightClickBehavior === 'selectWord', - // TODO: Guess whether to use canvas or dom better + fastScrollModifier: 'alt', + fastScrollSensitivity: editorOptions.fastScrollSensitivity, + scrollSensitivity: editorOptions.mouseWheelScrollSensitivity, rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType }); this._xterm = xterm; @@ -488,7 +487,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._processManager.onProcessData(data => this._onProcessData(data)); this._xterm.onData(data => this._processManager.write(data)); - // TODO: How does the cwd work on detached processes? this.processReady.then(async () => { if (this._linkHandler) { this._linkHandler.processCwd = await this._processManager.getInitialCwd(); @@ -507,7 +505,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return false; }); } - this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, this._processManager, this._configHelper); + this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, xterm, this._processManager, this._configHelper); }); this._commandTrackerAddon = new CommandTrackerAddon(); @@ -528,9 +526,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { throw new Error('The terminal instance has not been attached to a container yet'); } - if (this._wrapperElement.parentNode) { - this._wrapperElement.parentNode.removeChild(this._wrapperElement); - } + this._wrapperElement.parentNode?.removeChild(this._wrapperElement); this._container = container; this._container.appendChild(this._wrapperElement); } @@ -548,7 +544,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } // The container changed, reattach - this._container.removeChild(this._wrapperElement); + this._container?.removeChild(this._wrapperElement); this._container = container; this._container.appendChild(this._wrapperElement); } @@ -567,7 +563,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Attach the xterm object to the DOM, exposing it to the smoke tests this._wrapperElement.xterm = this._xterm; + this._wrapperElement.appendChild(this._xtermElement); + this._container.appendChild(this._wrapperElement); xterm.open(this._xtermElement); + + if (!xterm.element || !xterm.textarea) { + throw new Error('xterm elements not set after open'); + } + xterm.textarea.addEventListener('focus', () => this._onFocus.fire(this)); xterm.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => { // Disable all input if the terminal is exiting @@ -579,7 +582,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // within commandsToSkipShell const standardKeyboardEvent = new StandardKeyboardEvent(event); const resolveResult = this._keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); - if (resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { + const allowChords = resolveResult && resolveResult.enterChord && this._configHelper.config.allowChords; + if (allowChords || resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { event.preventDefault(); return false; } @@ -644,16 +648,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._refreshSelectionContextKey(); })); - this._wrapperElement.appendChild(this._xtermElement); - this._container.appendChild(this._wrapperElement); - const widgetManager = new TerminalWidgetManager(this._wrapperElement); this._widgetManager = widgetManager; - this._processManager.onProcessReady(() => { - if (this._linkHandler) { - this._linkHandler.setWidgetManager(widgetManager); - } - }); + this._processManager.onProcessReady(() => this._linkHandler?.setWidgetManager(widgetManager)); const computedStyle = window.getComputedStyle(this._container); const width = parseInt(computedStyle.getPropertyValue('width').replace('px', ''), 10); @@ -748,19 +745,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } public clearSelection(): void { - if (!this._xterm) { - return; - } - this._xterm.clearSelection(); + this._xterm?.clearSelection(); } public selectAll(): void { - if (!this._xterm) { - return; - } // Focus here to ensure the terminal context key is set - this._xterm.focus(); - this._xterm.selectAll(); + this._xterm?.focus(); + this._xterm?.selectAll(); } public findNext(term: string, searchOptions: ISearchOptions): boolean { @@ -801,7 +792,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this._wrapperElement.xterm) { this._wrapperElement.xterm = undefined; } - if (this._wrapperElement.parentElement) { + if (this._wrapperElement.parentElement && this._container) { this._container.removeChild(this._wrapperElement); } } @@ -900,6 +891,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // necessary if the number of rows in the terminal has decreased while it was in the // background since scrollTop changes take no effect but the terminal's position does // change since the number of visible rows decreases. + // This can likely be removed after https://github.com/xtermjs/xterm.js/issues/291 is + // fixed upstream. this._xtermCore._onScroll.fire(this._xterm.buffer.viewportY); if (this._container && this._container.parentElement) { // Force a layout when the instance becomes invisible. This is particularly important @@ -919,45 +912,31 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } public scrollDownLine(): void { - if (this._xterm) { - this._xterm.scrollLines(1); - } + this._xterm?.scrollLines(1); } public scrollDownPage(): void { - if (this._xterm) { - this._xterm.scrollPages(1); - } + this._xterm?.scrollPages(1); } public scrollToBottom(): void { - if (this._xterm) { - this._xterm.scrollToBottom(); - } + this._xterm?.scrollToBottom(); } public scrollUpLine(): void { - if (this._xterm) { - this._xterm.scrollLines(-1); - } + this._xterm?.scrollLines(-1); } public scrollUpPage(): void { - if (this._xterm) { - this._xterm.scrollPages(-1); - } + this._xterm?.scrollPages(-1); } public scrollToTop(): void { - if (this._xterm) { - this._xterm.scrollToTop(); - } + this._xterm?.scrollToTop(); } public clear(): void { - if (this._xterm) { - this._xterm.clear(); - } + this._xterm?.clear(); } private _refreshSelectionContextKey() { @@ -1014,12 +993,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } private _onProcessData(data: string): void { - if (this._widgetManager) { - this._widgetManager.closeMessage(); - } - if (this._xterm) { - this._xterm.write(data); - } + this._widgetManager?.closeMessage(); + this._xterm?.write(data); } /** @@ -1047,6 +1022,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { exitCodeMessage = nls.localize('terminal.integrated.exitedWithInvalidPathDirectory', 'The terminal shell path "{0}" is a directory', this._shellLaunchConfig.executable); } else if (exitCode === SHELL_CWD_INVALID_EXIT_CODE && this._shellLaunchConfig.cwd) { exitCodeMessage = nls.localize('terminal.integrated.exitedWithInvalidCWD', 'The terminal shell CWD "{0}" does not exist', this._shellLaunchConfig.cwd.toString()); + } else if (exitCode === LEGACY_CONSOLE_MODE_EXIT_CODE) { + exitCodeMessage = nls.localize('terminal.integrated.legacyConsoleModeError', 'The terminal failed to launch properly because your system has legacy console mode enabled, uncheck "Use legacy console" cmd.exe\'s properties to fix this.'); } else if (this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) { let args = ''; if (typeof this._shellLaunchConfig.args === 'string') { @@ -1105,11 +1082,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } - this._onExit.fire(exitCode || 0); + this._onExit.fire(exitCode); } private _attachPressAnyKeyToCloseListener(xterm: XTermTerminal) { - if (!this._pressAnyKeyToCloseListener) { + if (xterm.textarea && !this._pressAnyKeyToCloseListener) { this._pressAnyKeyToCloseListener = dom.addDisposableListener(xterm.textarea, 'keypress', (event: KeyboardEvent) => { if (this._pressAnyKeyToCloseListener) { this._pressAnyKeyToCloseListener.dispose(); @@ -1123,10 +1100,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { public reuseTerminal(shell: IShellLaunchConfig): void { // Unsubscribe any key listener we may have. - if (this._pressAnyKeyToCloseListener) { - this._pressAnyKeyToCloseListener.dispose(); - this._pressAnyKeyToCloseListener = undefined; - } + this._pressAnyKeyToCloseListener?.dispose(); + this._pressAnyKeyToCloseListener = undefined; // Kill and clear up the process, making the process manager ready for a new process this._processManager.dispose(); @@ -1240,6 +1215,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._safeSetOption('macOptionClickForcesSelection', config.macOptionClickForcesSelection); this._safeSetOption('rightClickSelectsWord', config.rightClickBehavior === 'selectWord'); this._safeSetOption('rendererType', config.rendererType === 'auto' ? 'canvas' : config.rendererType); + + const editorOptions = this._configurationService.getValue('editor'); + this._safeSetOption('fastScrollSensitivity', editorOptions.fastScrollSensitivity); + this._safeSetOption('scrollSensitivity', editorOptions.mouseWheelScrollSensitivity); } public updateAccessibilitySupport(): void { @@ -1248,10 +1227,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._navigationModeAddon = new NavigationModeAddon(this._terminalA11yTreeFocusContextKey); this._xterm!.loadAddon(this._navigationModeAddon); } else { - if (this._navigationModeAddon) { - this._navigationModeAddon.dispose(); - this._navigationModeAddon = undefined; - } + this._navigationModeAddon?.dispose(); + this._navigationModeAddon = undefined; } this._xterm!.setOption('screenReaderMode', isEnabled); } @@ -1312,7 +1289,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } - if (this._xterm) { + if (this._xterm && this._xterm.element) { this._xterm.element.style.width = terminalWidth + 'px'; } @@ -1367,6 +1344,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._processManager.ptyProcessReady.then(() => this._processManager.setDimensions(cols, rows)); } + public setShellType(shellType: TerminalShellType) { + this._shellType = shellType; + } + public setTitle(title: string | undefined, eventSource: TitleEventSource): void { if (!title) { return; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts index 244285b9694..544cabcde0d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts @@ -7,13 +7,13 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; +import { TerminalWidgetManager, WidgetVerticalAlignment } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITerminalProcessManager, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IFileService } from 'vs/platform/files/common/files'; -import { Terminal, ILinkMatcherOptions } from 'xterm'; +import { Terminal, ILinkMatcherOptions, IViewportRange } from 'xterm'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { posix, win32 } from 'vs/base/common/path'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; @@ -71,7 +71,7 @@ export class TerminalLinkHandler { private _processCwd: string | undefined; private _gitDiffPreImagePattern: RegExp; private _gitDiffPostImagePattern: RegExp; - private readonly _tooltipCallback: (event: MouseEvent, uri: string) => boolean | void; + private readonly _tooltipCallback: (event: MouseEvent, uri: string, location: IViewportRange) => boolean | void; private readonly _leaveCallback: () => void; constructor( @@ -89,15 +89,42 @@ export class TerminalLinkHandler { // Matches '+++ b/src/file1', capturing 'src/file1' in group 1 this._gitDiffPostImagePattern = /^\+\+\+ b\/(\S*)/; - this._tooltipCallback = (e: MouseEvent) => { + this._tooltipCallback = (e: MouseEvent, uri: string, location: IViewportRange) => { if (!this._widgetManager) { return; } + + // Get the row bottom up + let offsetRow = this._xterm.rows - location.start.y; + let verticalAlignment = WidgetVerticalAlignment.Bottom; + + // Show the tooltip on the top of the next row to avoid obscuring the first row + if (location.start.y <= 0) { + offsetRow = this._xterm.rows - 1; + verticalAlignment = WidgetVerticalAlignment.Top; + // The start of the wrapped line is above the viewport, move to start of the line + if (location.start.y < 0) { + location.start.x = 0; + } + } + if (this._configHelper.config.rendererType === 'dom') { - const target = (e.target as HTMLElement); - this._widgetManager.showMessage(target.offsetLeft, target.offsetTop, this._getLinkHoverString()); + const font = this._configHelper.getFont(); + const charWidth = font.charWidth; + const charHeight = font.charHeight; + + const leftPosition = location.start.x * (charWidth! + (font.letterSpacing / window.devicePixelRatio)); + const bottomPosition = offsetRow * (Math.ceil(charHeight! * window.devicePixelRatio) * font.lineHeight) / window.devicePixelRatio; + + this._widgetManager.showMessage(leftPosition, bottomPosition, this._getLinkHoverString(), verticalAlignment); } else { - this._widgetManager.showMessage(e.offsetX, e.offsetY, this._getLinkHoverString()); + const target = (e.target as HTMLElement); + const colWidth = target.offsetWidth / this._xterm.cols; + const rowHeight = target.offsetHeight / this._xterm.rows; + + const leftPosition = location.start.x * colWidth; + const bottomPosition = offsetRow * rowHeight; + this._widgetManager.showMessage(leftPosition, bottomPosition, this._getLinkHoverString(), verticalAlignment); } }; this._leaveCallback = () => { @@ -108,7 +135,9 @@ export class TerminalLinkHandler { this.registerWebLinkHandler(); if (this._processManager) { - this.registerLocalLinkHandler(); + if (this._configHelper.config.enableFileLinks) { + this.registerLocalLinkHandler(); + } this.registerGitDiffLinkHandlers(); } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts index 77ff7a72859..baf2855e0a5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts @@ -15,7 +15,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { TERMINAL_PANEL_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; -import { editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { editorHoverBackground, editorHoverBorder, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; import { KillTerminalAction, SwitchTerminalAction, SwitchTerminalActionViewItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction, SplitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { Panel } from 'vs/workbench/browser/panel'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; @@ -25,6 +25,7 @@ import { DataTransfers } from 'vs/base/browser/dnd'; import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { assertIsDefined } from 'vs/base/common/types'; const FIND_FOCUS_CLASS = 'find-focused'; @@ -70,7 +71,8 @@ export class TerminalPanel extends Panel { this._attachEventListeners(this._parentDomElement, this._terminalContainer); - this._terminalService.setContainers(this.getContainer(), this._terminalContainer); + const container = assertIsDefined(this.getContainer()); + this._terminalService.setContainers(container, this._terminalContainer); this._register(this.themeService.onThemeChange(theme => this._updateTheme(theme))); this._register(this._configurationService.onDidChangeConfiguration(e => { @@ -216,12 +218,13 @@ export class TerminalPanel extends Panel { terminal.focus(); } } else if (event.which === 3) { - if (this._terminalService.configHelper.config.rightClickBehavior === 'copyPaste') { + const rightClickBehavior = this._terminalService.configHelper.config.rightClickBehavior; + if (rightClickBehavior === 'copyPaste' || rightClickBehavior === 'paste') { const terminal = this._terminalService.getActiveInstance(); if (!terminal) { return; } - if (terminal.hasSelection()) { + if (rightClickBehavior === 'copyPaste' && terminal.hasSelection()) { await terminal.copySelection(); terminal.clearSelection(); } else { @@ -250,6 +253,7 @@ export class TerminalPanel extends Panel { getActionsContext: () => this._parentDomElement }); } else { + event.preventDefault(); event.stopImmediatePropagation(); } this._cancelContextMenu = false; @@ -288,7 +292,7 @@ export class TerminalPanel extends Panel { const terminal = this._terminalService.getActiveInstance(); if (terminal) { - return this._terminalService.preparePathForTerminalAsync(path, terminal.shellLaunchConfig.executable, terminal.title).then(preparedPath => { + return this._terminalService.preparePathForTerminalAsync(path, terminal.shellLaunchConfig.executable, terminal.title, terminal.shellType).then(preparedPath => { terminal.sendText(preparedPath, false); }); } @@ -334,7 +338,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { if (hoverBorder) { collector.addRule(`.monaco-workbench .panel.integrated-terminal .terminal-message-widget { border: 1px solid ${hoverBorder}; }`); } - const hoverForeground = theme.getColor(editorForeground); + const hoverForeground = theme.getColor(editorHoverForeground); if (hoverForeground) { collector.addRule(`.monaco-workbench .panel.integrated-terminal .terminal-message-widget { color: ${hoverForeground}; }`); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts index 345840a6410..3db8f795da5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts @@ -48,7 +48,7 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal constructor( public terminalId: number, shellLaunchConfig: IShellLaunchConfig, - activeWorkspaceRootUri: URI, + activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, configHelper: ITerminalConfigHelper, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts index cfe9620f43f..0a17ee6d236 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickOpen.ts @@ -88,7 +88,7 @@ export class TerminalPickerHandler extends QuickOpenHandler { const normalizedSearchValueLowercase = stripWildcards(searchValue).toLowerCase(); const terminalEntries: QuickOpenEntry[] = this.getTerminals(); - terminalEntries.push(new CreateTerminal(nls.localize("workbench.action.terminal.newplus", "$(plus) Create New Integrated Terminal"), this.commandService)); + terminalEntries.push(new CreateTerminal('$(plus) ' + nls.localize("workbench.action.terminal.newplus", "Create New Integrated Terminal"), this.commandService)); const entries = terminalEntries.filter(e => { if (!searchValue) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 28d6d55692e..336926a4cc0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -11,13 +11,12 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { INotificationService } from 'vs/platform/notification/common/notification'; import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance'; -import { IBrowserTerminalConfigHelper, ITerminalService, ITerminalInstance, ITerminalTab } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalService, ITerminalInstance, ITerminalTab, TerminalShellType, WindowsShellType } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; @@ -29,6 +28,7 @@ import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/termi import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform'; import { basename } from 'vs/base/common/path'; import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; +import { find } from 'vs/base/common/arrays'; interface IExtHostReadyEntry { promise: Promise; @@ -54,7 +54,7 @@ export class TerminalService implements ITerminalService { public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; } public get terminalTabs(): ITerminalTab[] { return this._terminalTabs; } - private _configHelper: IBrowserTerminalConfigHelper; + private _configHelper: TerminalConfigHelper; private _terminalContainer: HTMLElement | undefined; public get configHelper(): ITerminalConfigHelper { return this._configHelper; } @@ -91,7 +91,6 @@ export class TerminalService implements ITerminalService { @IPanelService private _panelService: IPanelService, @IWorkbenchLayoutService private _layoutService: IWorkbenchLayoutService, @ILifecycleService lifecycleService: ILifecycleService, - @INotificationService private _notificationService: INotificationService, @IDialogService private _dialogService: IDialogService, @IInstantiationService private _instantiationService: IInstantiationService, @IExtensionService private _extensionService: IExtensionService, @@ -135,7 +134,7 @@ export class TerminalService implements ITerminalService { return activeInstance ? activeInstance : this.createTerminal(undefined); } - public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { + public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { this._extensionService.whenInstalledExtensionsRegistered().then(async () => { // Wait for the remoteAuthority to be ready (and listening for events) before firing // the event to spawn the ext host process @@ -392,12 +391,7 @@ export class TerminalService implements ITerminalService { return null; } - const instance = tab.split(this._terminalFocusContextKey, this.configHelper, shellLaunchConfig); - if (!instance) { - this._showNotEnoughSpaceToast(); - return null; - } - + const instance = tab.split(shellLaunchConfig); this._initInstanceListeners(instance); this._onInstancesChanged.fire(); @@ -414,13 +408,8 @@ export class TerminalService implements ITerminalService { instance.addDisposable(instance.onFocus(this._onActiveInstanceChanged.fire, this._onActiveInstanceChanged)); } - private _getTabForInstance(instance: ITerminalInstance): ITerminalTab | null { - for (const tab of this._terminalTabs) { - if (tab.terminalInstances.indexOf(instance) !== -1) { - return tab; - } - } - return null; + private _getTabForInstance(instance: ITerminalInstance): ITerminalTab | undefined { + return find(this._terminalTabs, tab => tab.terminalInstances.indexOf(instance) !== -1); } public showPanel(focus?: boolean): Promise { @@ -499,10 +488,6 @@ export class TerminalService implements ITerminalService { return !res.confirmed; } - protected _showNotEnoughSpaceToast(): void { - this._notificationService.info(nls.localize('terminal.minWidth', "Not enough space to split terminal.")); - } - protected _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> { if (potentialPaths.length === 0) { return Promise.resolve(null); @@ -519,7 +504,7 @@ export class TerminalService implements ITerminalService { }); } - public preparePathForTerminalAsync(originalPath: string, executable: string, title: string): Promise { + public preparePathForTerminalAsync(originalPath: string, executable: string, title: string, shellType: TerminalShellType): Promise { return new Promise(c => { if (!executable) { c(originalPath); @@ -542,18 +527,41 @@ export class TerminalService implements ITerminalService { if (isWindows) { // 17063 is the build number where wsl path was introduced. // Update Windows uriPath to be executed in WSL. - const lowerExecutable = executable.toLowerCase(); - if (this._terminalNativeService.getWindowsBuildNumber() >= 17063 && - (lowerExecutable.indexOf('wsl') !== -1 || (lowerExecutable.indexOf('bash.exe') !== -1 && lowerExecutable.toLowerCase().indexOf('git') === -1))) { - c(this._terminalNativeService.getWslPath(originalPath)); - return; - } else if (hasSpace) { - c('"' + originalPath + '"'); + if (shellType !== undefined) { + if (shellType === WindowsShellType.GitBash) { + c(originalPath.replace(/\\/g, '/')); + return; + } + else if (shellType === WindowsShellType.Wsl) { + if (this._terminalNativeService.getWindowsBuildNumber() >= 17063) { + c(this._terminalNativeService.getWslPath(originalPath)); + } else { + c(originalPath.replace(/\\/g, '/')); + } + return; + } + + if (hasSpace) { + c('"' + originalPath + '"'); + } else { + c(originalPath); + } } else { - c(originalPath); + const lowerExecutable = executable.toLowerCase(); + if (this._terminalNativeService.getWindowsBuildNumber() >= 17063 && + (lowerExecutable.indexOf('wsl') !== -1 || (lowerExecutable.indexOf('bash.exe') !== -1 && lowerExecutable.toLowerCase().indexOf('git') === -1))) { + c(this._terminalNativeService.getWslPath(originalPath)); + return; + } else if (hasSpace) { + c('"' + originalPath + '"'); + } else { + c(originalPath); + } } + return; } + c(escapeNonWindowsPath(originalPath)); }); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts index 3d4d50cdc9f..68ff40e9135 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts @@ -14,7 +14,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ITerminalInstance, Direction, ITerminalTab, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; const SPLIT_PANE_MIN_SIZE = 120; -const TERMINAL_MIN_USEFUL_SIZE = 250; class SplitPaneContainer extends Disposable { private _height: number; @@ -370,18 +369,11 @@ export class TerminalTab extends Disposable implements ITerminalTab { this.terminalInstances.forEach(i => i.setVisible(visible)); } - public split( - terminalFocusContextKey: IContextKey, - configHelper: ITerminalConfigHelper, - shellLaunchConfig: IShellLaunchConfig - ): ITerminalInstance | undefined { + public split(shellLaunchConfig: IShellLaunchConfig): ITerminalInstance { if (!this._container) { throw new Error('Cannot split terminal that has not been attached'); } - const newTerminalSize = ((this._panelPosition === Position.BOTTOM ? this._container.clientWidth : this._container.clientHeight) / (this._terminalInstances.length + 1)); - if (newTerminalSize < TERMINAL_MIN_USEFUL_SIZE) { - return undefined; - } + const instance = this._terminalService.createInstance(undefined, shellLaunchConfig); this._terminalInstances.splice(this._activeInstanceIndex + 1, 0, instance); this._initInstanceListeners(instance); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts index ce9ed466a98..a3c8a90636f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalWidgetManager.ts @@ -5,6 +5,11 @@ import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +export enum WidgetVerticalAlignment { + Bottom, + Top +} + const WIDGET_HEIGHT = 29; export class TerminalWidgetManager implements IDisposable { @@ -43,13 +48,13 @@ export class TerminalWidgetManager implements IDisposable { mutationObserver.observe(this._xtermViewport, { attributes: true, attributeFilter: ['style'] }); } - public showMessage(left: number, top: number, text: string): void { + public showMessage(left: number, y: number, text: string, verticalAlignment: WidgetVerticalAlignment = WidgetVerticalAlignment.Bottom): void { if (!this._container) { return; } dispose(this._messageWidget); this._messageListeners.clear(); - this._messageWidget = new MessageWidget(this._container, left, top, text); + this._messageWidget = new MessageWidget(this._container, left, y, text, verticalAlignment); } public closeMessage(): void { @@ -71,9 +76,10 @@ class MessageWidget { private _domNode: HTMLDivElement; public get left(): number { return this._left; } - public get top(): number { return this._top; } + public get y(): number { return this._y; } public get text(): string { return this._text; } public get domNode(): HTMLElement { return this._domNode; } + public get verticalAlignment(): WidgetVerticalAlignment { return this._verticalAlignment; } public static fadeOut(messageWidget: MessageWidget): IDisposable { let handle: any; @@ -91,13 +97,22 @@ class MessageWidget { constructor( private _container: HTMLElement, private _left: number, - private _top: number, - private _text: string + private _y: number, + private _text: string, + private _verticalAlignment: WidgetVerticalAlignment ) { this._domNode = document.createElement('div'); this._domNode.style.position = 'absolute'; this._domNode.style.left = `${_left}px`; - this._domNode.style.bottom = `${_container.offsetHeight - Math.max(_top, WIDGET_HEIGHT)}px`; + + if (this.verticalAlignment === WidgetVerticalAlignment.Top) { + // Y position is to the top of the widget + this._domNode.style.bottom = `${Math.max(_y, WIDGET_HEIGHT) - WIDGET_HEIGHT}px`; + } else { + // Y position is to the bottom of the widget + this._domNode.style.bottom = `${Math.min(_y, _container.offsetHeight - WIDGET_HEIGHT)}px`; + } + this._domNode.classList.add('terminal-message-widget', 'fadeIn'); this._domNode.textContent = _text; this._container.appendChild(this._domNode); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts index 50aa2e843a8..9c57c636a9e 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts @@ -22,11 +22,6 @@ export interface XTermCore { }; _onIntersectionChange: any; }; - - // TODO: Remove below once a synchronous write API is added - // The below are only used in tests - writeBuffer: string[]; - _innerWrite(): void; } export interface IEventEmitter { diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index f6f1c9b619d..fdbc74996a0 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -65,6 +65,7 @@ export const DEFAULT_LINE_HEIGHT = 1; export const SHELL_PATH_INVALID_EXIT_CODE = -1; export const SHELL_PATH_DIRECTORY_EXIT_CODE = -2; export const SHELL_CWD_INVALID_EXIT_CODE = -3; +export const LEGACY_CONSOLE_MODE_EXIT_CODE = 3221225786; // microsoft/vscode#73790 export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; @@ -87,7 +88,7 @@ export interface ITerminalConfiguration { macOptionIsMeta: boolean; macOptionClickForcesSelection: boolean; rendererType: 'auto' | 'canvas' | 'dom'; - rightClickBehavior: 'default' | 'copyPaste' | 'selectWord'; + rightClickBehavior: 'default' | 'copyPaste' | 'paste' | 'selectWord'; cursorBlinking: boolean; cursorStyle: string; drawBoldTextInBrightColors: boolean; @@ -101,6 +102,7 @@ export interface ITerminalConfiguration { detectLocale: 'auto' | 'off' | 'on'; scrollback: number; commandsToSkipShell: string[]; + allowChords: boolean; cwd: string; confirmOnExit: boolean; enableBell: boolean; @@ -111,11 +113,11 @@ export interface ITerminalConfiguration { windows: { [key: string]: string }; }; showExitAlert: boolean; - experimentalBufferImpl: 'JsArray' | 'TypedArray'; splitCwd: 'workspaceRoot' | 'initial' | 'inherited'; windowsEnableConpty: boolean; experimentalRefreshOnResume: boolean; experimentalUseTitleEvent: boolean; + enableFileLinks: boolean; } export interface ITerminalConfigHelper { @@ -340,7 +342,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable { export interface ISpawnExtHostProcessRequest { proxy: ITerminalProcessExtHostProxy; shellLaunchConfig: IShellLaunchConfig; - activeWorkspaceRootUri: URI; + activeWorkspaceRootUri: URI | undefined; cols: number; rows: number; isWorkspaceShellAllowed: boolean; @@ -409,9 +411,7 @@ export interface ITerminalChildProcess { export const enum TERMINAL_COMMAND_ID { FIND_NEXT = 'workbench.action.terminal.findNext', - FIND_NEXT_TERMINAL_FOCUS = 'workbench.action.terminal.findNextTerminalFocus', FIND_PREVIOUS = 'workbench.action.terminal.findPrevious', - FIND_PREVIOUS_TERMINAL_FOCUS = 'workbench.action.terminal.findPreviousTerminalFocus', TOGGLE = 'workbench.action.terminal.toggleTerminal', KILL = 'workbench.action.terminal.kill', QUICK_KILL = 'workbench.action.terminal.quickKill', @@ -466,9 +466,6 @@ export const enum TERMINAL_COMMAND_ID { TOGGLE_FIND_REGEX = 'workbench.action.terminal.toggleFindRegex', TOGGLE_FIND_WHOLE_WORD = 'workbench.action.terminal.toggleFindWholeWord', TOGGLE_FIND_CASE_SENSITIVE = 'workbench.action.terminal.toggleFindCaseSensitive', - TOGGLE_FIND_REGEX_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindRegexTerminalFocus', - TOGGLE_FIND_WHOLE_WORD_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindWholeWordTerminalFocus', - TOGGLE_FIND_CASE_SENSITIVE_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindCaseSensitiveTerminalFocus', NAVIGATION_MODE_EXIT = 'workbench.action.terminal.navigationModeExit', NAVIGATION_MODE_FOCUS_NEXT = 'workbench.action.terminal.navigationModeFocusNext', NAVIGATION_MODE_FOCUS_PREVIOUS = 'workbench.action.terminal.navigationModeFocusPrevious' diff --git a/src/vs/workbench/contrib/terminal/common/terminalDataBuffering.ts b/src/vs/workbench/contrib/terminal/common/terminalDataBuffering.ts new file mode 100644 index 00000000000..8b2008bf29b --- /dev/null +++ b/src/vs/workbench/contrib/terminal/common/terminalDataBuffering.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 { Event } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; + +interface TerminalDataBuffer extends IDisposable { + data: string[]; + timeoutId: any; +} + +export class TerminalDataBufferer implements IDisposable { + private readonly _terminalBufferMap = new Map(); + + dispose() { + for (const buffer of this._terminalBufferMap.values()) { + buffer.dispose(); + } + } + + startBuffering(id: number, event: Event, callback: (id: number, data: string) => void, throttleBy: number = 5): IDisposable { + let disposable: IDisposable; + disposable = event((e: string) => { + let buffer = this._terminalBufferMap.get(id); + if (buffer) { + buffer.data.push(e); + + return; + } + + const timeoutId = setTimeout(() => { + this._terminalBufferMap.delete(id); + callback(id, buffer!.data.join('')); + }, throttleBy); + buffer = { + data: [e], + timeoutId: timeoutId, + dispose: () => { + clearTimeout(timeoutId); + this._terminalBufferMap.delete(id); + disposable.dispose(); + } + }; + this._terminalBufferMap.set(id, buffer); + }); + return disposable; + } + + stopBuffering(id: number) { + const buffer = this._terminalBufferMap.get(id); + if (buffer) { + buffer.dispose(); + } + } +} diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 171e639c20f..31b85a9ccdd 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -282,7 +282,6 @@ export function getDefaultShell( executable = configurationResolverService.resolve(lastActiveWorkspace, executable); } catch (e) { logService.error(`Could not resolve shell`, e); - executable = executable; } } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts index 17302176a38..3787f9ce6a3 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeService.ts @@ -69,9 +69,10 @@ export class TerminalNativeService implements ITerminalNativeService { throw new Error('wslpath does not exist on Windows build < 17063'); } return new Promise(c => { - execFile('bash.exe', ['-c', 'echo $(wslpath ' + escapeNonWindowsPath(path) + ')'], {}, (error, stdout, stderr) => { + const proc = execFile('bash.exe', ['-c', `wslpath ${escapeNonWindowsPath(path)}`], {}, (error, stdout, stderr) => { c(escapeNonWindowsPath(stdout.trim())); }); + proc.stdin!.end(); }); } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts b/src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts index e36a8d72f00..ba298a3bf7f 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/windowsShellHelper.ts @@ -9,11 +9,12 @@ import { IWindowsShellHelper, TitleEventSource } from 'vs/workbench/contrib/term import { Terminal as XTermTerminal } from 'xterm'; import * as WindowsProcessTreeType from 'windows-process-tree'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalInstance, TerminalShellType, WindowsShellType } from 'vs/workbench/contrib/terminal/browser/terminal'; const SHELL_EXECUTABLES = [ 'cmd.exe', 'powershell.exe', + 'pwsh.exe', 'bash.exe', 'wsl.exe', 'ubuntu.exe', @@ -81,6 +82,7 @@ export class WindowsShellHelper extends Disposable implements IWindowsShellHelpe if (platform.isWindows && this._terminalInstance.isTitleSetByProcess) { this.getShellName().then(title => { if (!this._isDisposed) { + this._terminalInstance.setShellType(this.getShellType(title)); this._terminalInstance.setTitle(title, TitleEventSource.Process); } }); @@ -138,4 +140,26 @@ export class WindowsShellHelper extends Disposable implements IWindowsShellHelpe }); return this._currentRequest; } + + public getShellType(executable: string): TerminalShellType { + switch (executable.toLowerCase()) { + case 'cmd.exe': + return WindowsShellType.CommandPrompt; + case 'powershell.exe': + case 'pwsh.exe': + return WindowsShellType.PowerShell; + case 'bash.exe': + return WindowsShellType.GitBash; + case 'wsl.exe': + case 'ubuntu.exe': + case 'ubuntu1804.exe': + case 'kali.exe': + case 'debian.exe': + case 'opensuse-42.exe': + case 'sles-12.exe': + return WindowsShellType.Wsl; + default: + return undefined; + } + } } diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts index 61e4891c821..8456a0fdd41 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts @@ -74,18 +74,21 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess if (!stat.isDirectory()) { return Promise.reject(SHELL_CWD_INVALID_EXIT_CODE); } + return undefined; }, async err => { if (err && err.code === 'ENOENT') { // So we can include in the error message the specified CWD shellLaunchConfig.cwd = cwd; return Promise.reject(SHELL_CWD_INVALID_EXIT_CODE); } + return undefined; }); const executableVerification = stat(shellLaunchConfig.executable!).then(async stat => { if (!stat.isFile() && !stat.isSymbolicLink()) { return Promise.reject(stat.isDirectory() ? SHELL_PATH_DIRECTORY_EXIT_CODE : SHELL_PATH_INVALID_EXIT_CODE); } + return undefined; }, async (err) => { if (err && err.code === 'ENOENT') { let cwd = shellLaunchConfig.cwd instanceof URI ? shellLaunchConfig.cwd.path : shellLaunchConfig.cwd!; @@ -96,6 +99,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess return Promise.reject(SHELL_PATH_INVALID_EXIT_CODE); } } + return undefined; }); Promise.all([cwdVerification, executableVerification]).then(() => { @@ -237,7 +241,14 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess cols = Math.max(cols, 1); rows = Math.max(rows, 1); this._logService.trace('IPty#resize', cols, rows); - this._ptyProcess.resize(cols, rows); + try { + this._ptyProcess.resize(cols, rows); + } catch (e) { + // Swallow error if the pty has already exited + if (this._exitCode !== undefined) { + throw e; + } + } } } @@ -253,7 +264,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess return; } this._logService.trace('IPty#pid'); - exec('lsof -p ' + this._ptyProcess.pid + ' | grep cwd', (error, stdout, stderr) => { + exec('lsof -OPl -p ' + this._ptyProcess.pid + ' | grep cwd', (error, stdout, stderr) => { if (stdout !== '') { resolve(stdout.substring(stdout.indexOf('/'), stdout.length - 1)); } diff --git a/src/vs/workbench/contrib/terminal/test/common/terminalDataBuffering.test.ts b/src/vs/workbench/contrib/terminal/test/common/terminalDataBuffering.test.ts new file mode 100644 index 00000000000..54a2e4be0ab --- /dev/null +++ b/src/vs/workbench/contrib/terminal/test/common/terminalDataBuffering.test.ts @@ -0,0 +1,191 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { Emitter } from 'vs/base/common/event'; +import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering'; + +const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + +suite('Workbench - TerminalDataBufferer', () => { + let bufferer: TerminalDataBufferer; + + setup(async () => { + bufferer = new TerminalDataBufferer(); + }); + + test('start', async () => { + let terminalOnData = new Emitter(); + let counter = 0; + let data: string | undefined; + + bufferer.startBuffering(1, terminalOnData.event, (id, e) => { + counter++; + data = e; + }, 0); + + terminalOnData.fire('1'); + terminalOnData.fire('2'); + terminalOnData.fire('3'); + + await wait(0); + + terminalOnData.fire('4'); + + assert.equal(counter, 1); + assert.equal(data, '123'); + + await wait(0); + + assert.equal(counter, 2); + assert.equal(data, '4'); + }); + + test('start 2', async () => { + let terminal1OnData = new Emitter(); + let terminal1Counter = 0; + let terminal1Data: string | undefined; + + bufferer.startBuffering(1, terminal1OnData.event, (id, e) => { + terminal1Counter++; + terminal1Data = e; + }, 0); + + let terminal2OnData = new Emitter(); + let terminal2Counter = 0; + let terminal2Data: string | undefined; + + bufferer.startBuffering(2, terminal2OnData.event, (id, e) => { + terminal2Counter++; + terminal2Data = e; + }, 0); + + terminal1OnData.fire('1'); + terminal2OnData.fire('4'); + terminal1OnData.fire('2'); + terminal2OnData.fire('5'); + terminal1OnData.fire('3'); + terminal2OnData.fire('6'); + terminal2OnData.fire('7'); + + assert.equal(terminal1Counter, 0); + assert.equal(terminal1Data, undefined); + assert.equal(terminal2Counter, 0); + assert.equal(terminal2Data, undefined); + + await wait(0); + + assert.equal(terminal1Counter, 1); + assert.equal(terminal1Data, '123'); + assert.equal(terminal2Counter, 1); + assert.equal(terminal2Data, '4567'); + }); + + test('stop', async () => { + let terminalOnData = new Emitter(); + let counter = 0; + let data: string | undefined; + + bufferer.startBuffering(1, terminalOnData.event, (id, e) => { + counter++; + data = e; + }, 0); + + terminalOnData.fire('1'); + terminalOnData.fire('2'); + terminalOnData.fire('3'); + + bufferer.stopBuffering(1); + + await wait(0); + + assert.equal(counter, 0); + assert.equal(data, undefined); + }); + + test('start 2 stop 1', async () => { + let terminal1OnData = new Emitter(); + let terminal1Counter = 0; + let terminal1Data: string | undefined; + + bufferer.startBuffering(1, terminal1OnData.event, (id, e) => { + terminal1Counter++; + terminal1Data = e; + }, 0); + + let terminal2OnData = new Emitter(); + let terminal2Counter = 0; + let terminal2Data: string | undefined; + + bufferer.startBuffering(2, terminal2OnData.event, (id, e) => { + terminal2Counter++; + terminal2Data = e; + }, 0); + + + terminal1OnData.fire('1'); + terminal2OnData.fire('4'); + terminal1OnData.fire('2'); + terminal2OnData.fire('5'); + terminal1OnData.fire('3'); + terminal2OnData.fire('6'); + terminal2OnData.fire('7'); + + assert.equal(terminal1Counter, 0); + assert.equal(terminal1Data, undefined); + assert.equal(terminal2Counter, 0); + assert.equal(terminal2Data, undefined); + + bufferer.stopBuffering(1); + await wait(0); + + assert.equal(terminal1Counter, 0); + assert.equal(terminal1Data, undefined); + assert.equal(terminal2Counter, 1); + assert.equal(terminal2Data, '4567'); + }); + + test('dispose', async () => { + let terminal1OnData = new Emitter(); + let terminal1Counter = 0; + let terminal1Data: string | undefined; + + bufferer.startBuffering(1, terminal1OnData.event, (id, e) => { + terminal1Counter++; + terminal1Data = e; + }, 0); + + let terminal2OnData = new Emitter(); + let terminal2Counter = 0; + let terminal2Data: string | undefined; + + bufferer.startBuffering(2, terminal2OnData.event, (id, e) => { + terminal2Counter++; + terminal2Data = e; + }, 0); + + + terminal1OnData.fire('1'); + terminal2OnData.fire('4'); + terminal1OnData.fire('2'); + terminal2OnData.fire('5'); + terminal1OnData.fire('3'); + terminal2OnData.fire('6'); + terminal2OnData.fire('7'); + + assert.equal(terminal1Counter, 0); + assert.equal(terminal1Data, undefined); + assert.equal(terminal2Counter, 0); + assert.equal(terminal2Data, undefined); + + bufferer.dispose(); + await wait(0); + + assert.equal(terminal1Counter, 0); + assert.equal(terminal1Data, undefined); + assert.equal(terminal2Counter, 0); + assert.equal(terminal2Data, undefined); + }); +}); diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts index f6198e4428c..bdaf6d62248 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts @@ -13,10 +13,8 @@ interface TestTerminal extends Terminal { _core: XTermCore; } -function syncWrite(term: TestTerminal, data: string): void { - // Terminal.write is asynchronous - term._core.writeBuffer.push(data); - term._core._innerWrite(); +function writePromise(term: Terminal, data: string): Promise { + return new Promise(r => term.write(data, r)); } const ROWS = 10; @@ -26,42 +24,42 @@ suite('Workbench - TerminalCommandTracker', () => { let xterm: TestTerminal; let commandTracker: CommandTrackerAddon; - setup(() => { + setup(async () => { xterm = (new Terminal({ cols: COLS, rows: ROWS })); // Fill initial viewport for (let i = 0; i < ROWS - 1; i++) { - syncWrite(xterm, `${i}\n`); + await writePromise(xterm, `${i}\n`); } commandTracker = new CommandTrackerAddon(); xterm.loadAddon(commandTracker); }); suite('Command tracking', () => { - test('should track commands when the prompt is of sufficient size', () => { + test('should track commands when the prompt is of sufficient size', async () => { assert.equal(xterm.markers.length, 0); - syncWrite(xterm, '\x1b[3G'); // Move cursor to column 3 + await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3 xterm._core._onKey.fire({ key: '\x0d' }); assert.equal(xterm.markers.length, 1); }); - test('should not track commands when the prompt is too small', () => { + test('should not track commands when the prompt is too small', async () => { assert.equal(xterm.markers.length, 0); - syncWrite(xterm, '\x1b[2G'); // Move cursor to column 2 + await writePromise(xterm, '\x1b[2G'); // Move cursor to column 2 xterm._core._onKey.fire({ key: '\x0d' }); assert.equal(xterm.markers.length, 0); }); }); suite('Commands', () => { - test('should scroll to the next and previous commands', () => { - syncWrite(xterm, '\x1b[3G'); // Move cursor to column 3 + test('should scroll to the next and previous commands', async () => { + await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3 xterm._core._onKey.fire({ key: '\x0d' }); // Mark line #10 assert.equal(xterm.markers[0].line, 9); for (let i = 0; i < 20; i++) { - syncWrite(xterm, `\r\n`); + await writePromise(xterm, `\r\n`); } assert.equal(xterm.buffer.baseY, 20); assert.equal(xterm.buffer.viewportY, 20); @@ -82,22 +80,24 @@ suite('Workbench - TerminalCommandTracker', () => { commandTracker.scrollToNextCommand(); assert.equal(xterm.buffer.viewportY, 20); }); - test('should select to the next and previous commands', () => { + test('should select to the next and previous commands', async () => { (window).matchMedia = () => { return { addListener: () => { } }; }; - xterm.open(document.createElement('div')); + const e = document.createElement('div'); + document.body.appendChild(e); + xterm.open(e); - syncWrite(xterm, '\r0'); - syncWrite(xterm, '\n\r1'); - syncWrite(xterm, '\x1b[3G'); // Move cursor to column 3 + await writePromise(xterm, '\r0'); + await writePromise(xterm, '\n\r1'); + await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3 xterm._core._onKey.fire({ key: '\x0d' }); // Mark line assert.equal(xterm.markers[0].line, 10); - syncWrite(xterm, '\n\r2'); - syncWrite(xterm, '\x1b[3G'); // Move cursor to column 3 + await writePromise(xterm, '\n\r2'); + await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3 xterm._core._onKey.fire({ key: '\x0d' }); // Mark line assert.equal(xterm.markers[1].line, 11); - syncWrite(xterm, '\n\r3'); + await writePromise(xterm, '\n\r3'); assert.equal(xterm.buffer.baseY, 3); assert.equal(xterm.buffer.viewportY, 3); @@ -111,23 +111,27 @@ suite('Workbench - TerminalCommandTracker', () => { assert.equal(xterm.getSelection(), '2'); commandTracker.selectToNextCommand(); assert.equal(xterm.getSelection(), isWindows ? '\r\n' : '\n'); + + document.body.removeChild(e); }); - test('should select to the next and previous lines & commands', () => { + test('should select to the next and previous lines & commands', async () => { (window).matchMedia = () => { return { addListener: () => { } }; }; - xterm.open(document.createElement('div')); + const e = document.createElement('div'); + document.body.appendChild(e); + xterm.open(e); - syncWrite(xterm, '\r0'); - syncWrite(xterm, '\n\r1'); - syncWrite(xterm, '\x1b[3G'); // Move cursor to column 3 + await writePromise(xterm, '\r0'); + await writePromise(xterm, '\n\r1'); + await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3 xterm._core._onKey.fire({ key: '\x0d' }); // Mark line assert.equal(xterm.markers[0].line, 10); - syncWrite(xterm, '\n\r2'); - syncWrite(xterm, '\x1b[3G'); // Move cursor to column 3 + await writePromise(xterm, '\n\r2'); + await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3 xterm._core._onKey.fire({ key: '\x0d' }); // Mark line assert.equal(xterm.markers[1].line, 11); - syncWrite(xterm, '\n\r3'); + await writePromise(xterm, '\n\r3'); assert.equal(xterm.buffer.baseY, 3); assert.equal(xterm.buffer.viewportY, 3); @@ -146,6 +150,8 @@ suite('Workbench - TerminalCommandTracker', () => { assert.equal(xterm.getSelection(), isWindows ? '1\r\n2' : '1\n2'); commandTracker.selectToPreviousLine(); assert.equal(xterm.getSelection(), isWindows ? '0\r\n1\r\n2' : '0\n1\n2'); + + document.body.removeChild(e); }); }); }); diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts index a5b8dbedfbd..a48c60f7b4a 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts @@ -9,6 +9,7 @@ import { TerminalLinkHandler, LineColumnInfo } from 'vs/workbench/contrib/termin import * as strings from 'vs/base/common/strings'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { Event } from 'vs/base/common/event'; +import { ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; class TestTerminalLinkHandler extends TerminalLinkHandler { public get localLinkRegex(): RegExp { @@ -62,13 +63,19 @@ interface LinkFormatInfo { column?: string; } +const testConfigHelper: ITerminalConfigHelper = { + config: { + enableFileLinks: true + } +}; + suite('Workbench - TerminalLinkHandler', () => { suite('localLinkRegex', () => { test('Windows', () => { const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm() as any, { os: OperatingSystem.Windows, userHome: '' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!); function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) { assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl); assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl); @@ -144,7 +151,7 @@ suite('Workbench - TerminalLinkHandler', () => { const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm() as any, { os: OperatingSystem.Linux, userHome: '' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!); function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) { assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl); assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl); @@ -212,7 +219,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, { os: OperatingSystem.Windows, userHome: 'C:\\Users\\Me' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!); linkHandler.processCwd = 'C:\\base'; assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\src\\file1'); @@ -225,7 +232,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, { os: OperatingSystem.Windows, userHome: 'C:\\Users\\M e' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!); linkHandler.processCwd = 'C:\\base dir'; assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base dir\\src\\file1'); @@ -239,7 +246,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, { os: OperatingSystem.Linux, userHome: '/home/me' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!); linkHandler.processCwd = '/base'; assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/src/file1'); @@ -252,7 +259,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, { os: OperatingSystem.Linux, userHome: '/home/me' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!); assert.equal(linkHandler.preprocessPath('./src/file1'), null); assert.equal(linkHandler.preprocessPath('src/file2'), null); @@ -266,7 +273,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, { os: OperatingSystem.Linux, userHome: '' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!); function assertAreGoodMatches(matches: RegExpMatchArray | null) { if (matches) { diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index 5026e50adad..268b0fcda80 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -14,7 +14,6 @@ import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING, IColor import { VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { Delayer } from 'vs/base/common/async'; import { IColorRegistry, Extensions as ColorRegistryExtensions } from 'vs/platform/theme/common/colorRegistry'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Color } from 'vs/base/common/color'; @@ -27,7 +26,7 @@ import { IQuickInputService, QuickPickInput } from 'vs/platform/quickinput/commo export class SelectColorThemeAction extends Action { static readonly ID = 'workbench.action.selectTheme'; - static LABEL = localize('selectTheme.label', "Color Theme"); + static readonly LABEL = localize('selectTheme.label', "Color Theme"); constructor( id: string, @@ -52,37 +51,59 @@ export class SelectColorThemeAction extends Action { ...configurationEntries(this.extensionGalleryService, localize('installColorThemes', "Install Additional Color Themes...")) ]; - const selectTheme = (theme: ThemeItem, applyTheme: boolean) => { - let themeId = theme.id; - if (typeof theme.id === 'undefined') { // 'pick in marketplace' entry - if (applyTheme) { - openExtensionViewlet(this.viewletService, 'category:themes '); - } - themeId = currentTheme.id; - } - let target: ConfigurationTarget | undefined = undefined; - if (applyTheme) { - let confValue = this.configurationService.inspect(COLOR_THEME_SETTING); - target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; - } + let selectThemeTimeout: number | undefined; - this.themeService.setColorTheme(themeId, target).then(undefined, - err => { - onUnexpectedError(err); - this.themeService.setColorTheme(currentTheme.id, undefined); + const selectTheme = (theme: ThemeItem, applyTheme: boolean) => { + if (selectThemeTimeout) { + clearTimeout(selectThemeTimeout); + } + selectThemeTimeout = window.setTimeout(() => { + selectThemeTimeout = undefined; + const themeId = theme && theme.id !== undefined ? theme.id : currentTheme.id; + let target: ConfigurationTarget | undefined = undefined; + if (applyTheme) { + const confValue = this.configurationService.inspect(COLOR_THEME_SETTING); + target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; } - ); + + this.themeService.setColorTheme(themeId, target).then(undefined, + err => { + onUnexpectedError(err); + this.themeService.setColorTheme(currentTheme.id, undefined); + } + ); + }, applyTheme ? 0 : 200); }; - const placeHolder = localize('themes.selectTheme', "Select Color Theme (Up/Down Keys to Preview)"); - const autoFocusIndex = firstIndex(picks, p => isItem(p) && p.id === currentTheme.id); - const activeItem: ThemeItem = picks[autoFocusIndex] as ThemeItem; - const delayer = new Delayer(100); - const chooseTheme = (theme: ThemeItem) => delayer.trigger(() => selectTheme(theme || currentTheme, true), 0); - const tryTheme = (theme: ThemeItem) => delayer.trigger(() => selectTheme(theme, false)); + return new Promise((s, _) => { + let isCompleted = false; - return this.quickInputService.pick(picks, { placeHolder, activeItem, onDidFocus: tryTheme }) - .then(chooseTheme); + const autoFocusIndex = firstIndex(picks, p => isItem(p) && p.id === currentTheme.id); + const quickpick = this.quickInputService.createQuickPick(); + quickpick.items = picks; + quickpick.placeholder = localize('themes.selectTheme', "Select Color Theme (Up/Down Keys to Preview)"); + quickpick.activeItems = [picks[autoFocusIndex] as ThemeItem]; + quickpick.canSelectMany = false; + quickpick.onDidAccept(_ => { + const theme = quickpick.activeItems[0]; + if (!theme || typeof theme.id === 'undefined') { // 'pick in marketplace' entry + openExtensionViewlet(this.viewletService, `category:themes ${quickpick.value}`); + } else { + selectTheme(theme, true); + } + isCompleted = true; + quickpick.hide(); + s(); + }); + quickpick.onDidChangeActive(themes => selectTheme(themes[0], false)); + quickpick.onDidHide(() => { + if (!isCompleted) { + selectTheme(currentTheme, true); + s(); + } + }); + quickpick.show(); + }); }); } } @@ -90,7 +111,7 @@ export class SelectColorThemeAction extends Action { class SelectIconThemeAction extends Action { static readonly ID = 'workbench.action.selectIconTheme'; - static LABEL = localize('selectIconTheme.label', "File Icon Theme"); + static readonly LABEL = localize('selectIconTheme.label', "File Icon Theme"); constructor( id: string, @@ -115,36 +136,58 @@ class SelectIconThemeAction extends Action { configurationEntries(this.extensionGalleryService, localize('installIconThemes', "Install Additional File Icon Themes...")) ); + let selectThemeTimeout: number | undefined; + const selectTheme = (theme: ThemeItem, applyTheme: boolean) => { - let themeId = theme.id; - if (typeof theme.id === 'undefined') { // 'pick in marketplace' entry + if (selectThemeTimeout) { + clearTimeout(selectThemeTimeout); + } + selectThemeTimeout = window.setTimeout(() => { + selectThemeTimeout = undefined; + const themeId = theme && theme.id !== undefined ? theme.id : currentTheme.id; + let target: ConfigurationTarget | undefined = undefined; if (applyTheme) { - openExtensionViewlet(this.viewletService, 'tag:icon-theme '); + const confValue = this.configurationService.inspect(ICON_THEME_SETTING); + target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; } - themeId = currentTheme.id; - } - let target: ConfigurationTarget | undefined = undefined; - if (applyTheme) { - let confValue = this.configurationService.inspect(ICON_THEME_SETTING); - target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; - } - this.themeService.setFileIconTheme(themeId, target).then(undefined, - err => { - onUnexpectedError(err); - this.themeService.setFileIconTheme(currentTheme.id, undefined); - } - ); + this.themeService.setFileIconTheme(themeId, target).then(undefined, + err => { + onUnexpectedError(err); + this.themeService.setFileIconTheme(currentTheme.id, undefined); + } + ); + }, applyTheme ? 0 : 200); }; - const placeHolder = localize('themes.selectIconTheme', "Select File Icon Theme"); - const autoFocusIndex = firstIndex(picks, p => isItem(p) && p.id === currentTheme.id); - const activeItem: ThemeItem = picks[autoFocusIndex] as ThemeItem; - const delayer = new Delayer(100); - const chooseTheme = (theme: ThemeItem) => delayer.trigger(() => selectTheme(theme || currentTheme, true), 0); - const tryTheme = (theme: ThemeItem) => delayer.trigger(() => selectTheme(theme, false)); + return new Promise((s, _) => { + let isCompleted = false; - return this.quickInputService.pick(picks, { placeHolder, activeItem, onDidFocus: tryTheme }) - .then(chooseTheme); + const autoFocusIndex = firstIndex(picks, p => isItem(p) && p.id === currentTheme.id); + const quickpick = this.quickInputService.createQuickPick(); + quickpick.items = picks; + quickpick.placeholder = localize('themes.selectIconTheme', "Select File Icon Theme"); + quickpick.activeItems = [picks[autoFocusIndex] as ThemeItem]; + quickpick.canSelectMany = false; + quickpick.onDidAccept(_ => { + const theme = quickpick.activeItems[0]; + if (!theme || typeof theme.id === 'undefined') { // 'pick in marketplace' entry + openExtensionViewlet(this.viewletService, `tag:icon-theme ${quickpick.value}`); + } else { + selectTheme(theme, true); + } + isCompleted = true; + quickpick.hide(); + s(); + }); + quickpick.onDidChangeActive(themes => selectTheme(themes[0], false)); + quickpick.onDidHide(() => { + if (!isCompleted) { + selectTheme(currentTheme, true); + s(); + } + }); + quickpick.show(); + }); }); } } @@ -197,7 +240,7 @@ function toEntries(themes: Array, label?: string): class GenerateColorThemeAction extends Action { static readonly ID = 'workbench.action.generateColorTheme'; - static LABEL = localize('generateColorTheme.label', "Generate Color Theme From Current Settings"); + static readonly LABEL = localize('generateColorTheme.label', "Generate Color Theme From Current Settings"); constructor( id: string, @@ -288,4 +331,4 @@ MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { title: localize('themes.selectIconTheme.label', "File Icon Theme") }, order: 2 -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/update/browser/media/markdown.css b/src/vs/workbench/contrib/update/browser/media/markdown.css deleted file mode 100644 index 8e1131551d7..00000000000 --- a/src/vs/workbench/contrib/update/browser/media/markdown.css +++ /dev/null @@ -1,130 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -body { - padding: 10px 20px; - line-height: 22px; -} - -img { - max-width: 100%; - max-height: 100%; -} - -a { - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -a:focus, -input:focus, -select:focus, -textarea:focus { - outline: 1px solid -webkit-focus-ring-color; - outline-offset: -1px; -} - -hr { - border: 0; - height: 2px; - border-bottom: 2px solid; -} - -h1 { - padding-bottom: 0.3em; - line-height: 1.2; - border-bottom-width: 1px; - border-bottom-style: solid; -} - -h1, h2, h3 { - font-weight: normal; -} - - -table { - border-collapse: collapse; -} - -table > thead > tr > th { - text-align: left; - border-bottom: 1px solid; -} - -table > thead > tr > th, -table > thead > tr > td, -table > tbody > tr > th, -table > tbody > tr > td { - padding: 5px 10px; -} - -table > tbody > tr + tr > td { - border-top-width: 1px; - border-top-style: solid; -} - -blockquote { - margin: 0 7px 0 5px; - padding: 0 16px 0 10px; - border-left-width: 5px; - border-left-style: solid; -} - -code { - font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback"; - font-size: 14px; - line-height: 19px; -} - -code > div { - padding: 16px; - border-radius: 3px; - overflow: auto; -} - -.monaco-tokenized-source { - white-space: pre; -} - -/** Theming */ - -.vscode-light code > div { - background-color: rgba(220, 220, 220, 0.4); -} - -.vscode-dark code > div { - background-color: rgba(10, 10, 10, 0.4); -} - -.vscode-high-contrast code > div { - background-color: rgb(0, 0, 0); -} - -.vscode-high-contrast h1 { - border-color: rgb(0, 0, 0); -} - -.vscode-light table > thead > tr > th { - border-color: rgba(0, 0, 0, 0.69); -} - -.vscode-dark table > thead > tr > th { - border-color: rgba(255, 255, 255, 0.69); -} - -.vscode-light h1, -.vscode-light hr, -.vscode-light table > tbody > tr + tr > td { - border-color: rgba(0, 0, 0, 0.18); -} - -.vscode-dark h1, -.vscode-dark hr, -.vscode-dark table > tbody > tr + tr > td { - border-color: rgba(255, 255, 255, 0.18); -} diff --git a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts index 5d5596f4588..ce64aefccc1 100644 --- a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts +++ b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts @@ -17,7 +17,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IRequestService, asText } from 'vs/platform/request/common/request'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IProductService } from 'vs/platform/product/common/productService'; -import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; +import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService'; import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; @@ -25,7 +25,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { generateUuid } from 'vs/base/common/uuid'; -import { renderMarkdownDocument } from 'vs/workbench/common/markdownDocumentRenderer'; +import { renderMarkdownDocument } from 'vs/workbench/contrib/markdown/common/markdownDocumentRenderer'; export class ReleaseNotesManager { @@ -43,7 +43,7 @@ export class ReleaseNotesManager { @ITelemetryService private readonly _telemetryService: ITelemetryService, @IEditorService private readonly _editorService: IEditorService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, - @IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService, + @IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService, @IExtensionService private readonly _extensionService: IExtensionService, @IProductService private readonly _productService: IProductService ) { @@ -71,9 +71,9 @@ export class ReleaseNotesManager { if (this._currentReleaseNotes) { this._currentReleaseNotes.setName(title); this._currentReleaseNotes.webview.html = html; - this._webviewEditorService.revealWebview(this._currentReleaseNotes, activeControl ? activeControl.group : this._editorGroupService.activeGroup, false); + this._webviewWorkbenchService.revealWebview(this._currentReleaseNotes, activeControl ? activeControl.group : this._editorGroupService.activeGroup, false); } else { - this._currentReleaseNotes = this._webviewEditorService.createWebview( + this._currentReleaseNotes = this._webviewWorkbenchService.createWebview( generateUuid(), 'releaseNotes', title, @@ -81,9 +81,7 @@ export class ReleaseNotesManager { { tryRestoreScrollPosition: true, enableFindWidget: true, - localResourceRoots: [ - URI.parse(require.toUrl('./media')) - ] + localResourceRoots: [] }, undefined); @@ -178,18 +176,146 @@ export class ReleaseNotesManager { } private async renderBody(text: string) { + const nonce = generateUuid(); const content = await renderMarkdownDocument(text, this._extensionService, this._modeService); const colorMap = TokenizationRegistry.getColorMap(); const css = colorMap ? generateTokensCSSForColorMap(colorMap) : ''; - const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-resource://'); return ` - - - + + ${content} `; diff --git a/src/vs/workbench/contrib/update/browser/update.contribution.ts b/src/vs/workbench/contrib/update/browser/update.contribution.ts index e4c1caf9409..b47e6b2ff04 100644 --- a/src/vs/workbench/contrib/update/browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/browser/update.contribution.ts @@ -8,14 +8,21 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution } from 'vs/workbench/contrib/update/browser/update'; +import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, CheckForVSCodeUpdateAction, CONTEXT_UPDATE_STATE } from 'vs/workbench/contrib/update/browser/update'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import product from 'vs/platform/product/common/product'; +import { StateType } from 'vs/platform/update/common/update'; const workbench = Registry.as(WorkbenchExtensions.Workbench); workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Restored); workbench.registerWorkbenchContribution(UpdateContribution, LifecyclePhase.Restored); +const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); + // Editor -Registry.as(ActionExtensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Release Notes'); +actionRegistry + .registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), `${product.nameShort}: Show Release Notes`, product.nameShort); + +actionRegistry + .registerWorkbenchAction(new SyncActionDescriptor(CheckForVSCodeUpdateAction, CheckForVSCodeUpdateAction.ID, CheckForVSCodeUpdateAction.LABEL), `${product.nameShort}: Check for Update`, product.nameShort, CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle)); diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index cce3046fad5..b28a46acb3d 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -26,11 +26,11 @@ import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/cont import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { FalseContext } from 'vs/platform/contextkey/common/contextkeys'; -import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { ShowCurrentReleaseNotesActionId, CheckForVSCodeUpdateActionId } from 'vs/workbench/contrib/update/common/update'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IProductService } from 'vs/platform/product/common/productService'; -const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Uninitialized); +export const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Idle); let releaseNotesManager: ReleaseNotesManager | undefined = undefined; @@ -99,7 +99,7 @@ export class ShowReleaseNotesAction extends AbstractShowReleaseNotesAction { export class ShowCurrentReleaseNotesAction extends AbstractShowReleaseNotesAction { static readonly ID = ShowCurrentReleaseNotesActionId; - static LABEL = nls.localize('showReleaseNotes', "Show Release Notes"); + static readonly LABEL = nls.localize('showReleaseNotes', "Show Release Notes"); constructor( id = ShowCurrentReleaseNotesAction.ID, @@ -122,44 +122,42 @@ export class ProductContribution implements IWorkbenchContribution { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IOpenerService openerService: IOpenerService, @IConfigurationService configurationService: IConfigurationService, - @IWindowService windowService: IWindowService, + @IHostService hostService: IHostService, @IProductService productService: IProductService ) { - windowService.isFocused().then(async isFocused => { - if (!isFocused) { - return; - } + if (!hostService.hasFocus) { + return; + } - const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); - const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); + const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); + const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); - // was there an update? if so, open release notes - const releaseNotesUrl = productService.releaseNotesUrl; - if (shouldShowReleaseNotes && !environmentService.skipReleaseNotes && releaseNotesUrl && lastVersion && productService.version !== lastVersion) { - showReleaseNotes(instantiationService, productService.version) - .then(undefined, () => { - notificationService.prompt( - severity.Info, - nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", productService.nameLong, productService.version), - [{ - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { - const uri = URI.parse(releaseNotesUrl); - openerService.open(uri); - } - }], - { sticky: true } - ); - }); - } + // was there an update? if so, open release notes + const releaseNotesUrl = productService.releaseNotesUrl; + if (shouldShowReleaseNotes && !environmentService.args['skip-release-notes'] && releaseNotesUrl && lastVersion && productService.version !== lastVersion) { + showReleaseNotes(instantiationService, productService.version) + .then(undefined, () => { + notificationService.prompt( + severity.Info, + nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", productService.nameLong, productService.version), + [{ + label: nls.localize('releaseNotes', "Release Notes"), + run: () => { + const uri = URI.parse(releaseNotesUrl); + openerService.open(uri); + } + }], + { sticky: true } + ); + }); + } - // should we show the new license? - if (productService.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(productService.version, '>=1.0.0')) { - notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", productService.licenseUrl)); - } + // should we show the new license? + if (productService.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(productService.version, '>=1.0.0')) { + notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", productService.licenseUrl)); + } - storageService.store(ProductContribution.KEY, productService.version, StorageScope.GLOBAL); - }); + storageService.store(ProductContribution.KEY, productService.version, StorageScope.GLOBAL); } } @@ -176,9 +174,9 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu @IDialogService private readonly dialogService: IDialogService, @IUpdateService private readonly updateService: IUpdateService, @IActivityService private readonly activityService: IActivityService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IProductService private readonly productService: IProductService + @IProductService private readonly productService: IProductService, + @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService ) { super(); this.state = updateService.state; @@ -214,7 +212,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu case StateType.Idle: if (state.error) { this.onError(state.error); - } else if (this.state.type === StateType.CheckingForUpdates && this.state.context && this.state.context.windowId === this.environmentService.configuration.windowId) { + } else if (this.state.type === StateType.CheckingForUpdates && this.state.context === this.workbenchEnvironmentService.configuration.sessionId) { this.onUpdateNotAvailable(); } break; @@ -397,7 +395,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu } private registerGlobalActivityActions(): void { - CommandsRegistry.registerCommand('update.check', () => this.updateService.checkForUpdates({ windowId: this.environmentService.configuration.windowId })); + CommandsRegistry.registerCommand('update.check', () => this.updateService.checkForUpdates(this.workbenchEnvironmentService.configuration.sessionId)); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '6_update', command: { @@ -465,9 +463,29 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu group: '6_update', command: { id: 'update.restart', - title: nls.localize('restartToUpdate', "Restart to Update") + title: nls.localize('restartToUpdate', "Restart to Update (1)") }, when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Ready) }); } } + +export class CheckForVSCodeUpdateAction extends Action { + + static readonly ID = CheckForVSCodeUpdateActionId; + static LABEL = nls.localize('checkForUpdates', "Check for Updates..."); + + constructor( + id: string, + label: string, + @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, + @IUpdateService private readonly updateService: IUpdateService, + ) { + super(id, label, undefined, true); + } + + run(): Promise { + return this.updateService.checkForUpdates(this.workbenchEnvironmentService.configuration.sessionId); + } +} + diff --git a/src/vs/workbench/contrib/update/common/update.ts b/src/vs/workbench/contrib/update/common/update.ts index 8fc0d5c041b..5b9303f6eac 100644 --- a/src/vs/workbench/contrib/update/common/update.ts +++ b/src/vs/workbench/contrib/update/common/update.ts @@ -3,4 +3,5 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export const ShowCurrentReleaseNotesActionId = 'update.showCurrentReleaseNotes'; \ No newline at end of file +export const ShowCurrentReleaseNotesActionId = 'update.showCurrentReleaseNotes'; +export const CheckForVSCodeUpdateActionId = 'update.checkForVSCodeUpdate'; \ No newline at end of file diff --git a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts deleted file mode 100644 index 26a9151d09c..00000000000 --- a/src/vs/workbench/contrib/update/electron-browser/update.contribution.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 platform from 'vs/base/common/platform'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { Win3264BitContribution } from 'vs/workbench/contrib/update/electron-browser/update'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; - -const workbench = Registry.as(WorkbenchExtensions.Workbench); - -if (platform.isWindows) { - if (process.arch === 'ia32') { - workbench.registerWorkbenchContribution(Win3264BitContribution, LifecyclePhase.Restored); - } -} diff --git a/src/vs/workbench/contrib/update/electron-browser/update.ts b/src/vs/workbench/contrib/update/electron-browser/update.ts deleted file mode 100644 index b8fbf48c2de..00000000000 --- a/src/vs/workbench/contrib/update/electron-browser/update.ts +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import severity from 'vs/base/common/severity'; -import product from 'vs/platform/product/common/product'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { INotificationService } from 'vs/platform/notification/common/notification'; - -export class Win3264BitContribution implements IWorkbenchContribution { - - private static readonly URL = 'https://code.visualstudio.com/updates/v1_15#_windows-64-bit'; - private static readonly INSIDER_URL = 'https://github.com/Microsoft/vscode-docs/blob/vnext/release-notes/v1_15.md#windows-64-bit'; - - constructor( - @INotificationService notificationService: INotificationService, - @IEnvironmentService environmentService: IEnvironmentService - ) { - if (environmentService.disableUpdates) { - return; - } - - const url = product.quality === 'insider' - ? Win3264BitContribution.INSIDER_URL - : Win3264BitContribution.URL; - - notificationService.prompt( - severity.Info, - nls.localize('64bitisavailable', "{0} for 64-bit Windows is now available! Click [here]({1}) to learn more.", product.nameShort, url), - [], - { - sticky: true, - neverShowAgain: { id: 'neverShowAgain:update/win32-64bits', isSecondary: true } - } - ); - } -} diff --git a/src/vs/workbench/contrib/url/common/trustedDomains.ts b/src/vs/workbench/contrib/url/common/trustedDomains.ts index 6df811c75d6..7c28ccf7ce8 100644 --- a/src/vs/workbench/contrib/url/common/trustedDomains.ts +++ b/src/vs/workbench/contrib/url/common/trustedDomains.ts @@ -76,6 +76,7 @@ export async function configureOpenerTrustedDomainsHandler( return trustedDomains; } if (pickedResult.id && trustedDomains.indexOf(pickedResult.id) === -1) { + storageService.remove('http.linkProtectionTrustedDomainsContent', StorageScope.GLOBAL); storageService.store( 'http.linkProtectionTrustedDomains', JSON.stringify([...trustedDomains, pickedResult.id]), diff --git a/src/vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider.ts b/src/vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider.ts index ba66812aab7..f38fa6ed583 100644 --- a/src/vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider.ts +++ b/src/vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider.ts @@ -7,17 +7,7 @@ import { Event } from 'vs/base/common/event'; import { parse } from 'vs/base/common/json'; import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { - FileDeleteOptions, - FileOverwriteOptions, - FileSystemProviderCapabilities, - FileType, - FileWriteOptions, - IFileService, - IFileSystemProvider, - IStat, - IWatchOptions -} from 'vs/platform/files/common/files'; +import { FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, FileWriteOptions, IFileService, IStat, IWatchOptions, IFileSystemProviderWithFileReadWriteCapability } from 'vs/platform/files/common/files'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -33,8 +23,7 @@ const TRUSTED_DOMAINS_STAT: IStat = { size: 0 }; -const CONFIG_HELP_TEXT_PRE = - `// Links matching one or more entries in the list below can be opened without link protection. +const CONFIG_HELP_TEXT_PRE = `// Links matching one or more entries in the list below can be opened without link protection. // The following examples show what entries can look like: // - "https://microsoft.com": Matches this specific domain using https // - "https://*.microsoft.com": Match all domains ending in "microsoft.com" using https @@ -76,7 +65,7 @@ function computeTrustedDomainContent(defaultTrustedDomains: string[], trustedDom return content; } -export class TrustedDomainsFileSystemProvider implements IFileSystemProvider, IWorkbenchContribution { +export class TrustedDomainsFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability, IWorkbenchContribution { readonly capabilities = FileSystemProviderCapabilities.FileReadWrite; readonly onDidChangeCapabilities = Event.None; @@ -95,23 +84,36 @@ export class TrustedDomainsFileSystemProvider implements IFileSystemProvider, IW } readFile(resource: URI): Promise { - const { defaultTrustedDomains, trustedDomains } = readTrustedDomains(this.storageService, this.productService); + let trustedDomainsContent = this.storageService.get( + 'http.linkProtectionTrustedDomainsContent', + StorageScope.GLOBAL + ); + + if ( + !trustedDomainsContent || + trustedDomainsContent.indexOf(CONFIG_HELP_TEXT_PRE) === -1 || + trustedDomainsContent.indexOf(CONFIG_HELP_TEXT_AFTER) === -1 + ) { + const { defaultTrustedDomains, trustedDomains } = readTrustedDomains(this.storageService, this.productService); + + trustedDomainsContent = computeTrustedDomainContent(defaultTrustedDomains, trustedDomains); + } - const trustedDomainsContent = computeTrustedDomainContent(defaultTrustedDomains, trustedDomains); const buffer = VSBuffer.fromString(trustedDomainsContent).buffer; return Promise.resolve(buffer); } writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { try { - const trustedDomains = parse(content.toString()); + const trustedDomainsContent = content.toString(); + const trustedDomains = parse(trustedDomainsContent); + this.storageService.store('http.linkProtectionTrustedDomainsContent', trustedDomainsContent, StorageScope.GLOBAL); this.storageService.store( 'http.linkProtectionTrustedDomains', - JSON.stringify(trustedDomains), + JSON.stringify(trustedDomains) || '', StorageScope.GLOBAL ); - } catch (err) { } return Promise.resolve(); diff --git a/src/vs/workbench/contrib/url/common/url.contribution.ts b/src/vs/workbench/contrib/url/common/url.contribution.ts index 4ba68ecd95b..86add42f8ce 100644 --- a/src/vs/workbench/contrib/url/common/url.contribution.ts +++ b/src/vs/workbench/contrib/url/common/url.contribution.ts @@ -35,7 +35,7 @@ export class OpenUrlAction extends Action { run(): Promise { return this.quickInputService.input({ prompt: 'URL to open' }).then(input => { const uri = URI.parse(input); - this.urlService.open(uri); + this.urlService.open(uri, { trusted: true }); }); } } @@ -54,7 +54,10 @@ CommandsRegistry.registerCommand(manageTrustedDomainSettingsCommand); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: manageTrustedDomainSettingsCommand.id, - title: manageTrustedDomainSettingsCommand.description.description + title: { + value: manageTrustedDomainSettingsCommand.description.description, + original: 'Manage Trusted Domains' + } } }); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts index ba89fb5267a..3fe61e9a7e5 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts @@ -4,31 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IUserDataSyncService, SyncStatus, SyncSource, CONTEXT_SYNC_STATE, registerConfiguration } from 'vs/platform/userDataSync/common/userDataSync'; -import { localize } from 'vs/nls'; -import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { registerConfiguration } from 'vs/platform/userDataSync/common/userDataSync'; +import { Disposable } from 'vs/base/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/actions'; -import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; -import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { URI } from 'vs/base/common/uri'; -import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; -import { ResourceContextKey } from 'vs/workbench/common/resources'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { Event } from 'vs/base/common/event'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { isEqual } from 'vs/base/common/resources'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { isWeb } from 'vs/base/common/platform'; import { UserDataAutoSync } from 'vs/platform/userDataSync/common/userDataSyncService'; import { IProductService } from 'vs/platform/product/common/productService'; +import { UserDataSyncWorkbenchContribution } from 'vs/workbench/contrib/userDataSync/browser/userDataSync'; class UserDataSyncConfigurationContribution implements IWorkbenchContribution { @@ -53,177 +37,8 @@ class UserDataAutoSyncContribution extends Disposable implements IWorkbenchContr } } -const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/check-light.svg`)); -const SYNC_PUSH_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/check-dark.svg`)); -class SyncActionsContribution extends Disposable implements IWorkbenchContribution { - - private readonly syncEnablementContext: IContextKey; - private readonly badgeDisposable = this._register(new MutableDisposable()); - private readonly conflictsWarningDisposable = this._register(new MutableDisposable()); - - constructor( - @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, - @IContextKeyService contextKeyService: IContextKeyService, - @IActivityService private readonly activityService: IActivityService, - @INotificationService private readonly notificationService: INotificationService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IEditorService private readonly editorService: IEditorService, - @ITextFileService private readonly textFileService: ITextFileService, - @IHistoryService private readonly historyService: IHistoryService, - @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, - ) { - super(); - this.syncEnablementContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService); - this.onDidChangeStatus(userDataSyncService.status); - this._register(Event.debounce(userDataSyncService.onDidChangeStatus, () => undefined, 500)(status => this.onDidChangeStatus(userDataSyncService.status))); - this.registerActions(); - } - - private onDidChangeStatus(status: SyncStatus) { - this.syncEnablementContext.set(status); - - let badge: IBadge | undefined = undefined; - let clazz: string | undefined; - - if (status === SyncStatus.HasConflicts) { - badge = new NumberBadge(1, () => localize('resolve conflicts', "Resolve Conflicts")); - } else if (status === SyncStatus.Syncing) { - badge = new ProgressBadge(() => localize('syncing', "Synchronising User Configuration...")); - clazz = 'progress-badge'; - } - - this.badgeDisposable.clear(); - - if (badge) { - this.badgeDisposable.value = this.activityService.showActivity(GLOBAL_ACTIVITY_ID, badge, clazz); - } - - if (status === SyncStatus.HasConflicts) { - if (!this.conflictsWarningDisposable.value) { - const handle = this.notificationService.prompt(Severity.Warning, localize('conflicts detected', "Unable to sync due to conflicts. Please resolve them to continue."), - [ - { - label: localize('resolve', "Resolve Conflicts"), - run: () => this.handleConflicts() - } - ]); - this.conflictsWarningDisposable.value = toDisposable(() => handle.close()); - handle.onDidClose(() => this.conflictsWarningDisposable.clear()); - } - } else { - this.conflictsWarningDisposable.clear(); - } - } - - private async continueSync(): Promise { - // Get the preview editor - const editorInput = this.editorService.editors.filter(input => isEqual(input.getResource(), this.workbenchEnvironmentService.settingsSyncPreviewResource))[0]; - // Save the preview - if (editorInput && editorInput.isDirty()) { - await this.textFileService.save(editorInput.getResource()!); - } - try { - // Continue Sync - await this.userDataSyncService.sync(true); - } catch (error) { - this.notificationService.error(error); - return; - } - // Close the preview editor - if (editorInput) { - editorInput.dispose(); - } - } - - private async handleConflicts(): Promise { - if (this.userDataSyncService.conflictsSource === SyncSource.Settings) { - const resourceInput = { - resource: this.workbenchEnvironmentService.settingsSyncPreviewResource, - options: { - preserveFocus: false, - pinned: false, - revealIfVisible: true, - }, - mode: 'jsonc' - }; - this.editorService.openEditor(resourceInput) - .then(editor => { - this.historyService.remove(resourceInput); - if (editor && editor.input) { - // Trigger sync after closing the conflicts editor. - const disposable = editor.input.onDispose(() => { - disposable.dispose(); - this.userDataSyncService.sync(true); - }); - } - }); - } - } - - private registerActions(): void { - - const startSyncMenuItem: IMenuItem = { - group: '5_sync', - command: { - id: 'workbench.userData.actions.syncStart', - title: localize('start sync', "Sync: Start") - }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not('config.userConfiguration.enableSync')), - }; - CommandsRegistry.registerCommand(startSyncMenuItem.command.id, () => this.configurationService.updateValue('userConfiguration.enableSync', true)); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, startSyncMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, startSyncMenuItem); - - const stopSyncMenuItem: IMenuItem = { - group: '5_sync', - command: { - id: 'workbench.userData.actions.stopSync', - title: localize('stop sync', "Sync: Stop") - }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has('config.userConfiguration.enableSync')), - }; - CommandsRegistry.registerCommand(stopSyncMenuItem.command.id, () => this.configurationService.updateValue('userConfiguration.enableSync', false)); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, stopSyncMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, stopSyncMenuItem); - - const resolveConflictsMenuItem: IMenuItem = { - group: '5_sync', - command: { - id: 'sync.resolveConflicts', - title: localize('resolveConflicts', "Sync: Resolve Conflicts"), - }, - when: CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), - }; - CommandsRegistry.registerCommand(resolveConflictsMenuItem.command.id, () => this.handleConflicts()); - MenuRegistry.appendMenuItem(MenuId.GlobalActivity, resolveConflictsMenuItem); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, resolveConflictsMenuItem); - - const continueSyncCommandId = 'workbench.userData.actions.continueSync'; - CommandsRegistry.registerCommand(continueSyncCommandId, () => this.continueSync()); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, { - command: { - id: continueSyncCommandId, - title: localize('continue sync', "Sync: Continue") - }, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts)), - }); - MenuRegistry.appendMenuItem(MenuId.EditorTitle, { - command: { - id: continueSyncCommandId, - title: localize('continue sync', "Sync: Continue"), - iconLocation: { - light: SYNC_PUSH_LIGHT_ICON_URI, - dark: SYNC_PUSH_DARK_ICON_URI - } - }, - group: 'navigation', - order: 1, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), ResourceContextKey.Resource.isEqualTo(this.workbenchEnvironmentService.settingsSyncPreviewResource.toString())), - }); - } -} const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(UserDataSyncConfigurationContribution, LifecyclePhase.Starting); -workbenchRegistry.registerWorkbenchContribution(SyncActionsContribution, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(UserDataSyncWorkbenchContribution, LifecyclePhase.Restored); workbenchRegistry.registerWorkbenchContribution(UserDataAutoSyncContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts new file mode 100644 index 00000000000..92cb1c09c88 --- /dev/null +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -0,0 +1,283 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IUserDataSyncService, SyncStatus, SyncSource, CONTEXT_SYNC_STATE } from 'vs/platform/userDataSync/common/userDataSync'; +import { localize } from 'vs/nls'; +import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/actions'; +import { IContextKeyService, IContextKey, ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; +import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { URI } from 'vs/base/common/uri'; +import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; +import { ResourceContextKey } from 'vs/workbench/common/resources'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { Event } from 'vs/base/common/event'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { isEqual } from 'vs/base/common/resources'; +import { IEditorInput } from 'vs/workbench/common/editor'; +import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { timeout } from 'vs/base/common/async'; + +const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey('authTokenStatus', AuthTokenStatus.Inactive); +const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/check-light.svg`)); +const SYNC_PUSH_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/check-dark.svg`)); + +export class UserDataSyncWorkbenchContribution extends Disposable implements IWorkbenchContribution { + + private readonly syncStatusContext: IContextKey; + private readonly authTokenContext: IContextKey; + private readonly badgeDisposable = this._register(new MutableDisposable()); + private readonly conflictsWarningDisposable = this._register(new MutableDisposable()); + private readonly signInNotificationDisposable = this._register(new MutableDisposable()); + + constructor( + @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, + @IAuthTokenService private readonly authTokenService: IAuthTokenService, + @IContextKeyService contextKeyService: IContextKeyService, + @IActivityService private readonly activityService: IActivityService, + @INotificationService private readonly notificationService: INotificationService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IEditorService private readonly editorService: IEditorService, + @ITextFileService private readonly textFileService: ITextFileService, + @IHistoryService private readonly historyService: IHistoryService, + @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + ) { + super(); + this.syncStatusContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService); + this.authTokenContext = CONTEXT_AUTH_TOKEN_STATE.bindTo(contextKeyService); + + this.onDidChangeAuthTokenStatus(this.authTokenService.status); + this.onDidChangeSyncStatus(this.userDataSyncService.status); + this._register(Event.debounce(authTokenService.onDidChangeStatus, () => undefined, 500)(() => this.onDidChangeAuthTokenStatus(this.authTokenService.status))); + this._register(Event.debounce(userDataSyncService.onDidChangeStatus, () => undefined, 500)(() => this.onDidChangeSyncStatus(this.userDataSyncService.status))); + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateBadge())); + this.registerActions(); + + timeout(2000).then(() => { + if (this.authTokenService.status === AuthTokenStatus.Inactive && configurationService.getValue('configurationSync.enable')) { + this.showSignInNotification(); + } + }); + } + + private onDidChangeAuthTokenStatus(status: AuthTokenStatus) { + this.authTokenContext.set(status); + if (status === AuthTokenStatus.Active) { + this.signInNotificationDisposable.clear(); + } + this.updateBadge(); + } + + private onDidChangeSyncStatus(status: SyncStatus) { + this.syncStatusContext.set(status); + + this.updateBadge(); + + if (this.userDataSyncService.status === SyncStatus.HasConflicts) { + if (!this.conflictsWarningDisposable.value) { + const handle = this.notificationService.prompt(Severity.Warning, localize('conflicts detected', "Unable to sync due to conflicts. Please resolve them to continue."), + [ + { + label: localize('resolve', "Resolve Conflicts"), + run: () => this.handleConflicts() + } + ]); + this.conflictsWarningDisposable.value = toDisposable(() => handle.close()); + handle.onDidClose(() => this.conflictsWarningDisposable.clear()); + } + } else { + const previewEditorInput = this.getPreviewEditorInput(); + if (previewEditorInput) { + previewEditorInput.dispose(); + } + this.conflictsWarningDisposable.clear(); + } + } + + private updateBadge(): void { + this.badgeDisposable.clear(); + + let badge: IBadge | undefined = undefined; + let clazz: string | undefined; + + if (this.authTokenService.status === AuthTokenStatus.Inactive && this.configurationService.getValue('configurationSync.enable')) { + badge = new NumberBadge(1, () => localize('sign in', "Sign in...")); + } else if (this.userDataSyncService.status === SyncStatus.HasConflicts) { + badge = new NumberBadge(1, () => localize('resolve conflicts', "Resolve Conflicts")); + } else if (this.userDataSyncService.status === SyncStatus.Syncing) { + badge = new ProgressBadge(() => localize('syncing', "Synchronizing User Configuration...")); + clazz = 'progress-badge'; + } + + if (badge) { + this.badgeDisposable.value = this.activityService.showActivity(GLOBAL_ACTIVITY_ID, badge, clazz); + } + } + + private showSignInNotification(): void { + const handle = this.notificationService.prompt(Severity.Info, localize('show sign in', "Please sign in to Settings Sync service to start syncing configuration."), + [ + { + label: localize('sign in', "Sign in..."), + run: () => this.signIn() + } + ]); + this.signInNotificationDisposable.value = toDisposable(() => handle.close()); + handle.onDidClose(() => this.signInNotificationDisposable.clear()); + } + + private async signIn(): Promise { + const token = await this.quickInputService.input({ placeHolder: localize('enter token', "Please provide the auth bearer token"), ignoreFocusLost: true, }); + if (token) { + await this.authTokenService.updateToken(token); + } + } + + private async signOut(): Promise { + await this.authTokenService.deleteToken(); + } + + private async continueSync(): Promise { + // Get the preview editor + const previewEditorInput = this.getPreviewEditorInput(); + // Save the preview + if (previewEditorInput && previewEditorInput.isDirty()) { + await this.textFileService.save(previewEditorInput.getResource()!); + } + try { + // Continue Sync + await this.userDataSyncService.sync(true); + } catch (error) { + this.notificationService.error(error); + return; + } + // Close the preview editor + if (previewEditorInput) { + previewEditorInput.dispose(); + } + } + + private getPreviewEditorInput(): IEditorInput | undefined { + return this.editorService.editors.filter(input => isEqual(input.getResource(), this.workbenchEnvironmentService.settingsSyncPreviewResource))[0]; + } + + private async handleConflicts(): Promise { + if (this.userDataSyncService.conflictsSource === SyncSource.Settings) { + const resourceInput = { + resource: this.workbenchEnvironmentService.settingsSyncPreviewResource, + options: { + preserveFocus: false, + pinned: false, + revealIfVisible: true, + }, + mode: 'jsonc' + }; + this.editorService.openEditor(resourceInput) + .then(editor => { + this.historyService.remove(resourceInput); + if (editor && editor.input) { + // Trigger sync after closing the conflicts editor. + const disposable = editor.input.onDispose(() => { + disposable.dispose(); + this.userDataSyncService.sync(true); + }); + } + }); + } + } + + private registerActions(): void { + + const signInMenuItem: IMenuItem = { + group: '5_sync', + command: { + id: 'workbench.userData.actions.login', + title: localize('sign in', "Sign in...") + }, + when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Inactive), ContextKeyExpr.has('config.configurationSync.enable')), + }; + CommandsRegistry.registerCommand(signInMenuItem.command.id, () => this.signIn()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signInMenuItem); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, signInMenuItem); + + const signOutMenuItem: IMenuItem = { + command: { + id: 'workbench.userData.actions.logout', + title: localize('sign out', "Sign Out") + }, + when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Active)), + }; + CommandsRegistry.registerCommand(signOutMenuItem.command.id, () => this.signOut()); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, signOutMenuItem); + + const startSyncMenuItem: IMenuItem = { + group: '5_sync', + command: { + id: 'workbench.userData.actions.syncStart', + title: localize('start sync', "Configuration Sync: Turn On") + }, + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.not('config.configurationSync.enable')), + }; + CommandsRegistry.registerCommand(startSyncMenuItem.command.id, () => this.configurationService.updateValue('configurationSync.enable', true)); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, startSyncMenuItem); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, startSyncMenuItem); + + const stopSyncMenuItem: IMenuItem = { + group: '5_sync', + command: { + id: 'workbench.userData.actions.stopSync', + title: localize('stop sync', "Configuration Sync: Turn Off") + }, + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), ContextKeyExpr.has('config.configurationSync.enable')), + }; + CommandsRegistry.registerCommand(stopSyncMenuItem.command.id, () => this.configurationService.updateValue('configurationSync.enable', false)); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, stopSyncMenuItem); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, stopSyncMenuItem); + + const resolveConflictsMenuItem: IMenuItem = { + group: '5_sync', + command: { + id: 'sync.resolveConflicts', + title: localize('resolveConflicts', "Configuration Sync: Resolve Conflicts"), + }, + when: CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), + }; + CommandsRegistry.registerCommand(resolveConflictsMenuItem.command.id, () => this.handleConflicts()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, resolveConflictsMenuItem); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, resolveConflictsMenuItem); + + const continueSyncCommandId = 'workbench.userData.actions.continueSync'; + CommandsRegistry.registerCommand(continueSyncCommandId, () => this.continueSync()); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: continueSyncCommandId, + title: localize('continue sync', "Configuration Sync: Continue") + }, + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts)), + }); + MenuRegistry.appendMenuItem(MenuId.EditorTitle, { + command: { + id: continueSyncCommandId, + title: localize('continue sync', "Configuration Sync: Continue"), + iconLocation: { + light: SYNC_PUSH_LIGHT_ICON_URI, + dark: SYNC_PUSH_DARK_ICON_URI + } + }, + group: 'navigation', + order: 1, + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), ResourceContextKey.Resource.isEqualTo(this.workbenchEnvironmentService.settingsSyncPreviewResource.toString())), + }); + } +} diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index e9a4d74f213..e68c960a1f4 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -28,6 +28,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; +import { assertIsDefined } from 'vs/base/common/types'; const $ = dom.$; @@ -122,7 +123,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr } private create(): void { - const container = this.layoutService.getContainer(Parts.EDITOR_PART); + const container = assertIsDefined(this.layoutService.getContainer(Parts.EDITOR_PART)); container.classList.add('has-watermark'); this.watermark = $('.watermark'); @@ -168,7 +169,9 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr this.watermark.remove(); const container = this.layoutService.getContainer(Parts.EDITOR_PART); - container.classList.remove('has-watermark'); + if (container) { + container.classList.remove('has-watermark'); + } this.watermarkDisposable.clear(); } diff --git a/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts b/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts new file mode 100644 index 00000000000..466e046411a --- /dev/null +++ b/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts @@ -0,0 +1,290 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { addClass } from 'vs/base/browser/dom'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { WebviewExtensionDescription, WebviewOptions, WebviewContentOptions } from 'vs/workbench/contrib/webview/browser/webview'; +import { URI } from 'vs/base/common/uri'; +import { areWebviewInputOptionsEqual } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService'; +import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/common/themeing'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + +export const enum WebviewMessageChannels { + onmessage = 'onmessage', + didClickLink = 'did-click-link', + didScroll = 'did-scroll', + didFocus = 'did-focus', + didBlur = 'did-blur', + doUpdateState = 'do-update-state', + doReload = 'do-reload', + loadResource = 'load-resource', + loadLocalhost = 'load-localhost', + webviewReady = 'webview-ready', +} + +interface IKeydownEvent { + key: string; + keyCode: number; + code: string; + shiftKey: boolean; + altKey: boolean; + ctrlKey: boolean; + metaKey: boolean; + repeat: boolean; +} + +interface WebviewContent { + readonly html: string; + readonly options: WebviewContentOptions; + readonly state: string | undefined; +} + +export abstract class BaseWebview extends Disposable { + + private _element: T | undefined; + protected get element(): T | undefined { return this._element; } + + private _focused: boolean | undefined; + protected get focused(): boolean { return !!this._focused; } + + private readonly _ready: Promise; + + protected content: WebviewContent; + + public extension: WebviewExtensionDescription | undefined; + + constructor( + // TODO: matb, this should not be protected. The only reason it needs to be is that the base class ends up using it in the call to createElement + protected readonly id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + private readonly webviewThemeDataProvider: WebviewThemeDataProvider, + @ITelemetryService private readonly _telemetryService: ITelemetryService, + @IEnvironmentService private readonly _environementService: IEnvironmentService, + @IWorkbenchEnvironmentService protected readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, + ) { + super(); + + this.content = { + html: '', + options: contentOptions, + state: undefined + }; + + this._element = this.createElement(options); + + this._ready = new Promise(resolve => { + const subscription = this._register(this.on(WebviewMessageChannels.webviewReady, () => { + if (this.element) { + addClass(this.element, 'ready'); + } + subscription.dispose(); + resolve(); + })); + }); + + this._register(this.on('no-csp-found', () => { + this.handleNoCspFound(); + })); + + this._register(this.on(WebviewMessageChannels.didClickLink, (uri: string) => { + this._onDidClickLink.fire(URI.parse(uri)); + })); + + this._register(this.on(WebviewMessageChannels.onmessage, (data: any) => { + this._onMessage.fire(data); + })); + + this._register(this.on(WebviewMessageChannels.didScroll, (scrollYPercentage: number) => { + this._onDidScroll.fire({ scrollYPercentage: scrollYPercentage }); + })); + + this._register(this.on(WebviewMessageChannels.doReload, () => { + this.reload(); + })); + + this._register(this.on(WebviewMessageChannels.doUpdateState, (state: any) => { + this.state = state; + this._onDidUpdateState.fire(state); + })); + + this._register(this.on(WebviewMessageChannels.didFocus, () => { + this.handleFocusChange(true); + })); + + this._register(this.on(WebviewMessageChannels.didBlur, () => { + this.handleFocusChange(false); + })); + + this._register(this.on('did-keydown', (data: KeyboardEvent) => { + // Electron: workaround for https://github.com/electron/electron/issues/14258 + // We have to detect keyboard events in the and dispatch them to our + // keybinding service because these events do not bubble to the parent window anymore. + this.handleKeyDown(data); + })); + + this.style(); + this._register(webviewThemeDataProvider.onThemeDataChanged(this.style, this)); + } + + dispose(): void { + if (this.element) { + this.element.remove(); + } + + this._element = undefined; + super.dispose(); + } + + private readonly _onMissingCsp = this._register(new Emitter()); + public readonly onMissingCsp = this._onMissingCsp.event; + + private readonly _onDidClickLink = this._register(new Emitter()); + public readonly onDidClickLink = this._onDidClickLink.event; + + private readonly _onMessage = this._register(new Emitter()); + public readonly onMessage = this._onMessage.event; + + private readonly _onDidScroll = this._register(new Emitter<{ readonly scrollYPercentage: number; }>()); + public readonly onDidScroll = this._onDidScroll.event; + + private readonly _onDidUpdateState = this._register(new Emitter()); + public readonly onDidUpdateState = this._onDidUpdateState.event; + + private readonly _onDidFocus = this._register(new Emitter()); + public readonly onDidFocus = this._onDidFocus.event; + + public sendMessage(data: any): void { + this._send('message', data); + } + + protected _send(channel: string, data?: any): void { + this._ready + .then(() => this.postMessage(channel, data)) + .catch(err => console.error(err)); + } + + protected abstract readonly extraContentOptions: { readonly [key: string]: string }; + + protected abstract createElement(options: WebviewOptions): T; + + protected abstract on(channel: string, handler: (data: T) => void): IDisposable; + + protected abstract postMessage(channel: string, data?: any): void; + + private _hasAlertedAboutMissingCsp = false; + private handleNoCspFound(): void { + if (this._hasAlertedAboutMissingCsp) { + return; + } + this._hasAlertedAboutMissingCsp = true; + + if (this.extension && this.extension.id) { + if (this._environementService.isExtensionDevelopment) { + this._onMissingCsp.fire(this.extension.id); + } + + type TelemetryClassification = { + extension?: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; }; + }; + type TelemetryData = { + extension?: string, + }; + + this._telemetryService.publicLog2('webviewMissingCsp', { + extension: this.extension.id.value + }); + } + } + + public reload(): void { + this.doUpdateContent(); + } + + public set html(value: string) { + this.content = { + html: value, + options: this.content.options, + state: this.content.state, + }; + this.doUpdateContent(); + } + + 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 state(state: string | undefined) { + this.content = { + html: this.content.html, + options: this.content.options, + state, + }; + } + + public set initialScrollProgress(value: number) { + this._send('initial-scroll-position', value); + } + + private doUpdateContent() { + this._send('content', { + contents: this.content.html, + options: this.content.options, + state: this.content.state, + ...this.extraContentOptions + }); + } + + protected style(): void { + const { styles, activeTheme } = this.webviewThemeDataProvider.getWebviewThemeData(); + this._send('styles', { styles, activeTheme }); + } + + protected handleFocusChange(isFocused: boolean): void { + this._focused = isFocused; + if (isFocused) { + this._onDidFocus.fire(); + } + } + + private handleKeyDown(event: IKeydownEvent) { + // Create a fake KeyboardEvent from the data provided + const emulatedKeyboardEvent = new KeyboardEvent('keydown', event); + // Force override the target + Object.defineProperty(emulatedKeyboardEvent, 'target', { + get: () => this.element, + }); + // And re-dispatch + window.dispatchEvent(emulatedKeyboardEvent); + } + + windowDidDragStart(): void { + // Webview break drag and droping around the main window (no events are generated when you are over them) + // Work around this by disabling pointer events during the drag. + // https://github.com/electron/electron/issues/18226 + if (this.element) { + this.element.style.pointerEvents = 'none'; + } + } + + windowDidDragEnd(): void { + if (this.element) { + this.element.style.pointerEvents = ''; + } + } +} diff --git a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts index d85e4df4791..945e6be9f4b 100644 --- a/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts +++ b/src/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts @@ -8,8 +8,8 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { IWebviewService, Webview, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; -import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; +import { IWebviewService, Webview, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions, WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview'; +import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { Dimension } from 'vs/base/browser/dom'; /** @@ -24,17 +24,25 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd private _html: string = ''; private _initialScrollProgress: number = 0; private _state: string | undefined = undefined; + private _extension: WebviewExtensionDescription | undefined; + + private _contentOptions: WebviewContentOptions; + private _options: WebviewOptions; + private _owner: any = undefined; public constructor( private readonly id: string, - public readonly options: WebviewOptions, - private _contentOptions: WebviewContentOptions, + initialOptions: WebviewOptions, + initialContentOptions: WebviewContentOptions, @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, @IWebviewService private readonly _webviewService: IWebviewService ) { super(); + this._options = initialOptions; + this._contentOptions = initialContentOptions; + this._register(toDisposable(() => this.container.remove())); } @@ -42,7 +50,12 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd public get container() { const container = document.createElement('div'); container.id = `webview-${this.id}`; - this._layoutService.getContainer(Parts.EDITOR_PART).appendChild(container); + container.style.visibility = 'hidden'; + + // Webviews cannot be reparented in the dom as it will destory their contents. + // Mount them to a high level node to avoid this. + this._layoutService.getWorkbenchElement().appendChild(container); + return container; } @@ -57,7 +70,7 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd } this._owner = undefined; this.container.style.visibility = 'hidden'; - if (!this.options.retainContextWhenHidden) { + if (!this._options.retainContextWhenHidden) { this._webview.clear(); this._webviewEvents.clear(); } @@ -78,30 +91,32 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd private show() { if (!this._webview.value) { - const webview = this._webviewService.createWebview(this.id, this.options, this._contentOptions); + const webview = this._webviewService.createWebview(this.id, this._options, this._contentOptions); this._webview.value = webview; webview.state = this._state; webview.html = this._html; - if (this.options.tryRestoreScrollPosition) { + webview.extension = this._extension; + if (this._options.tryRestoreScrollPosition) { webview.initialScrollProgress = this._initialScrollProgress; } this._webview.value.mountTo(this.container); + + // Forward events from inner webview to outer listeners this._webviewEvents.clear(); + this._webviewEvents.add(webview.onDidFocus(() => { this._onDidFocus.fire(); })); + this._webviewEvents.add(webview.onDidClickLink(x => { this._onDidClickLink.fire(x); })); + this._webviewEvents.add(webview.onMessage(x => { this._onMessage.fire(x); })); + this._webviewEvents.add(webview.onMissingCsp(x => { this._onMissingCsp.fire(x); })); - webview.onDidFocus(() => { this._onDidFocus.fire(); }, undefined, this._webviewEvents); - webview.onDidClickLink(x => { this._onDidClickLink.fire(x); }, undefined, this._webviewEvents); - webview.onMessage(x => { this._onMessage.fire(x); }, undefined, this._webviewEvents); - webview.onMissingCsp(x => { this._onMissingCsp.fire(x); }, undefined, this._webviewEvents); - - webview.onDidScroll(x => { + this._webviewEvents.add(webview.onDidScroll(x => { this._initialScrollProgress = x.scrollYPercentage; this._onDidScroll.fire(x); - }, undefined, this._webviewEvents); + })); - webview.onDidUpdateState(state => { + this._webviewEvents.add(webview.onDidUpdateState(state => { this._state = state; this._onDidUpdateState.fire(state); - }, undefined, this._webviewEvents); + })); this._pendingMessages.forEach(msg => webview.sendMessage(msg)); this._pendingMessages.clear(); @@ -127,12 +142,21 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd this.withWebview(webview => webview.state = value); } + public get options(): WebviewOptions { return this._options; } + public set options(value: WebviewOptions) { this._options = { customClasses: this._options.customClasses, ...value }; } + public get contentOptions(): WebviewContentOptions { return this._contentOptions; } public set contentOptions(value: WebviewContentOptions) { this._contentOptions = value; this.withWebview(webview => webview.contentOptions = value); } + public get extension() { return this._extension; } + public set extension(value) { + this._extension = value; + this.withWebview(webview => webview.extension = value); + } + private readonly _onDidFocus = this._register(new Emitter()); public readonly onDidFocus: Event = this._onDidFocus.event; @@ -159,15 +183,6 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd } } - update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean): void { - this._contentOptions = options; - this._html = html; - this.withWebview(webview => { - webview.update(html, options, retainContextWhenHidden); - }); - } - - layout(): void { this.withWebview(webview => webview.layout()); } focus(): void { this.withWebview(webview => webview.focus()); } reload(): void { this.withWebview(webview => webview.reload()); } showFind(): void { this.withWebview(webview => webview.showFind()); } @@ -183,4 +198,12 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd f(this._webview.value); } } + + windowDidDragStart() { + this.withWebview(webview => webview.windowDidDragStart()); + } + + windowDidDragEnd() { + this.withWebview(webview => webview.windowDidDragEnd()); + } } diff --git a/src/vs/workbench/contrib/webview/browser/pre/fake.html b/src/vs/workbench/contrib/webview/browser/pre/fake.html index e69de29bb2d..726a69397f8 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/fake.html +++ b/src/vs/workbench/contrib/webview/browser/pre/fake.html @@ -0,0 +1,11 @@ + + + + + + + Fake + + + + diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html index e301f5ea90d..f4ed4275956 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index.html @@ -3,7 +3,8 @@ - + Virtual Document diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index c97da43b4c5..138707c9a9b 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -91,6 +91,24 @@ border-color: var(--vscode-textBlockQuote-border); } + kbd { + color: var(--vscode-editor-foreground); + border-radius: 3px; + vertical-align: middle; + padding: 1px 3px; + + background-color: hsla(0,0%,50%,.17); + border: 1px solid rgba(71,71,71,.4); + border-bottom-color: rgba(88,88,88,.4); + box-shadow: inset 0 -1px 0 rgba(88,88,88,.4); + } + .vscode-light kbd { + background-color: hsla(0,0%,87%,.5); + border: 1px solid hsla(0,0%,80%,.7); + border-bottom-color: hsla(0,0%,73%,.7); + box-shadow: inset 0 -1px 0 hsla(0,0%,73%,.7); + } + ::-webkit-scrollbar { width: 10px; height: 10px; @@ -213,7 +231,8 @@ /** * @param {MouseEvent} event */ - const handleAuxClick = (event) => { + const handleAuxClick = + (event) => { // Prevent middle clicks opening a broken link in the browser if (!event.view || !event.view.document) { return; @@ -308,7 +327,12 @@ } else { // Rewrite vscode-resource in csp if (data.endpoint) { - csp.setAttribute('content', csp.getAttribute('content').replace(/vscode-resource:/g, data.endpoint)); + try { + const endpointUrl = new URL(data.endpoint); + csp.setAttribute('content', csp.getAttribute('content').replace(/vscode-resource:(?=(\s|;|$))/g, endpointUrl.origin)); + } catch (e) { + console.error('Could not rewrite csp'); + } } } @@ -409,19 +433,20 @@ newFrame.contentDocument.open(); } - 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); - } + // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=978325 + setTimeout(() => { + 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); + } + }, 0); }); const onLoad = (contentDocument, contentWindow) => { @@ -474,9 +499,11 @@ } }); - // Bubble out link clicks + // Bubble out various events newFrame.contentWindow.addEventListener('click', handleInnerClick); newFrame.contentWindow.addEventListener('auxclick', handleAuxClick); + newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown); + newFrame.contentWindow.addEventListener('contextmenu', e => e.preventDefault()); if (host.onIframeLoaded) { host.onIframeLoaded(newFrame); diff --git a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts index 1c5572ec400..2189e68d81f 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts @@ -19,7 +19,7 @@ import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, webviewDeveloperCategor import { HideWebViewEditorFindCommand, ReloadWebviewAction, ShowWebViewEditorFindWidgetCommand, WebViewEditorFindNextCommand, WebViewEditorFindPreviousCommand } from '../browser/webviewCommands'; import { WebviewEditor } from '../browser/webviewEditor'; import { WebviewInput } from '../browser/webviewEditorInput'; -import { IWebviewEditorService, WebviewEditorService } from '../browser/webviewEditorService'; +import { IWebviewWorkbenchService, WebviewEditorService } from './webviewWorkbenchService'; (Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor( WebviewEditor, @@ -31,7 +31,7 @@ Registry.as(EditorInputExtensions.EditorInputFactor WebviewEditorInputFactory.ID, WebviewEditorInputFactory); -registerSingleton(IWebviewEditorService, WebviewEditorService, true); +registerSingleton(IWebviewWorkbenchService, WebviewEditorService, true); const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); diff --git a/src/vs/workbench/contrib/webview/browser/webview.ts b/src/vs/workbench/contrib/webview/browser/webview.ts index 46635e42144..cf633fbc463 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.ts @@ -40,13 +40,8 @@ export interface IWebviewService { ): WebviewEditorOverlay; } -export const WebviewResourceScheme = 'vscode-resource'; - export interface WebviewOptions { - readonly extension?: { - readonly location: URI; - readonly id?: ExtensionIdentifier; - }; + readonly customClasses?: string; readonly enableFindWidget?: boolean; readonly tryRestoreScrollPosition?: boolean; readonly retainContextWhenHidden?: boolean; @@ -59,10 +54,16 @@ export interface WebviewContentOptions { readonly enableCommandUris?: boolean; } +export interface WebviewExtensionDescription { + readonly location: URI; + readonly id: ExtensionIdentifier; +} + export interface Webview extends IDisposable { html: string; contentOptions: WebviewContentOptions; + extension: WebviewExtensionDescription | undefined; initialScrollProgress: number; state: string | undefined; @@ -74,19 +75,16 @@ export interface Webview extends IDisposable { readonly onMissingCsp: Event; sendMessage(data: any): void; - update( - html: string, - options: WebviewContentOptions, - retainContextWhenHidden: boolean - ): void; - layout(): void; focus(): void; reload(): void; showFind(): void; hideFind(): void; runFindAction(previous: boolean): void; + + windowDidDragStart(): void; + windowDidDragEnd(): void; } export interface WebviewElement extends Webview { @@ -95,7 +93,7 @@ export interface WebviewElement extends Webview { export interface WebviewEditorOverlay extends Webview { readonly container: HTMLElement; - readonly options: WebviewOptions; + options: WebviewOptions; claim(owner: any): void; release(owner: any): void; diff --git a/src/vs/workbench/contrib/webview/browser/webviewCommands.ts b/src/vs/workbench/contrib/webview/browser/webviewCommands.ts index 62a3eecece5..bfde6b8520e 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewCommands.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewCommands.ts @@ -13,44 +13,32 @@ import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEdito export class ShowWebViewEditorFindWidgetCommand extends Command { public static readonly ID = 'editor.action.webvieweditor.showFind'; - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.showFind(); - } + public runCommand(accessor: ServicesAccessor): void { + getActiveWebviewEditor(accessor)?.showFind(); } } export class HideWebViewEditorFindCommand extends Command { public static readonly ID = 'editor.action.webvieweditor.hideFind'; - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.hideFind(); - } + public runCommand(accessor: ServicesAccessor): void { + getActiveWebviewEditor(accessor)?.hideFind(); } } export class WebViewEditorFindNextCommand extends Command { public static readonly ID = 'editor.action.webvieweditor.findNext'; - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.find(false); - } + public runCommand(accessor: ServicesAccessor): void { + getActiveWebviewEditor(accessor)?.find(false); } } export class WebViewEditorFindPreviousCommand extends Command { public static readonly ID = 'editor.action.webvieweditor.findPrevious'; - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.find(true); - } + public runCommand(accessor: ServicesAccessor): void { + getActiveWebviewEditor(accessor)?.find(true); } } export class ReloadWebviewAction extends Action { @@ -79,8 +67,8 @@ export class ReloadWebviewAction extends Action { } } -function getActiveWebviewEditor(accessor: ServicesAccessor): WebviewEditor | null { +export function getActiveWebviewEditor(accessor: ServicesAccessor): WebviewEditor | undefined { const editorService = accessor.get(IEditorService); - const activeControl = editorService.activeControl as WebviewEditor; - return activeControl.isWebviewEditor ? activeControl : null; + const activeControl = editorService.activeControl as WebviewEditor | undefined; + return activeControl?.isWebviewEditor ? activeControl : undefined; } diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts index c02b82b0095..a0e741c2917 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts @@ -6,22 +6,24 @@ import * as DOM from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; -import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { isWeb } from 'vs/base/common/platform'; 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 { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { EditorOptions, EditorInput } from 'vs/workbench/common/editor'; -import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; +import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; +import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, Webview, WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview'; -import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; +import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; export class WebviewEditor extends BaseEditor { - public static ID = 'WebviewEditor'; + public static readonly ID = 'WebviewEditor'; private readonly _scopedContextKeyService = this._register(new MutableDisposable()); private _findWidgetVisible: IContextKey; @@ -29,7 +31,7 @@ export class WebviewEditor extends BaseEditor { private _content?: HTMLElement; private _dimension?: DOM.Dimension; - private readonly _webviewFocusTrackerDisposables = this._register(new DisposableStore()); + private readonly _webviewVisibleDisposables = this._register(new DisposableStore()); private readonly _onFocusWindowHandler = this._register(new MutableDisposable()); private readonly _onDidFocusWebview = this._register(new Emitter()); @@ -38,10 +40,11 @@ export class WebviewEditor extends BaseEditor { constructor( @ITelemetryService telemetryService: ITelemetryService, @IThemeService themeService: IThemeService, + @IStorageService storageService: IStorageService, @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IEditorService private readonly _editorService: IEditorService, - @IWindowService private readonly _windowService: IWindowService, - @IStorageService storageService: IStorageService + @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, + @IHostService private readonly _hostService: IHostService, ) { super(WebviewEditor.ID, telemetryService, themeService, storageService); @@ -93,15 +96,14 @@ export class WebviewEditor extends BaseEditor { this._dimension = dimension; if (this.input && this.input instanceof WebviewInput) { this.synchronizeWebviewContainerDimensions(this.input.webview, dimension); - this.input.webview.layout(); } } public focus(): void { super.focus(); - if (!this._onFocusWindowHandler.value) { + if (!this._onFocusWindowHandler.value && !isWeb) { // Make sure we restore focus when switching back to a VS Code window - this._onFocusWindowHandler.value = this._windowService.onDidChangeFocus(focused => { + this._onFocusWindowHandler.value = this._hostService.onDidChangeFocus(focused => { if (focused && this._editorService.activeControl === this) { this.focus(); } @@ -117,22 +119,22 @@ export class WebviewEditor extends BaseEditor { } protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { - const webview = this.input && (this.input as WebviewInput).webview; - if (webview) { + if (this.input instanceof WebviewInput) { + const webview = this.input.webview; if (visible) { webview.claim(this); } else { webview.release(this); } - this.claimWebview(this.input as WebviewInput); + this.claimWebview(this.input); } - super.setEditorVisible(visible, group); } public clearInput() { if (this.input && this.input instanceof WebviewInput) { this.input.webview.release(this); + this._webviewVisibleDisposables.clear(); } super.clearInput(); @@ -177,8 +179,35 @@ export class WebviewEditor extends BaseEditor { this._content.setAttribute('aria-flowto', input.webview.container.id); } + this._webviewVisibleDisposables.clear(); + + // Webviews are not part of the normal editor dom, so we have to register our own drag and drop handler on them. + if (this._editorGroupsService instanceof EditorPart) { + this._webviewVisibleDisposables.add(this._editorGroupsService.createEditorDropTarget(input.webview.container, { + groupContainsPredicate: (group) => this.group?.id === group.group.id + })); + } + + this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.DRAG_START, () => { + if (this.input instanceof WebviewInput) { + this.input.webview.windowDidDragStart(); + } + })); + + const onDragEnd = () => { + if (this.input instanceof WebviewInput) { + this.input.webview.windowDidDragEnd(); + } + }; + this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.DRAG_END, onDragEnd)); + this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.MOUSE_MOVE, currentEvent => { + if (currentEvent.buttons === 0) { + onDragEnd(); + } + })); + this.synchronizeWebviewContainerDimensions(input.webview); - this.trackFocus(input.webview); + this._webviewVisibleDisposables.add(this.trackFocus(input.webview)); } private synchronizeWebviewContainerDimensions(webview: WebviewEditorOverlay, dimension?: DOM.Dimension) { @@ -187,15 +216,17 @@ export class WebviewEditor extends BaseEditor { } } - private trackFocus(webview: WebviewEditorOverlay): void { - this._webviewFocusTrackerDisposables.clear(); + private trackFocus(webview: WebviewEditorOverlay): IDisposable { + const store = new DisposableStore(); // Track focus in webview content const webviewContentFocusTracker = DOM.trackFocus(webview.container); - this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker); - this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker.onDidFocus(() => this._onDidFocusWebview.fire())); + store.add(webviewContentFocusTracker); + store.add(webviewContentFocusTracker.onDidFocus(() => this._onDidFocusWebview.fire())); // Track focus in webview element - this._webviewFocusTrackerDisposables.add(webview.onDidFocus(() => this._onDidFocusWebview.fire())); + store.add(webview.onDidFocus(() => this._onDidFocusWebview.fire())); + + return store; } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts index d89a890249f..1a6bee73161 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.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. *--------------------------------------------------------------------------------------------*/ + import * as dom from 'vs/base/browser/dom'; import { memoize } from 'vs/base/common/decorators'; +import { Lazy } from 'vs/base/common/lazy'; +import { UnownedDisposable as Unowned } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IEditorModel } from 'vs/platform/editor/common/editor'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { EditorInput, EditorModel, GroupIdentifier, IEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview'; -import { UnownedDisposable as Unowned } from 'vs/base/common/lifecycle'; const WebviewPanelResourceScheme = 'webview-panel'; class WebviewIconsManager { private readonly _icons = new Map(); + @memoize private get _styleElement(): HTMLStyleElement { const element = dom.createStyleSheet(); @@ -25,7 +28,8 @@ class WebviewIconsManager { public setIcons( webviewId: string, - iconPath: { light: URI, dark: URI } | undefined + iconPath: { light: URI, dark: URI } | undefined, + lifecycleService: ILifecycleService, ) { if (iconPath) { this._icons.set(webviewId, iconPath); @@ -33,22 +37,27 @@ class WebviewIconsManager { this._icons.delete(webviewId); } - this.updateStyleSheet(); + this.updateStyleSheet(lifecycleService); } - 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: ${dom.asCSSUrl(value)}; }`); - } - else { - cssRules.push(`.vs ${webviewSelector} { content: ""; background-image: ${dom.asCSSUrl(value.light)}; }`); - cssRules.push(`.vs-dark ${webviewSelector} { content: ""; background-image: ${dom.asCSSUrl(value.dark)}; }`); - } - }); - this._styleElement.innerHTML = cssRules.join('\n'); + private async updateStyleSheet(lifecycleService: ILifecycleService, ) { + await lifecycleService.when(LifecyclePhase.Starting); + + try { + 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: ${dom.asCSSUrl(value)}; }`); + } else { + cssRules.push(`.vs ${webviewSelector} { content: ""; background-image: ${dom.asCSSUrl(value.light)}; }`); + cssRules.push(`.vs-dark ${webviewSelector} { content: ""; background-image: ${dom.asCSSUrl(value.dark)}; }`); + } + }); + this._styleElement.innerHTML = cssRules.join('\n'); + } catch { + // noop + } } } @@ -61,24 +70,20 @@ export class WebviewInput extends EditorInput { private _name: string; private _iconPath?: { light: URI, dark: URI }; private _group?: GroupIdentifier; - private readonly _webview: WebviewEditorOverlay; + private readonly _webview: Lazy; constructor( public readonly id: string, public readonly viewType: string, name: string, - public readonly extension: undefined | { - readonly location: URI; - readonly id: ExtensionIdentifier; - }, - webview: Unowned + webview: Lazy>, + @ILifecycleService private readonly lifecycleService: ILifecycleService, ) { super(); this._name = name; - this.extension = extension; - this._webview = this._register(webview.acquire()); // The input owns this webview + this._webview = webview.map(value => this._register(value.acquire())); // The input owns this webview } public getTypeId(): string { @@ -100,7 +105,7 @@ export class WebviewInput extends EditorInput { return this.getName(); } - public getDescription() { + public getDescription(): string | undefined { return undefined; } @@ -109,8 +114,12 @@ export class WebviewInput extends EditorInput { this._onDidChangeLabel.fire(); } - public get webview() { - return this._webview; + public get webview(): WebviewEditorOverlay { + return this._webview.getValue(); + } + + public get extension() { + return this._webview.getValue().extension; } public get iconPath() { @@ -119,7 +128,7 @@ export class WebviewInput extends EditorInput { public set iconPath(value: { light: URI, dark: URI } | undefined) { this._iconPath = value; - WebviewInput.iconsManager.setIcons(this.id, value); + WebviewInput.iconsManager.setIcons(this.id, value, this.lifecycleService); } public matches(other: IEditorInput): boolean { @@ -130,6 +139,10 @@ export class WebviewInput extends EditorInput { return this._group; } + public updateGroup(group: GroupIdentifier): void { + this._group = group; + } + public async resolve(): Promise { return new EditorModel(); } @@ -137,34 +150,4 @@ export class WebviewInput extends EditorInput { public supportsSplitEditor() { return false; } - - public updateGroup(group: GroupIdentifier): void { - this._group = group; - } -} - -export class RevivedWebviewEditorInput extends WebviewInput { - private _revived: boolean = false; - - constructor( - id: string, - viewType: string, - name: string, - extension: undefined | { - readonly location: URI; - readonly id: ExtensionIdentifier - }, - private readonly reviver: (input: WebviewInput) => Promise, - webview: Unowned - ) { - super(id, viewType, name, extension, webview); - } - - public async resolve(): Promise { - if (!this._revived) { - this._revived = true; - await this.reviver(this); - } - return super.resolve(); - } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts index 288c2c9e537..50150f357de 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts @@ -9,7 +9,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorInputFactory } from 'vs/workbench/common/editor'; import { WebviewInput } from './webviewEditorInput'; -import { IWebviewEditorService, WebviewInputOptions } from './webviewEditorService'; +import { IWebviewWorkbenchService, WebviewInputOptions } from './webviewWorkbenchService'; interface SerializedIconPath { light: string | UriComponents; @@ -33,11 +33,11 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { public static readonly ID = WebviewInput.typeId; public constructor( - @IWebviewEditorService private readonly _webviewService: IWebviewEditorService + @IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService ) { } public serialize(input: WebviewInput): string | undefined { - if (!this._webviewService.shouldPersist(input)) { + if (!this._webviewWorkbenchService.shouldPersist(input)) { return undefined; } @@ -54,7 +54,7 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { serializedEditorInput: string ): WebviewInput { const data = this.fromJson(serializedEditorInput); - return this._webviewService.reviveWebview(data.id || generateUuid(), data.viewType, data.title, data.iconPath, data.state, data.options, data.extensionLocation ? { + return this._webviewWorkbenchService.reviveWebview(data.id || generateUuid(), data.viewType, data.title, data.iconPath, data.state, data.options, data.extensionLocation && data.extensionId ? { location: data.extensionLocation, id: data.extensionId } : undefined, data.group); diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index db8dca5e362..d4926d849b4 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -3,148 +3,74 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { addClass, addDisposableListener } from 'vs/base/browser/dom'; -import { Emitter } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { addDisposableListener } from 'vs/base/browser/dom'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; -import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; -import { areWebviewInputOptionsEqual } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping'; import { loadLocalResource } from 'vs/workbench/contrib/webview/common/resourceLoader'; -import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing'; +import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/common/themeing'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { BaseWebview, WebviewMessageChannels } from 'vs/workbench/contrib/webview/browser/baseWebviewElement'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -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; - +export class IFrameWebview extends BaseWebview implements Webview { private readonly _portMappingManager: WebviewPortMappingManager; constructor( - private readonly id: string, - private _options: WebviewOptions, + id: string, + options: WebviewOptions, contentOptions: WebviewContentOptions, - @IThemeService themeService: IThemeService, + webviewThemeDataProvider: WebviewThemeDataProvider, @ITunnelService tunnelService: ITunnelService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IFileService private readonly fileService: IFileService, @IConfigurationService private readonly _configurationService: IConfigurationService, + @ITelemetryService telemetryService: ITelemetryService, + @IEnvironmentService environementService: IEnvironmentService, + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { - super(); - if (!this.useExternalEndpoint && (!environmentService.options || typeof environmentService.webviewExternalEndpoint !== 'string')) { + super(id, options, contentOptions, webviewThemeDataProvider, telemetryService, environementService, workbenchEnvironmentService); + + if (!this.useExternalEndpoint && (!workbenchEnvironmentService.options || typeof workbenchEnvironmentService.webviewExternalEndpoint !== 'string')) { throw new Error('To use iframe based webviews, you must configure `environmentService.webviewExternalEndpoint`'); } this._portMappingManager = this._register(new WebviewPortMappingManager( - this._options.extension ? this._options.extension.location : undefined, + () => this.extension ? this.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.externalEndpoint}/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._register(this.on(WebviewMessageChannels.loadResource, (entry: any) => { + const rawPath = entry.path; + const normalizedPath = decodeURIComponent(rawPath); + const uri = URI.parse(normalizedPath.replace(/^\/(\w+)\/(.+)$/, (_, scheme, path) => scheme + ':/' + path)); + this.loadResource(rawPath, uri); })); - 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._register(this.on(WebviewMessageChannels.loadLocalhost, (entry: any) => { + this.localLocalhost(entry.origin); + })); + } - this.style(themeService.getTheme()); - this._register(themeService.onThemeChange(this.style, this)); + protected createElement(options: WebviewOptions) { + const element = document.createElement('iframe'); + element.className = `webview ${options.customClasses || ''}`; + element.sandbox.add('allow-scripts', 'allow-same-origin'); + element.setAttribute('src', `${this.externalEndpoint}/index.html?id=${this.id}`); + element.style.border = 'none'; + element.style.width = '100%'; + element.style.height = '100%'; + return element; } private get externalEndpoint(): string { - const endpoint = this.environmentService.webviewExternalEndpoint!.replace('{{uuid}}', this.id); + const endpoint = this.workbenchEnvironmentService.webviewExternalEndpoint!.replace('{{uuid}}', this.id); if (endpoint[endpoint.length - 1] === '/') { return endpoint.slice(0, endpoint.length - 1); } @@ -161,111 +87,32 @@ export class IFrameWebview extends Disposable implements Webview { } } - 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(); + super.html = this.preprocessHtml(value); } private preprocessHtml(value: string): string { - return value.replace(/(["'])vscode-resource:([^\s'"]+?)(["'])/gi, (_, startQuote, path, endQuote) => - `${startQuote}${this.externalEndpoint}/vscode-resource${path}${endQuote}`); + return value + .replace(/(["'])vscode-resource:(\/\/([^\s\/'"]+?)(?=\/))?([^\s'"]+?)(["'])/gi, (match, startQuote, _1, scheme, path, endQuote) => { + if (scheme) { + return `${startQuote}${this.externalEndpoint}/vscode-resource/${scheme}${path}${endQuote}`; + } + return `${startQuote}${this.externalEndpoint}/vscode-resource/file${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, + protected get extraContentOptions() { + return { endpoint: this.externalEndpoint, - }); - } - - private handleFocusChange(isFocused: boolean): void { - this._focused = isFocused; - if (this._focused) { - this._onDidFocus.fire(); - } - } - - initialScrollProgress: number = 0; - - 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; - - private readonly _onMissingCsp = this._register(new Emitter()); - public readonly onMissingCsp = this._onMissingCsp.event; - - - sendMessage(data: any): void { - this._send('message', data); - } - - layout(): void { - // noop + }; } focus(): void { if (this.element) { - this.element.focus(); + this._send('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.'); } @@ -278,36 +125,9 @@ export class IFrameWebview extends Disposable implements Webview { 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, + const result = await loadLocalResource(uri, this.fileService, this.extension ? this.extension.location : undefined, () => (this.content.options.localResourceRoots || [])); if (result.type === 'success') { @@ -324,7 +144,7 @@ export class IFrameWebview extends Disposable implements Webview { return this._send('did-load-resource', { status: 404, - path: uri.path + path: requestPath }); } @@ -335,4 +155,21 @@ export class IFrameWebview extends Disposable implements Webview { location: redirect }); } + + protected postMessage(channel: string, data?: any): void { + if (this.element) { + this.element.contentWindow!.postMessage({ channel, args: data }, '*'); + } + } + + protected on(channel: WebviewMessageChannels, handler: (data: T) => void): IDisposable { + return addDisposableListener(window, 'message', e => { + if (!e || !e.data || e.data.target !== this.id) { + return; + } + if (e.data.channel === channel) { + handler(e.data.data); + } + }); + } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts index 21333aca8bc..44610b046b8 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewService.ts @@ -3,25 +3,30 @@ * 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/browser/webview'; -import { DynamicWebviewEditorOverlay } from './dynamicWebviewEditorOverlay'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; +import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/common/themeing'; +import { DynamicWebviewEditorOverlay } from './dynamicWebviewEditorOverlay'; export class WebviewService implements IWebviewService { _serviceBrand: undefined; + private readonly _webviewThemeDataProvider: WebviewThemeDataProvider; + constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, - ) { } + ) { + this._webviewThemeDataProvider = this._instantiationService.createInstance(WebviewThemeDataProvider); + } createWebview( id: string, options: WebviewOptions, contentOptions: WebviewContentOptions ): WebviewElement { - return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions); + return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions, this._webviewThemeDataProvider); } createWebviewEditorOverlay( diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts b/src/vs/workbench/contrib/webview/browser/webviewWorkbenchService.ts similarity index 67% rename from src/vs/workbench/contrib/webview/browser/webviewEditorService.ts rename to src/vs/workbench/contrib/webview/browser/webviewWorkbenchService.ts index f1f379dd0ef..ee635fbe60a 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewWorkbenchService.ts @@ -4,85 +4,29 @@ *--------------------------------------------------------------------------------------------*/ import { equals } from 'vs/base/common/arrays'; +import { memoize } from 'vs/base/common/decorators'; +import { Lazy } from 'vs/base/common/lazy'; import { IDisposable, toDisposable, UnownedDisposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; +import { isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { EditorActivation, IEditorModel } from 'vs/platform/editor/common/editor'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { GroupIdentifier } from 'vs/workbench/common/editor'; -import { IWebviewService, WebviewOptions, WebviewContentOptions } from 'vs/workbench/contrib/webview/browser/webview'; +import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/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, WebviewInput } from './webviewEditorInput'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { EditorActivation } from 'vs/platform/editor/common/editor'; +import { WebviewInput } from './webviewEditorInput'; -export const IWebviewEditorService = createDecorator('webviewEditorService'); +export const IWebviewWorkbenchService = createDecorator('webviewEditorService'); export interface ICreateWebViewShowOptions { group: IEditorGroup | GroupIdentifier | ACTIVE_GROUP_TYPE | SIDE_GROUP_TYPE; preserveFocus: boolean; } -export interface IWebviewEditorService { - _serviceBrand: undefined; - - createWebview( - id: string, - viewType: string, - title: string, - showOptions: ICreateWebViewShowOptions, - options: WebviewInputOptions, - extension: undefined | { - location: URI, - id: ExtensionIdentifier - }, - ): WebviewInput; - - reviveWebview( - id: string, - viewType: string, - title: string, - iconPath: { light: URI, dark: URI } | undefined, - state: any, - options: WebviewInputOptions, - extension: undefined | { - readonly location: URI, - readonly id?: ExtensionIdentifier - }, - group: number | undefined - ): WebviewInput; - - revealWebview( - webview: WebviewInput, - group: IEditorGroup, - preserveFocus: boolean - ): void; - - registerResolver( - reviver: WebviewResolve - ): IDisposable; - - shouldPersist( - input: WebviewInput - ): boolean; - - resolveWebview( - webview: WebviewInput, - ): Promise; -} - -export interface WebviewResolve { - canResolve( - webview: WebviewInput, - ): boolean; - - resolveWebview( - webview: WebviewInput, - ): Promise; -} - export interface WebviewInputOptions extends WebviewOptions, WebviewContentOptions { readonly tryRestoreScrollPosition?: boolean; readonly retainContextWhenHidden?: boolean; @@ -95,17 +39,90 @@ export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewIn && 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.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort))); + && equals(a.localResourceRoots, b.localResourceRoots, isEqual) + && equals(a.portMapping, b.portMapping, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort); } -function canRevive(reviver: WebviewResolve, webview: WebviewInput): boolean { +export interface IWebviewWorkbenchService { + _serviceBrand: undefined; + + createWebview( + id: string, + viewType: string, + title: string, + showOptions: ICreateWebViewShowOptions, + options: WebviewInputOptions, + extension: WebviewExtensionDescription | undefined, + ): WebviewInput; + + reviveWebview( + id: string, + viewType: string, + title: string, + iconPath: { light: URI, dark: URI } | undefined, + state: any, + options: WebviewInputOptions, + extension: WebviewExtensionDescription | undefined, + group: number | undefined + ): WebviewInput; + + revealWebview( + webview: WebviewInput, + group: IEditorGroup, + preserveFocus: boolean + ): void; + + registerResolver( + resolver: WebviewResolver + ): IDisposable; + + shouldPersist( + input: WebviewInput + ): boolean; + + resolveWebview( + webview: WebviewInput, + ): Promise; +} + +export interface WebviewResolver { + canResolve( + webview: WebviewInput, + ): boolean; + + resolveWebview( + webview: WebviewInput, + ): Promise; +} + +function canRevive(reviver: WebviewResolver, webview: WebviewInput): boolean { if (webview.isDisposed()) { return false; } return reviver.canResolve(webview); } + +export class LazilyResolvedWebviewEditorInput extends WebviewInput { + constructor( + id: string, + viewType: string, + name: string, + webview: Lazy>, + @IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService, + @ILifecycleService lifeCycleService: ILifecycleService, + ) { + super(id, viewType, name, webview, lifeCycleService); + } + + @memoize + public async resolve(): Promise { + await this._webviewWorkbenchService.resolveWebview(this); + return super.resolve(); + } +} + + class RevivalPool { private _awaitingRevival: Array<{ input: WebviewInput, resolve: () => void }> = []; @@ -113,7 +130,7 @@ class RevivalPool { this._awaitingRevival.push({ input, resolve }); } - public reviveFor(reviver: WebviewResolve) { + public reviveFor(reviver: WebviewResolver) { const toRevive = this._awaitingRevival.filter(({ input }) => canRevive(reviver, input)); this._awaitingRevival = this._awaitingRevival.filter(({ input }) => !canRevive(reviver, input)); @@ -123,18 +140,17 @@ class RevivalPool { } } -export class WebviewEditorService implements IWebviewEditorService { +export class WebviewEditorService implements IWebviewWorkbenchService { _serviceBrand: undefined; - private readonly _revivers = new Set(); + private readonly _revivers = new Set(); private readonly _revivalPool = new RevivalPool(); constructor( + @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, @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( @@ -143,14 +159,10 @@ export class WebviewEditorService implements IWebviewEditorService { title: string, showOptions: ICreateWebViewShowOptions, options: WebviewInputOptions, - extension: undefined | { - location: URI, - id: ExtensionIdentifier - }, + extension: WebviewExtensionDescription | undefined, ): WebviewInput { - const webview = this.createWebiew(id, extension, options); - - const webviewInput = this._instantiationService.createInstance(WebviewInput, id, viewType, title, extension, new UnownedDisposable(webview), undefined); + const webview = new Lazy(() => new UnownedDisposable(this.createWebiew(id, extension, options))); + const webviewInput = this._instantiationService.createInstance(WebviewInput, id, viewType, title, webview); this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus, @@ -188,28 +200,16 @@ export class WebviewEditorService implements IWebviewEditorService { iconPath: { light: URI, dark: URI } | undefined, state: any, options: WebviewInputOptions, - extension: undefined | { - readonly location: URI, - readonly id: ExtensionIdentifier - }, + extension: WebviewExtensionDescription | undefined, group: number | undefined, ): WebviewInput { - const webview = this.createWebiew(id, extension, options); - webview.state = state; - - const webviewInput = new RevivedWebviewEditorInput(id, viewType, title, extension, async (webview: WebviewInput): Promise => { - const didRevive = await this.tryRevive(webview); - if (didRevive) { - return Promise.resolve(undefined); - } - - // A reviver may not be registered yet. Put into pool and resolve promise when we can revive - let resolve: () => void; - const promise = new Promise(r => { resolve = r; }); - this._revivalPool.add(webview, resolve!); - return promise; - }, new UnownedDisposable(webview)); + const webview = new Lazy(() => { + const webview = this.createWebiew(id, extension, options); + webview.state = state; + return new UnownedDisposable(webview); + }); + const webviewInput = this._instantiationService.createInstance(LazilyResolvedWebviewEditorInput, id, viewType, title, webview); webviewInput.iconPath = iconPath; if (typeof group === 'number') { @@ -219,7 +219,7 @@ export class WebviewEditorService implements IWebviewEditorService { } public registerResolver( - reviver: WebviewResolve + reviver: WebviewResolver ): IDisposable { this._revivers.add(reviver); this._revivalPool.reviveFor(reviver); @@ -238,7 +238,7 @@ export class WebviewEditorService implements IWebviewEditorService { // Revived webviews may not have an actively registered reviver but we still want to presist them // since a reviver should exist when it is actually needed. - return webview instanceof RevivedWebviewEditorInput; + return webview instanceof LazilyResolvedWebviewEditorInput; } private async tryRevive( @@ -258,31 +258,22 @@ export class WebviewEditorService implements IWebviewEditorService { ): Promise { const didRevive = await this.tryRevive(webview); if (!didRevive) { - this._revivalPool.add(webview, () => { }); + // A reviver may not be registered yet. Put into pool and resolve promise when we can revive + let resolve: () => void; + const promise = new Promise(r => { resolve = r; }); + this._revivalPool.add(webview, resolve!); + return promise; } } - private createWebiew(id: string, extension: { location: URI; id: ExtensionIdentifier; } | undefined, options: WebviewInputOptions) { - return this._webviewService.createWebviewEditorOverlay(id, { - extension: extension, + private createWebiew(id: string, extension: WebviewExtensionDescription | undefined, options: WebviewInputOptions) { + const webview = this._webviewService.createWebviewEditorOverlay(id, { 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; + }, options); + webview.extension = extension; + return webview; } } -registerSingleton(IWebviewEditorService, WebviewEditorService, true); +registerSingleton(IWebviewWorkbenchService, WebviewEditorService, true); diff --git a/src/vs/workbench/contrib/webview/common/portMapping.ts b/src/vs/workbench/contrib/webview/common/portMapping.ts index 30041eb213b..69c216631ba 100644 --- a/src/vs/workbench/contrib/webview/common/portMapping.ts +++ b/src/vs/workbench/contrib/webview/common/portMapping.ts @@ -14,7 +14,7 @@ export class WebviewPortMappingManager extends Disposable { private readonly _tunnels = new Map>(); constructor( - private readonly extensionLocation: URI | undefined, + private readonly getExtensionLocation: () => URI | undefined, private readonly mappings: () => ReadonlyArray, private readonly tunnelService: ITunnelService ) { @@ -30,9 +30,13 @@ export class WebviewPortMappingManager extends Disposable { for (const mapping of this.mappings()) { if (mapping.webviewPort === requestLocalHostInfo.port) { - if (this.extensionLocation && this.extensionLocation.scheme === REMOTE_HOST_SCHEME) { + const extensionLocation = this.getExtensionLocation(); + if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) { const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort); if (tunnel) { + if (tunnel.tunnelLocalPort === mapping.webviewPort) { + return undefined; + } return encodeURI(uri.with({ authority: `127.0.0.1:${tunnel.tunnelLocalPort}`, }).toString(true)); diff --git a/src/vs/workbench/contrib/webview/common/resourceLoader.ts b/src/vs/workbench/contrib/webview/common/resourceLoader.ts index ea33db2e268..c0915591caf 100644 --- a/src/vs/workbench/contrib/webview/common/resourceLoader.ts +++ b/src/vs/workbench/contrib/webview/common/resourceLoader.ts @@ -11,6 +11,8 @@ 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'; +export const WebviewResourceScheme = 'vscode-resource'; + class Success { readonly type = 'success'; @@ -45,11 +47,7 @@ export async function loadLocalResource( extensionLocation: URI | undefined, getRoots: () => ReadonlyArray ): Promise { - const normalizedPath = requestUri.with({ - scheme: 'file', - fragment: '', - query: '', - }); + const normalizedPath = normalizeRequestPath(requestUri); for (const root of getRoots()) { if (!containsResource(root, normalizedPath)) { @@ -62,7 +60,7 @@ export async function loadLocalResource( authority: extensionLocation.authority, path: '/vscode-resource', query: JSON.stringify({ - requestResourcePath: requestUri.path + requestResourcePath: normalizedPath.path }) }); return resolveContent(fileService, redirectedUri, getWebviewContentMimeType(requestUri)); @@ -74,6 +72,21 @@ export async function loadLocalResource( return AccessDenied; } +function normalizeRequestPath(requestUri: URI) { + if (requestUri.scheme !== WebviewResourceScheme) { + return requestUri; + } + + // Modern vscode-resources uris put the scheme of the requested resource as the authority + if (requestUri.authority) { + return URI.parse(requestUri.authority + ':' + requestUri.path); + } + + // Old style vscode-resource uris lose the scheme of the resource which means they are unable to + // load a mix of local and remote content properly. + return requestUri.with({ scheme: 'file' }); +} + 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 index 7c39b7a4bdd..9b2684fd3ae 100644 --- a/src/vs/workbench/contrib/webview/common/themeing.ts +++ b/src/vs/workbench/contrib/webview/common/themeing.ts @@ -3,45 +3,83 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { createMemoizer } from 'vs/base/common/decorators'; +import { Disposable } from 'vs/base/common/lifecycle'; 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'; +import { DARK, ITheme, IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; +import { Emitter } from 'vs/base/common/event'; interface WebviewThemeData { readonly activeTheme: string; - readonly styles: { readonly [key: string]: string | number }; + 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; +export class WebviewThemeDataProvider extends Disposable { - 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 - }; + private static readonly MEMOIZER = createMemoizer(); - const activeTheme = ApiThemeClassName.fromTheme(theme); - return { styles, activeTheme }; + private readonly _onThemeDataChanged = this._register(new Emitter()); + public readonly onThemeDataChanged = this._onThemeDataChanged.event; + + constructor( + @IThemeService private readonly _themeService: IThemeService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + ) { + super(); + + this._register(this._themeService.onThemeChange(() => { + this.reset(); + })); + + const webviewConfigurationKeys = ['editor.fontFamily', 'editor.fontWeight', 'editor.fontSize']; + this._register(this._configurationService.onDidChangeConfiguration(e => { + if (webviewConfigurationKeys.some(key => e.affectsConfiguration(key))) { + this.reset(); + } + })); + } + + public getTheme(): ITheme { + return this._themeService.getTheme(); + } + + @WebviewThemeDataProvider.MEMOIZER + public getWebviewThemeData(): WebviewThemeData { + 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 theme = this._themeService.getTheme(); + 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); + return { styles, activeTheme }; + } + + private reset() { + WebviewThemeDataProvider.MEMOIZER.clear(); + this._onThemeDataChanged.fire(); + } } enum ApiThemeClassName { @@ -52,12 +90,10 @@ enum ApiThemeClassName { 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; + switch (theme.type) { + case LIGHT: return ApiThemeClassName.light; + case DARK: return ApiThemeClassName.dark; + default: return ApiThemeClassName.highContrast; } } } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts index e9e709e18e0..40cc80f75f6 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts @@ -6,11 +6,10 @@ 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/browser/webview'; import { WebviewTag } from 'electron'; +import { getActiveWebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewCommands'; export class OpenWebviewDeveloperToolsAction extends Action { static readonly ID = 'workbench.action.webview.openDeveloperTools'; @@ -82,12 +81,6 @@ export class RedoWebviewEditorCommand extends Command { } } -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) { diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index e891c95527e..929b367097b 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -3,42 +3,70 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { OnBeforeRequestDetails, OnHeadersReceivedDetails, Response, WebviewTag, WebContents, FindInPageOptions } from 'electron'; -import { addClass, addDisposableListener } from 'vs/base/browser/dom'; +import { FindInPageOptions, OnBeforeRequestDetails, OnHeadersReceivedDetails, Response, WebContents, WebviewTag } from 'electron'; +import { addDisposableListener } from 'vs/base/browser/dom'; import { Emitter, Event } from 'vs/base/common/event'; import { once } from 'vs/base/common/functional'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, toDisposable, IDisposable } from 'vs/base/common/lifecycle'; import { isMacintosh } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; 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 { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { Webview, WebviewContentOptions, WebviewOptions, WebviewResourceScheme } from 'vs/workbench/contrib/webview/browser/webview'; +import { Webview, WebviewContentOptions, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping'; -import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing'; +import { WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/resourceLoader'; +import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/common/themeing'; import { registerFileProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols'; -import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService'; -import { WebviewFindWidget, WebviewFindDelegate } from '../browser/webviewFindWidget'; +import { WebviewFindDelegate, WebviewFindWidget } from '../browser/webviewFindWidget'; +import { BaseWebview, WebviewMessageChannels } from 'vs/workbench/contrib/webview/browser/baseWebviewElement'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -interface IKeydownEvent { - key: string; - keyCode: number; - code: string; - shiftKey: boolean; - altKey: boolean; - ctrlKey: boolean; - metaKey: boolean; - repeat: boolean; + +class WebviewTagHandle extends Disposable { + + private _webContents: undefined | WebContents | 'destroyed'; + + public constructor( + public readonly webview: WebviewTag, + ) { + super(); + + this._register(addDisposableListener(this.webview, 'destroyed', () => { + this._webContents = 'destroyed'; + })); + + this._register(addDisposableListener(this.webview, 'did-start-loading', once(() => { + const contents = this.webContents; + if (contents) { + this._onFirstLoad.fire(contents); + this._register(toDisposable(() => { + contents.removeAllListeners(); + })); + } + }))); + } + + private readonly _onFirstLoad = this._register(new Emitter()); + public readonly onFirstLoad = this._onFirstLoad.event; + + public get webContents(): WebContents | undefined { + if (this._webContents === 'destroyed') { + return undefined; + } + if (this._webContents) { + return this._webContents; + } + this._webContents = this.webview.getWebContents(); + return this._webContents; + } } type OnBeforeRequestDelegate = (details: OnBeforeRequestDetails) => Promise; -type OnHeadersReceivedDelegate = (details: OnHeadersReceivedDetails) => { cancel: boolean } | undefined; +type OnHeadersReceivedDelegate = (details: OnHeadersReceivedDetails) => { cancel: boolean; } | undefined; class WebviewSession extends Disposable { @@ -46,16 +74,11 @@ class WebviewSession extends Disposable { private readonly _onHeadersReceivedDelegates: Array = []; public constructor( - webview: WebviewTag, + webviewHandle: WebviewTagHandle, ) { super(); - this._register(addDisposableListener(webview, 'did-start-loading', once(() => { - const contents = webview.getWebContents(); - if (!contents) { - return; - } - + this._register(webviewHandle.onFirstLoad(contents => { contents.session.webRequest.onBeforeRequest(async (details, callback) => { for (const delegate of this._onBeforeRequestDelegates) { const result = await delegate(details); @@ -77,7 +100,7 @@ class WebviewSession extends Disposable { } callback({ cancel: false, responseHeaders: details.responseHeaders }); }); - }))); + })); } public onBeforeRequest(delegate: OnBeforeRequestDelegate) { @@ -91,27 +114,20 @@ class WebviewSession extends Disposable { class WebviewProtocolProvider extends Disposable { constructor( - webview: WebviewTag, - private readonly _extensionLocation: URI | undefined, + handle: WebviewTagHandle, + private readonly _getExtensionLocation: () => URI | undefined, private readonly _getLocalResourceRoots: () => ReadonlyArray, private readonly _fileService: IFileService, ) { super(); - this._register(addDisposableListener(webview, 'did-start-loading', once(() => { - const contents = webview.getWebContents(); - if (contents) { - this.registerProtocols(contents); - } - }))); + this._register(handle.onFirstLoad(contents => { + this.registerProtocols(contents); + })); } private registerProtocols(contents: WebContents) { - if (contents.isDestroyed()) { - return; - } - - registerFileProtocol(contents, WebviewResourceScheme, this._fileService, this._extensionLocation, () => + registerFileProtocol(contents, WebviewResourceScheme, this._fileService, this._getExtensionLocation(), () => this._getLocalResourceRoots() ); } @@ -119,19 +135,17 @@ class WebviewProtocolProvider extends Disposable { class WebviewPortMappingProvider extends Disposable { - private readonly _manager: WebviewPortMappingManager; - constructor( session: WebviewSession, - extensionLocation: URI | undefined, + getExtensionLocation: () => URI | undefined, mappings: () => ReadonlyArray, tunnelService: ITunnelService, ) { super(); - this._manager = this._register(new WebviewPortMappingManager(extensionLocation, mappings, tunnelService)); + const manager = this._register(new WebviewPortMappingManager(getExtensionLocation, mappings, tunnelService)); session.onBeforeRequest(async details => { - const redirect = await this._manager.getRedirect(details.url); + const redirect = await manager.getRedirect(details.url); return redirect ? { redirectURL: redirect } : undefined; }); } @@ -142,33 +156,23 @@ class WebviewKeyboardHandler extends Disposable { private _ignoreMenuShortcut = false; constructor( - private readonly _webview: WebviewTag + private readonly _webviewHandle: WebviewTagHandle ) { super(); if (this.shouldToggleMenuShortcutsEnablement) { - this._register(addDisposableListener(this._webview, 'did-start-loading', () => { - const contents = this.getWebContents(); - if (contents) { - contents.on('before-input-event', (_event, input) => { - if (input.type === 'keyDown' && document.activeElement === this._webview) { - this._ignoreMenuShortcut = input.control || input.meta; - this.setIgnoreMenuShortcuts(this._ignoreMenuShortcut); - } - }); - } + this._register(_webviewHandle.onFirstLoad(contents => { + contents.on('before-input-event', (_event, input) => { + if (input.type === 'keyDown' && document.activeElement === this._webviewHandle.webview) { + this._ignoreMenuShortcut = input.control || input.meta; + this.setIgnoreMenuShortcuts(this._ignoreMenuShortcut); + } + }); })); } - this._register(addDisposableListener(this._webview, 'ipc-message', (event) => { + this._register(addDisposableListener(this._webviewHandle.webview, 'ipc-message', (event) => { switch (event.channel) { - case 'did-keydown': - // Electron: workaround for https://github.com/electron/electron/issues/14258 - // We have to detect keyboard events in the and dispatch them to our - // keybinding service because these events do not bubble to the parent window anymore. - this.handleKeydown(event.args[0]); - return; - case 'did-focus': this.setIgnoreMenuShortcuts(this._ignoreMenuShortcut); break; @@ -188,323 +192,146 @@ class WebviewKeyboardHandler extends Disposable { if (!this.shouldToggleMenuShortcutsEnablement) { return; } - const contents = this.getWebContents(); + const contents = this._webviewHandle.webContents; if (contents) { contents.setIgnoreMenuShortcuts(value); } } - - private getWebContents(): WebContents | undefined { - const contents = this._webview.getWebContents(); - if (contents && !contents.isDestroyed()) { - return contents; - } - return undefined; - } - - private handleKeydown(event: IKeydownEvent): void { - // Create a fake KeyboardEvent from the data provided - const emulatedKeyboardEvent = new KeyboardEvent('keydown', event); - // Force override the target - Object.defineProperty(emulatedKeyboardEvent, 'target', { - get: () => this._webview - }); - // And re-dispatch - window.dispatchEvent(emulatedKeyboardEvent); - } } -interface WebviewContent { - readonly html: string; - readonly options: WebviewContentOptions; - readonly state: string | undefined; -} - -export class ElectronWebviewBasedWebview extends Disposable implements Webview, WebviewFindDelegate { - private _webview: WebviewTag | undefined; - private _ready: Promise; - +export class ElectronWebviewBasedWebview extends BaseWebview implements Webview, WebviewFindDelegate { private _webviewFindWidget: WebviewFindWidget | undefined; private _findStarted: boolean = false; - private content: WebviewContent; - private _focused = false; - - private readonly _onDidFocus = this._register(new Emitter()); - public readonly onDidFocus: Event = this._onDidFocus.event; + public extension: WebviewExtensionDescription | undefined; constructor( - private readonly _options: WebviewOptions, + id: string, + options: WebviewOptions, contentOptions: WebviewContentOptions, + private readonly _webviewThemeDataProvider: WebviewThemeDataProvider, @IInstantiationService instantiationService: IInstantiationService, - @IThemeService themeService: IThemeService, @IFileService fileService: IFileService, @ITunnelService tunnelService: ITunnelService, - @IConfigurationService private readonly _configurationService: IConfigurationService, - @ITelemetryService private readonly _telemetryService: ITelemetryService, - @IEnvironmentService private readonly _environementService: IEnvironmentService, + @ITelemetryService telemetryService: ITelemetryService, + @IEnvironmentService environementService: IEnvironmentService, + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { - super(); - this.content = { - html: '', - options: contentOptions, - state: undefined - }; + super(id, options, contentOptions, _webviewThemeDataProvider, telemetryService, environementService, workbenchEnvironmentService); - this._webview = document.createElement('webview'); - this._webview.setAttribute('partition', `webview${Date.now()}`); - this._webview.setAttribute('webpreferences', 'contextIsolation=yes'); - - this._webview.style.flex = '0 1'; - this._webview.style.width = '0'; - this._webview.style.height = '0'; - this._webview.style.outline = '0'; - - this._webview.preload = require.toUrl('./pre/electron-index.js'); - 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 (this._webview && event.channel === 'webview-ready') { - // console.info('[PID Webview] ' event.args[0]); - addClass(this._webview, 'ready'); // can be found by debug command - - subscription.dispose(); - resolve(); - } - })); - }); - - const session = this._register(new WebviewSession(this._webview)); + const webviewAndContents = this._register(new WebviewTagHandle(this.element!)); + const session = this._register(new WebviewSession(webviewAndContents)); this._register(new WebviewProtocolProvider( - this._webview, - this._options.extension ? this._options.extension.location : undefined, + webviewAndContents, + () => this.extension ? this.extension.location : undefined, () => (this.content.options.localResourceRoots || []), fileService)); this._register(new WebviewPortMappingProvider( session, - _options.extension ? _options.extension.location : undefined, + () => this.extension ? this.extension.location : undefined, () => (this.content.options.portMapping || []), tunnelService, )); - this._register(new WebviewKeyboardHandler(this._webview)); + this._register(new WebviewKeyboardHandler(webviewAndContents)); - this._register(addDisposableListener(this._webview, 'console-message', function (e: { level: number; message: string; line: number; sourceId: string; }) { + this._register(addDisposableListener(this.element!, 'console-message', function (e: { level: number; message: string; line: number; sourceId: string; }) { console.log(`[Embedded Page] ${e.message}`); })); - this._register(addDisposableListener(this._webview, 'dom-ready', () => { - this.layout(); - + this._register(addDisposableListener(this.element!, 'dom-ready', () => { // Workaround for https://github.com/electron/electron/issues/14474 - if (this._webview && (this._focused || document.activeElement === this._webview)) { - this._webview.blur(); - this._webview.focus(); + if (this.element && (this.focused || document.activeElement === this.element)) { + this.element.blur(); + this.element.focus(); } })); - this._register(addDisposableListener(this._webview, 'crashed', () => { + this._register(addDisposableListener(this.element!, 'crashed', () => { console.error('embedded page crashed'); })); - this._register(addDisposableListener(this._webview, 'ipc-message', (event) => { - if (!this._webview) { + + this._register(this.on('synthetic-mouse-event', (rawEvent: any) => { + if (!this.element) { return; } - - switch (event.channel) { - case 'onmessage': - if (event.args && event.args.length) { - this._onMessage.fire(event.args[0]); - } - return; - - case 'did-click-link': - const [uri] = event.args; - this._onDidClickLink.fire(URI.parse(uri)); - return; - - case 'synthetic-mouse-event': - { - const rawEvent = event.args[0]; - const bounds = this._webview.getBoundingClientRect(); - try { - window.dispatchEvent(new MouseEvent(rawEvent.type, { - ...rawEvent, - clientX: rawEvent.clientX + bounds.left, - clientY: rawEvent.clientY + bounds.top, - })); - return; - } catch { - // CustomEvent was treated as MouseEvent so don't do anything - https://github.com/microsoft/vscode/issues/78915 - return; - } - } - - case 'did-set-content': - this._webview.style.flex = ''; - this._webview.style.width = '100%'; - this._webview.style.height = '100%'; - this.layout(); - return; - - case 'did-scroll': - if (event.args && typeof event.args[0] === 'number') { - this._onDidScroll.fire({ scrollYPercentage: event.args[0] }); - } - return; - - case 'do-reload': - this.reload(); - return; - - case 'do-update-state': - const state = event.args[0]; - this.state = state; - this._onDidUpdateState.fire(state); - return; - - case 'did-focus': - this.handleFocusChange(true); - return; - - case 'did-blur': - this.handleFocusChange(false); - return; - - case 'no-csp-found': - this.handleNoCspFound(); - return; + const bounds = this.element.getBoundingClientRect(); + try { + window.dispatchEvent(new MouseEvent(rawEvent.type, { + ...rawEvent, + clientX: rawEvent.clientX + bounds.left, + clientY: rawEvent.clientY + bounds.top, + })); + return; + } catch { + // CustomEvent was treated as MouseEvent so don't do anything - https://github.com/microsoft/vscode/issues/78915 + return; } })); - this._register(addDisposableListener(this._webview, 'devtools-opened', () => { + this._register(this.on('did-set-content', () => { + if (this.element) { + this.element.style.flex = ''; + this.element.style.width = '100%'; + this.element.style.height = '100%'; + } + })); + + this._register(addDisposableListener(this.element!, 'devtools-opened', () => { this._send('devtools-opened'); })); - if (_options.enableFindWidget) { + if (options.enableFindWidget) { this._webviewFindWidget = this._register(instantiationService.createInstance(WebviewFindWidget, this)); - this._register(addDisposableListener(this._webview, 'found-in-page', e => { + this._register(addDisposableListener(this.element!, 'found-in-page', e => { this._hasFindResult.fire(e.result.matches > 0); })); - } - this.style(themeService.getTheme()); - this._register(themeService.onThemeChange(this.style, this)); + this.styledFindWidget(); + } } + protected createElement(options: WebviewOptions) { + const element = document.createElement('webview'); + element.setAttribute('partition', `webview${Date.now()}`); + element.setAttribute('webpreferences', 'contextIsolation=yes'); + element.className = `webview ${options.customClasses || ''}`; + + element.style.flex = '0 1'; + element.style.width = '0'; + element.style.height = '0'; + element.style.outline = '0'; + + element.preload = require.toUrl('./pre/electron-index.js'); + element.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'; + + return element; + } + + protected readonly extraContentOptions = {}; + public mountTo(parent: HTMLElement) { - if (!this._webview) { + if (!this.element) { return; } if (this._webviewFindWidget) { parent.appendChild(this._webviewFindWidget.getDomNode()!); } - parent.appendChild(this._webview); + parent.appendChild(this.element); } - dispose(): void { - if (this._webview) { - if (this._webview.parentElement) { - this._webview.parentElement.removeChild(this._webview); - } - this._webview = undefined; - } - - if (this._webviewFindWidget) { - this._webviewFindWidget.dispose(); - this._webviewFindWidget = undefined; - } - super.dispose(); - } - - 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; - - private readonly _onMissingCsp = this._register(new Emitter()); - public readonly onMissingCsp = this._onMissingCsp.event; - - private _send(channel: string, data?: any): void { - this._ready - .then(() => { - if (this._webview) { - this._webview.send(channel, data); - } - }) - .catch(err => console.error(err)); - } - - public set initialScrollProgress(value: number) { - this._send('initial-scroll-position', value); - } - - public set state(state: string | undefined) { - this.content = { - html: this.content.html, - options: this.content.options, - state, - }; - } - - 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: value, - options: this.content.options, - state: this.content.state, - }; - this.doUpdateContent(); - } - - public update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { - if (retainContextWhenHidden && html === this.content.html && areWebviewInputOptionsEqual(options, this.content.options)) { - return; - } - this.content = { - html: 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 - }); + protected postMessage(channel: string, data?: any): void { + this.element?.send(channel, data); } public focus(): void { - if (!this._webview) { + if (!this.element) { return; } try { - this._webview.focus(); + this.element.focus(); } catch { // noop } @@ -514,78 +341,20 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview, this.handleFocusChange(true); } - private handleFocusChange(isFocused: boolean): void { - this._focused = isFocused; - if (isFocused) { - this._onDidFocus.fire(); - } + protected style(): void { + super.style(); + this.styledFindWidget(); } - private _hasAlertedAboutMissingCsp = false; - - private handleNoCspFound(): void { - if (this._hasAlertedAboutMissingCsp) { - return; - } - this._hasAlertedAboutMissingCsp = true; - - if (this._options.extension && this._options.extension.id) { - if (this._environementService.isExtensionDevelopment) { - this._onMissingCsp.fire(this._options.extension.id); - } - - type TelemetryClassification = { - extension?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' } - }; - type TelemetryData = { - extension?: string, - }; - - this._telemetryService.publicLog2('webviewMissingCsp', { - extension: this._options.extension.id.value - }); - } - } - - public sendMessage(data: any): void { - this._send('message', data); - } - - private style(theme: ITheme): void { - const { styles, activeTheme } = getWebviewThemeData(theme, this._configurationService); - this._send('styles', { styles, activeTheme }); - - if (this._webviewFindWidget) { - this._webviewFindWidget.updateTheme(theme); - } - } - - public layout(): void { - if (!this._webview || this._webview.style.width === '0px') { - return; - } - const contents = this._webview.getWebContents(); - if (!contents || contents.isDestroyed()) { - return; - } - const window = (contents as any).getOwnerBrowserWindow(); - if (!window || !window.webContents || window.webContents.isDestroyed()) { - return; - } - window.webContents.getZoomFactor((factor: number) => { - if (contents.isDestroyed()) { - return; - } - - contents.setZoomFactor(factor); - }); + private styledFindWidget() { + this._webviewFindWidget?.updateTheme(this._webviewThemeDataProvider.getTheme()); } private readonly _hasFindResult = this._register(new Emitter()); public readonly hasFindResult: Event = this._hasFindResult.event; public startFind(value: string, options?: FindInPageOptions) { - if (!value || !this._webview) { + if (!value || !this.element) { return; } @@ -601,7 +370,7 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview, }; this._findStarted = true; - this._webview.findInPage(value, findOptions); + this.element.findInPage(value, findOptions); } /** @@ -612,7 +381,7 @@ export class ElectronWebviewBasedWebview 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) { + if (!this.element) { return; } @@ -627,73 +396,65 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview, return; } - this._webview.findInPage(value, options); + this.element.findInPage(value, options); } public stopFind(keepSelection?: boolean): void { this._hasFindResult.fire(false); - if (!this._webview) { + if (!this.element) { return; } this._findStarted = false; - this._webview.stopFindInPage(keepSelection ? 'keepSelection' : 'clearSelection'); + this.element.stopFindInPage(keepSelection ? 'keepSelection' : 'clearSelection'); } public showFind() { - if (this._webviewFindWidget) { - this._webviewFindWidget.reveal(); - } + this._webviewFindWidget?.reveal(); } public hideFind() { - if (this._webviewFindWidget) { - this._webviewFindWidget.hide(); - } + this._webviewFindWidget?.hide(); } public runFindAction(previous: boolean) { - if (this._webviewFindWidget) { - this._webviewFindWidget.find(previous); - } - } - - public reload() { - this.doUpdateContent(); + this._webviewFindWidget?.find(previous); } public selectAll() { - if (this._webview) { - this._webview.selectAll(); - } + this.element?.selectAll(); } public copy() { - if (this._webview) { - this._webview.copy(); - } + this.element?.copy(); } public paste() { - if (this._webview) { - this._webview.paste(); - } + this.element?.paste(); } public cut() { - if (this._webview) { - this._webview.cut(); - } + this.element?.cut(); } public undo() { - if (this._webview) { - this._webview.undo(); - } + this.element?.undo(); } public redo() { - if (this._webview) { - this._webview.redo(); + this.element?.redo(); + } + + protected on(channel: WebviewMessageChannels | string, handler: (data: T) => void): IDisposable { + if (!this.element) { + return Disposable.None; } + return addDisposableListener(this.element, 'ipc-message', (event) => { + if (!this.element) { + return; + } + if (event.channel === channel && event.args && event.args.length) { + handler(event.args[0]); + } + }); } } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts index 49ec194e743..c9110c6ea2b 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts @@ -6,17 +6,22 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; 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/browser/webview'; +import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/common/themeing'; import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; export class ElectronWebviewService implements IWebviewService { _serviceBrand: undefined; + private readonly webviewThemeDataProvider: WebviewThemeDataProvider; + constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, @IConfigurationService private readonly _configService: IConfigurationService, - ) { } + ) { + this.webviewThemeDataProvider = this._instantiationService.createInstance(WebviewThemeDataProvider); + } createWebview( id: string, @@ -25,9 +30,9 @@ export class ElectronWebviewService implements IWebviewService { ): WebviewElement { const useExternalEndpoint = this._configService.getValue('webview.experimental.useExternalEndpoint'); if (useExternalEndpoint) { - return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions); + return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions, this.webviewThemeDataProvider); } else { - return this._instantiationService.createInstance(ElectronWebviewBasedWebview, options, contentOptions); + return this._instantiationService.createInstance(ElectronWebviewBasedWebview, id, options, contentOptions, this.webviewThemeDataProvider); } } diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.ts b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.ts deleted file mode 100644 index 7eb2bc0dc1c..00000000000 --- a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.ts +++ /dev/null @@ -1,72 +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 { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import * as platform from 'vs/base/common/platform'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { URI } from 'vs/base/common/uri'; -import { IProductService } from 'vs/platform/product/common/productService'; - -export class OpenWelcomePageInBrowser implements IWorkbenchContribution { - - private static readonly hideWelcomeSettingskey = 'workbench.hide.welcome'; - - private welcomePageURL?: string; - private appName: string; - - constructor( - @IStorageService private readonly storageService: IStorageService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @ITelemetryService private readonly telemetryService: ITelemetryService, - @IOpenerService private readonly openerService: IOpenerService, - @IProductService productService: IProductService - ) { - this.appName = productService.nameLong; - this.welcomePageURL = productService.welcomePage; - - if ( - !productService.welcomePage || - environmentService.skipGettingStarted || - environmentService.isExtensionDevelopment - ) { - return; - } - - this.handleWelcome(); - } - - private getUrl(telemetryInfo: ITelemetryInfo): string { - return `${this.welcomePageURL}&&from=${this.appName}&&id=${telemetryInfo.machineId}`; - } - - private openExternal(url: string) { - // Don't open the welcome page as the root user on Linux, this is due to a bug with xdg-open - // which recommends against running itself as root. - if (platform.isLinux && platform.isRootUser()) { - return; - } - this.openerService.open(URI.parse(url)); - } - - private handleWelcome(): void { - //make sure the user is online, otherwise refer to the next run to show the welcome page - if (!navigator.onLine) { - return; - } - - let firstStartup = !this.storageService.get(OpenWelcomePageInBrowser.hideWelcomeSettingskey, StorageScope.GLOBAL); - - if (firstStartup && this.welcomePageURL) { - this.telemetryService.getTelemetryInfo().then(info => { - let url = this.getUrl(info); - this.openExternal(url); - this.storageService.store(OpenWelcomePageInBrowser.hideWelcomeSettingskey, true, StorageScope.GLOBAL); - }); - } - } -} diff --git a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts index 0ba17c87166..9dc2d370370 100644 --- a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts @@ -207,12 +207,13 @@ class WelcomeOverlay extends Disposable { dom.addClass(workbench, 'blur-background'); this._overlayVisible.set(true); this.updateProblemsKey(); + this.updateActivityBarKeys(); this._overlay.focus(); } } private updateProblemsKey() { - const problems = document.querySelector('div[id="workbench.parts.statusbar"] .statusbar-item.left .octicon.octicon-warning'); + const problems = document.querySelector('div[id="workbench.parts.statusbar"] .statusbar-item.left .codicon.codicon-warning'); const key = this._overlay.querySelector('.key.problems') as HTMLElement; if (problems instanceof HTMLElement) { const target = problems.getBoundingClientRect(); @@ -222,8 +223,27 @@ class WelcomeOverlay extends Disposable { key.style.bottom = bottom + 'px'; key.style.left = left + 'px'; } else { - key.style.bottom = null; - key.style.left = null; + key.style.bottom = ''; + key.style.left = ''; + } + } + + private updateActivityBarKeys() { + const ids = ['explorer', 'search', 'git', 'debug', 'extensions']; + const activityBar = document.querySelector('.activitybar .composite-bar'); + if (activityBar instanceof HTMLElement) { + const target = activityBar.getBoundingClientRect(); + const bounds = this._overlay.getBoundingClientRect(); + for (let i = 0; i < ids.length; i++) { + const key = this._overlay.querySelector(`.key.${ids[i]}`) as HTMLElement; + const top = target.top - bounds.top + 50 * i + 13; + key.style.top = top + 'px'; + } + } else { + for (let i = 0; i < ids.length; i++) { + const key = this._overlay.querySelector(`.key.${ids[i]}`) as HTMLElement; + key.style.top = ''; + } } } diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index 5632b4f0b0a..bf21486dee0 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -14,7 +14,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors'; -import { IWindowService, IWindowOpenable } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable } 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'; @@ -40,9 +40,10 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IFileService } from 'vs/platform/files/common/files'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { joinPath } from 'vs/base/common/resources'; -import { IRecentlyOpened, isRecentWorkspace, IRecentWorkspace, IRecentFolder, isRecentFolder } from 'vs/platform/history/common/history'; +import { IRecentlyOpened, isRecentWorkspace, IRecentWorkspace, IRecentFolder, isRecentFolder, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IProductService } from 'vs/platform/product/common/productService'; const configurationKey = 'workbench.startupEditor'; const oldConfigurationKey = 'workbench.welcome.enabled'; @@ -146,7 +147,6 @@ interface ExtensionSuggestion { const extensionPacks: ExtensionSuggestion[] = [ { name: localize('welcomePage.javaScript', "JavaScript"), id: 'dbaeumer.vscode-eslint' }, - { name: localize('welcomePage.typeScript', "TypeScript"), id: 'ms-vscode.vscode-typescript-tslint-plugin' }, { name: localize('welcomePage.python', "Python"), id: 'ms-python.python' }, // { name: localize('welcomePage.go', "Go"), id: 'lukehoban.go' }, { name: localize('welcomePage.php', "PHP"), id: 'felixfbecker.php-pack' }, @@ -252,7 +252,7 @@ class WelcomePage extends Disposable { constructor( @IEditorService private readonly editorService: IEditorService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IWindowService private readonly windowService: IWindowService, + @IWorkspacesService private readonly workspacesService: IWorkspacesService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IConfigurationService private readonly configurationService: IConfigurationService, @ILabelService private readonly labelService: ILabelService, @@ -264,12 +264,14 @@ class WelcomePage extends Disposable { @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @ILifecycleService lifecycleService: ILifecycleService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IHostService private readonly hostService: IHostService + @IHostService private readonly hostService: IHostService, + @IProductService private readonly productService: IProductService, + ) { super(); this._register(lifecycleService.onShutdown(() => this.dispose())); - const recentlyOpened = this.windowService.getRecentlyOpened(); + const recentlyOpened = this.workspacesService.getRecentlyOpened(); const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions); const resource = URI.parse(require.toUrl('./vs_code_welcome_page')) .with({ @@ -299,6 +301,11 @@ class WelcomePage extends Disposable { this.configurationService.updateValue(configurationKey, showOnStartup.checked ? 'welcomePage' : 'newUntitledFile', ConfigurationTarget.USER); }); + const prodName = container.querySelector('.welcomePage .title .caption') as HTMLElement; + if (prodName) { + prodName.innerHTML = this.productService.nameLong; + } + recentlyOpened.then(({ workspaces }) => { // Filter out the current workspace workspaces = workspaces.filter(recent => !this.contextService.isCurrentWorkspace(isRecentWorkspace(recent) ? recent.workspace : recent.folderUri)); @@ -365,7 +372,7 @@ class WelcomePage extends Disposable { id: 'openRecentFolder', from: telemetryFrom }); - this.hostService.openInWindow([windowOpenable], { forceNewWindow: e.ctrlKey || e.metaKey }); + this.hostService.openWindow([windowOpenable], { forceNewWindow: e.ctrlKey || e.metaKey }); e.preventDefault(); e.stopPropagation(); }); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts b/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution.ts similarity index 69% rename from src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts rename to src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution.ts index 1c11cd4a4c1..d0440e20402 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts +++ b/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution.ts @@ -4,10 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Registry } from 'vs/platform/registry/common/platform'; -import { TelemetryOptOut } from './telemetryOptOut'; +import { BrowserTelemetryOptOut } from 'vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -Registry - .as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(TelemetryOptOut, LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BrowserTelemetryOptOut, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.ts similarity index 64% rename from src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts rename to src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.ts index 135bc48f22d..50398d48086 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts +++ b/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.ts @@ -10,8 +10,6 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { IWindowService } from 'vs/platform/windows/common/windows'; 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'; @@ -20,63 +18,66 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IProductService } from 'vs/platform/product/common/productService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -export class TelemetryOptOut implements IWorkbenchContribution { +export abstract class AbstractTelemetryOptOut implements IWorkbenchContribution { - private static TELEMETRY_OPT_OUT_SHOWN = 'workbench.telemetryOptOutShown'; + private static readonly TELEMETRY_OPT_OUT_SHOWN = 'workbench.telemetryOptOutShown'; private privacyUrl: string | undefined; constructor( - @IStorageService storageService: IStorageService, - @IOpenerService openerService: IOpenerService, + @IStorageService private readonly storageService: IStorageService, + @IOpenerService private readonly openerService: IOpenerService, @INotificationService private readonly notificationService: INotificationService, - @IWindowService windowService: IWindowService, - @IHostService hostService: IHostService, + @IHostService private readonly hostService: IHostService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IExperimentService private readonly experimentService: IExperimentService, @IConfigurationService private readonly configurationService: IConfigurationService, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, - @IProductService productService: IProductService - ) { - if (!productService.telemetryOptOutUrl || storageService.get(TelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, StorageScope.GLOBAL)) { - return; - } - const experimentId = 'telemetryOptOut'; - Promise.all([ - windowService.isFocused(), - hostService.windowCount, - experimentService.getExperimentById(experimentId) - ]).then(([focused, count, experimentState]) => { - if (!focused && count > 1) { - return; + @IProductService private readonly productService: IProductService, + ) { } + + protected async handleTelemetryOptOut(): Promise { + if (this.productService.telemetryOptOutUrl && !this.storageService.get(AbstractTelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, StorageScope.GLOBAL)) { + const experimentId = 'telemetryOptOut'; + + const [count, experimentState] = await Promise.all([this.getWindowCount(), this.experimentService.getExperimentById(experimentId)]); + + if (!this.hostService.hasFocus && count > 1) { + return; // return early if meanwhile another window opened (we only show the opt-out once) } - storageService.store(TelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, true, StorageScope.GLOBAL); - this.privacyUrl = productService.privacyStatementUrl || productService.telemetryOptOutUrl; + this.storageService.store(AbstractTelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, true, StorageScope.GLOBAL); - if (experimentState && experimentState.state === ExperimentState.Run && telemetryService.isOptedIn) { + this.privacyUrl = this.productService.privacyStatementUrl || this.productService.telemetryOptOutUrl; + + if (experimentState && experimentState.state === ExperimentState.Run && this.telemetryService.isOptedIn) { this.runExperiment(experimentId); return; } - const telemetryOptOutUrl = productService.telemetryOptOutUrl; + const telemetryOptOutUrl = this.productService.telemetryOptOutUrl; if (telemetryOptOutUrl) { - const optOutNotice = localize('telemetryOptOut.optOutNotice', "Help improve VS Code by allowing Microsoft to collect usage data. Read our [privacy statement]({0}) and learn how to [opt out]({1}).", this.privacyUrl, productService.telemetryOptOutUrl); - const optInNotice = localize('telemetryOptOut.optInNotice', "Help improve VS Code by allowing Microsoft to collect usage data. Read our [privacy statement]({0}) and learn how to [opt in]({1}).", this.privacyUrl, productService.telemetryOptOutUrl); - - notificationService.prompt( - Severity.Info, - telemetryService.isOptedIn ? optOutNotice : optInNotice, - [{ - label: localize('telemetryOptOut.readMore', "Read More"), - run: () => openerService.open(URI.parse(telemetryOptOutUrl)) - }], - { sticky: true } - ); + this.showTelemetryOptOut(telemetryOptOutUrl); } - }) - .then(undefined, onUnexpectedError); + } } + private showTelemetryOptOut(telemetryOptOutUrl: string): void { + const optOutNotice = localize('telemetryOptOut.optOutNotice', "Help improve VS Code by allowing Microsoft to collect usage data. Read our [privacy statement]({0}) and learn how to [opt out]({1}).", this.privacyUrl, this.productService.telemetryOptOutUrl); + const optInNotice = localize('telemetryOptOut.optInNotice', "Help improve VS Code by allowing Microsoft to collect usage data. Read our [privacy statement]({0}) and learn how to [opt in]({1}).", this.privacyUrl, this.productService.telemetryOptOutUrl); + + this.notificationService.prompt( + Severity.Info, + this.telemetryService.isOptedIn ? optOutNotice : optInNotice, + [{ + label: localize('telemetryOptOut.readMore', "Read More"), + run: () => this.openerService.open(URI.parse(telemetryOptOutUrl)) + }], + { sticky: true } + ); + } + + protected abstract getWindowCount(): Promise; + private runExperiment(experimentId: string) { const promptMessageKey = 'telemetryOptOut.optOutOption'; const yesLabelKey = 'telemetryOptOut.OptIn'; @@ -99,7 +100,7 @@ export class TelemetryOptOut implements IWorkbenchContribution { return this.galleryService.getCoreTranslation(extensionToFetchTranslationsFrom, locale!) .then(translation => { - const translationsFromPack: any = 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/telemetryOptOut/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)'; @@ -151,3 +152,26 @@ export class TelemetryOptOut implements IWorkbenchContribution { }); } } + +export class BrowserTelemetryOptOut extends AbstractTelemetryOptOut { + + constructor( + @IStorageService storageService: IStorageService, + @IOpenerService openerService: IOpenerService, + @INotificationService notificationService: INotificationService, + @IHostService hostService: IHostService, + @ITelemetryService telemetryService: ITelemetryService, + @IExperimentService experimentService: IExperimentService, + @IConfigurationService configurationService: IConfigurationService, + @IExtensionGalleryService galleryService: IExtensionGalleryService, + @IProductService productService: IProductService + ) { + super(storageService, openerService, notificationService, hostService, telemetryService, experimentService, configurationService, galleryService, productService); + + this.handleTelemetryOptOut(); + } + + protected async getWindowCount(): Promise { + return 1; + } +} diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution.ts b/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-browser/telemetryOptOut.contribution.ts similarity index 68% rename from src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution.ts rename to src/vs/workbench/contrib/welcome/telemetryOptOut/electron-browser/telemetryOptOut.contribution.ts index bdcee7756a2..44b1e266005 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution.ts +++ b/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-browser/telemetryOptOut.contribution.ts @@ -4,10 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Registry } from 'vs/platform/registry/common/platform'; -import { OpenWelcomePageInBrowser } from './openWebsite'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { NativeTelemetryOptOut } from 'vs/workbench/contrib/welcome/telemetryOptOut/electron-browser/telemetryOptOut'; -Registry - .as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(OpenWelcomePageInBrowser, LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeTelemetryOptOut, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-browser/telemetryOptOut.ts new file mode 100644 index 00000000000..d561cf83320 --- /dev/null +++ b/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-browser/telemetryOptOut.ts @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { AbstractTelemetryOptOut } from 'vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut'; +import { IElectronService } from 'vs/platform/electron/node/electron'; + +export class NativeTelemetryOptOut extends AbstractTelemetryOptOut { + + constructor( + @IStorageService storageService: IStorageService, + @IOpenerService openerService: IOpenerService, + @INotificationService notificationService: INotificationService, + @IHostService hostService: IHostService, + @ITelemetryService telemetryService: ITelemetryService, + @IExperimentService experimentService: IExperimentService, + @IConfigurationService configurationService: IConfigurationService, + @IExtensionGalleryService galleryService: IExtensionGalleryService, + @IProductService productService: IProductService, + @IElectronService private readonly electronService: IElectronService + ) { + super(storageService, openerService, notificationService, hostService, telemetryService, experimentService, configurationService, galleryService, productService); + + this.handleTelemetryOptOut(); + } + + protected getWindowCount(): Promise { + return this.electronService.getWindowCount(); + } +} diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts index 53afce0c964..252b682d8b8 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts @@ -160,7 +160,7 @@ Emmet takes the snippets idea to a whole new level: you can type CSS-like expres ul>li.item$*5 ||| ->**Tip:** The [Emmet cheat sheet](http://docs.emmet.io/cheat-sheet/) is a great source of Emmet syntax suggestions. To expand Emmet abbreviations and snippets using the |tab| key use the |emmet.triggerExpansionOnTab| [setting](command:workbench.action.openGlobalSettings). Check out the docs on [Emmet in VS Code](https://code.visualstudio.com/docs/editor/emmet) to learn more. +>**Tip:** The [Emmet cheat sheet](https://docs.emmet.io/cheat-sheet/) is a great source of Emmet syntax suggestions. To expand Emmet abbreviations and snippets using the |tab| key use the |emmet.triggerExpansionOnTab| [setting](command:workbench.action.openGlobalSettings). Check out the docs on [Emmet in VS Code](https://code.visualstudio.com/docs/editor/emmet) to learn more. diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts index 6d69a2758f1..2b7a9668bd2 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts @@ -10,6 +10,7 @@ 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'; +import { isEqual } from 'vs/base/common/resources'; export class WalkThroughModel extends EditorModel { @@ -78,7 +79,7 @@ export class WalkThroughInput extends EditorInput { return this.options.telemetryFrom; } - getTelemetryDescriptor(): { [key: string]: unknown } { + getTelemetryDescriptor(): { [key: string]: unknown; } { const descriptor = super.getTelemetryDescriptor(); descriptor['target'] = this.getTelemetryFrom(); /* __GDPR__FRAGMENT__ @@ -130,7 +131,7 @@ export class WalkThroughInput extends EditorInput { let otherResourceEditorInput = otherInput; // Compare by properties - return otherResourceEditorInput.options.resource.toString() === this.options.resource.toString(); + return isEqual(otherResourceEditorInput.options.resource, this.options.resource); } return false; diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css index 0d4122ccdff..3ccb4957f44 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css @@ -8,6 +8,7 @@ padding: 10px 20px; line-height: 22px; user-select: initial; + -webkit-user-select: initial; } .monaco-workbench .part.editor > .content .walkThroughContent img { diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index 089c2bb1a46..d550a53a3c4 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -58,11 +58,11 @@ export class WalkThroughPart extends BaseEditor { private readonly disposables = new DisposableStore(); private contentDisposables: IDisposable[] = []; - private content: HTMLDivElement; - private scrollbar: DomScrollableElement; + private content!: HTMLDivElement; + private scrollbar!: DomScrollableElement; private editorFocus: IContextKey; - private lastFocus: HTMLElement; - private size: Dimension; + private lastFocus: HTMLElement | undefined; + private size: Dimension | undefined; private editorMemento: IEditorMemento; constructor( diff --git a/src/vs/workbench/electron-browser/actions/developerActions.ts b/src/vs/workbench/electron-browser/actions/developerActions.ts index d9b50a3f494..e4c1160ca47 100644 --- a/src/vs/workbench/electron-browser/actions/developerActions.ts +++ b/src/vs/workbench/electron-browser/actions/developerActions.ts @@ -7,13 +7,19 @@ import { Action } from 'vs/base/common/actions'; import * as nls from 'vs/nls'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; export class ToggleDevToolsAction extends Action { static readonly ID = 'workbench.action.toggleDevTools'; - static LABEL = nls.localize('toggleDevTools', "Toggle Developer Tools"); + static readonly LABEL = nls.localize('toggleDevTools', "Toggle Developer Tools"); - constructor(id: string, label: string, @IElectronService private readonly electronService: IElectronService) { + constructor( + id: string, + label: string, + @IElectronService private readonly electronService: IElectronService + ) { super(id, label); } @@ -25,9 +31,13 @@ export class ToggleDevToolsAction extends Action { export class ToggleSharedProcessAction extends Action { static readonly ID = 'workbench.action.toggleSharedProcess'; - static LABEL = nls.localize('toggleSharedProcess', "Toggle Shared Process"); + static readonly LABEL = nls.localize('toggleSharedProcess', "Toggle Shared Process"); - constructor(id: string, label: string, @ISharedProcessService private readonly sharedProcessService: ISharedProcessService) { + constructor( + id: string, + label: string, + @ISharedProcessService private readonly sharedProcessService: ISharedProcessService + ) { super(id, label); } @@ -35,3 +45,22 @@ export class ToggleSharedProcessAction extends Action { return this.sharedProcessService.toggleSharedProcessWindow(); } } + +export class ConfigureRuntimeArgumentsAction extends Action { + + static readonly ID = 'workbench.action.configureRuntimeArguments'; + static readonly LABEL = nls.localize('configureRuntimeArguments', "Configure Runtime Arguments"); + + constructor( + id: string, + label: string, + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IEditorService private readonly editorService: IEditorService + ) { + super(id, label); + } + + async run(): Promise { + await this.editorService.openEditor({ resource: this.environmentService.argvResource }); + } +} diff --git a/src/vs/workbench/electron-browser/actions/windowActions.ts b/src/vs/workbench/electron-browser/actions/windowActions.ts index 440cba68b56..9bc18a02043 100644 --- a/src/vs/workbench/electron-browser/actions/windowActions.ts +++ b/src/vs/workbench/electron-browser/actions/windowActions.ts @@ -5,7 +5,6 @@ import { URI } from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import * as nls from 'vs/nls'; import * as browser from 'vs/base/browser/browser'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -19,6 +18,7 @@ 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 { IElectronService } from 'vs/platform/electron/node/electron'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; export class CloseCurrentWindowAction extends Action { @@ -137,10 +137,10 @@ export class ZoomResetAction extends BaseZoomAction { } } -export class RestartWithExtensionsDisabledAction extends Action { +export class ReloadWindowWithExtensionsDisabledAction extends Action { - static readonly ID = 'workbench.action.restartWithExtensionsDisabled'; - static LABEL = nls.localize('restartWithExtensionsDisabled', "Restart With Extensions Disabled"); + static readonly ID = 'workbench.action.reloadWindowWithExtensionsDisabled'; + static readonly LABEL = nls.localize('reloadWindowWithExtensionsDisabled', "Reload With Extensions Disabled"); constructor( id: string, @@ -151,7 +151,7 @@ export class RestartWithExtensionsDisabledAction extends Action { } async run(): Promise { - await this.electronService.relaunch({ addArgs: ['--disable-extensions'] }); + await this.electronService.reload({ disableExtensions: true }); return true; } @@ -167,7 +167,7 @@ export abstract class BaseSwitchWindow extends Action { constructor( id: string, label: string, - private windowService: IWindowService, + private electronEnvironmentService: IElectronEnvironmentService, private quickInputService: IQuickInputService, private keybindingService: IKeybindingService, private modelService: IModelService, @@ -180,7 +180,7 @@ export abstract class BaseSwitchWindow extends Action { protected abstract isQuickNavigate(): boolean; async run(): Promise { - const currentWindowId = this.windowService.windowId; + const currentWindowId = this.electronEnvironmentService.windowId; const windows = await this.electronService.getWindows(); const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window to switch to"); @@ -217,19 +217,19 @@ export abstract class BaseSwitchWindow extends Action { export class SwitchWindow extends BaseSwitchWindow { static readonly ID = 'workbench.action.switchWindow'; - static LABEL = nls.localize('switchWindow', "Switch Window..."); + static readonly LABEL = nls.localize('switchWindow', "Switch Window..."); constructor( id: string, label: string, - @IWindowService windowService: IWindowService, + @IElectronEnvironmentService electronEnvironmentService: IElectronEnvironmentService, @IQuickInputService quickInputService: IQuickInputService, @IKeybindingService keybindingService: IKeybindingService, @IModelService modelService: IModelService, @IModeService modeService: IModeService, @IElectronService electronService: IElectronService ) { - super(id, label, windowService, quickInputService, keybindingService, modelService, modeService, electronService); + super(id, label, electronEnvironmentService, quickInputService, keybindingService, modelService, modeService, electronService); } protected isQuickNavigate(): boolean { @@ -240,19 +240,19 @@ export class SwitchWindow extends BaseSwitchWindow { export class QuickSwitchWindow extends BaseSwitchWindow { static readonly ID = 'workbench.action.quickSwitchWindow'; - static LABEL = nls.localize('quickSwitchWindow', "Quick Switch Window..."); + static readonly LABEL = nls.localize('quickSwitchWindow', "Quick Switch Window..."); constructor( id: string, label: string, - @IWindowService windowService: IWindowService, + @IElectronEnvironmentService electronEnvironmentService: IElectronEnvironmentService, @IQuickInputService quickInputService: IQuickInputService, @IKeybindingService keybindingService: IKeybindingService, @IModelService modelService: IModelService, @IModeService modeService: IModeService, @IElectronService electronService: IElectronService ) { - super(id, label, windowService, quickInputService, keybindingService, modelService, modeService, electronService); + super(id, label, electronEnvironmentService, quickInputService, keybindingService, modelService, modeService, electronService); } protected isQuickNavigate(): boolean { diff --git a/src/vs/workbench/electron-browser/actions/workspaceActions.ts b/src/vs/workbench/electron-browser/actions/workspaceActions.ts deleted file mode 100644 index cfb1455a5d3..00000000000 --- a/src/vs/workbench/electron-browser/actions/workspaceActions.ts +++ /dev/null @@ -1,70 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Action } from 'vs/base/common/actions'; -import * as nls from 'vs/nls'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; - -export class SaveWorkspaceAsAction extends Action { - - static readonly ID = 'workbench.action.saveWorkspaceAs'; - static LABEL = nls.localize('saveWorkspaceAsAction', "Save Workspace As..."); - - constructor( - id: string, - label: string, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService - - ) { - super(id, label); - } - - async run(): Promise { - const configPathUri = await this.workspaceEditingService.pickNewWorkspacePath(); - if (configPathUri) { - switch (this.contextService.getWorkbenchState()) { - case WorkbenchState.EMPTY: - case WorkbenchState.FOLDER: - const folders = this.contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri })); - return this.workspaceEditingService.createAndEnterWorkspace(folders, configPathUri); - case WorkbenchState.WORKSPACE: - return this.workspaceEditingService.saveAndEnterWorkspace(configPathUri); - } - } - } -} - -export class DuplicateWorkspaceInNewWindowAction extends Action { - - static readonly ID = 'workbench.action.duplicateWorkspaceInNewWindow'; - static readonly LABEL = nls.localize('duplicateWorkspaceInNewWindow', "Duplicate Workspace in New Window"); - - constructor( - id: string, - label: string, - @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, - @IHostService private readonly hostService: IHostService, - @IWorkspacesService private readonly workspacesService: IWorkspacesService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { - super(id, label); - } - - async run(): Promise { - const folders = this.workspaceContextService.getWorkspace().folders; - const remoteAuthority = this.environmentService.configuration.remoteAuthority; - - const newWorkspace = await this.workspacesService.createUntitledWorkspace(folders, remoteAuthority); - await this.workspaceEditingService.copyWorkspaceSettings(newWorkspace); - - return this.hostService.openInWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true }); - } -} diff --git a/src/vs/workbench/electron-browser/desktop.contribution.ts b/src/vs/workbench/electron-browser/desktop.contribution.ts index 94a1259ed28..2afbed6f4ce 100644 --- a/src/vs/workbench/electron-browser/desktop.contribution.ts +++ b/src/vs/workbench/electron-browser/desktop.contribution.ts @@ -11,23 +11,24 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; -import { ToggleSharedProcessAction, ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; -import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseCurrentWindowAction, SwitchWindow, QuickSwitchWindow, RestartWithExtensionsDisabledAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-browser/actions/windowActions'; -import { SaveWorkspaceAsAction, DuplicateWorkspaceInNewWindowAction } from 'vs/workbench/electron-browser/actions/workspaceActions'; +import { ToggleSharedProcessAction, ToggleDevToolsAction, ConfigureRuntimeArgumentsAction } from 'vs/workbench/electron-browser/actions/developerActions'; +import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseCurrentWindowAction, SwitchWindow, QuickSwitchWindow, ReloadWindowWithExtensionsDisabledAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-browser/actions/windowActions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext } from 'vs/workbench/browser/contextkeys'; +import { IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext } from 'vs/workbench/browser/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import product from 'vs/platform/product/common/product'; // Actions (function registerActions(): void { const registry = Registry.as(Extensions.WorkbenchActions); - // Actions: View - (function registerViewActions(): void { + // Actions: Zoom + (function registerZoomActions(): void { const viewCategory = nls.localize('view', "View"); 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); @@ -65,14 +66,6 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; }); })(); - // Actions: Workspaces - (function registerWorkspaceActions(): void { - const workspacesCategory = nls.localize('workspaces', "Workspaces"); - - 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, SupportsWorkspacesContext); - })(); - // Actions: macOS Native Tabs (function registerMacOSNativeTabsActions(): void { if (isMacintosh) { @@ -98,7 +91,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; (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(RestartWithExtensionsDisabledAction, RestartWithExtensionsDisabledAction.ID, RestartWithExtensionsDisabledAction.LABEL), 'Developer: Restart With Extensions Disabled', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Developer: Reload With Extensions Disabled', developerCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL), 'Developer: Toggle Developer Tools', developerCategory); KeybindingsRegistry.registerKeybindingRule({ @@ -109,20 +102,16 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_I } }); })(); + + // Actions: Runtime Arguments + (function registerRuntimeArgumentsAction(): void { + const preferencesCategory = nls.localize('preferences', "Preferences"); + registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureRuntimeArgumentsAction, ConfigureRuntimeArgumentsAction.ID, ConfigureRuntimeArgumentsAction.LABEL), 'Preferences: Configure Runtime Arguments', preferencesCategory); + })(); })(); // Menu (function registerMenu(): void { - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '3_workspace', - command: { - id: SaveWorkspaceAsAction.ID, - title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...") - }, - order: 2, - when: SupportsWorkspacesContext - }); - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '6_close', command: { @@ -171,14 +160,16 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; order: 3 }); - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '3_feedback', - command: { - id: 'workbench.action.openIssueReporter', - title: nls.localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue") - }, - order: 3 - }); + if (!!product.reportIssueUrl) { + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '3_feedback', + command: { + id: 'workbench.action.openIssueReporter', + title: nls.localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue") + }, + order: 3 + }); + } // Tools MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { @@ -306,7 +297,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; 'default': false, 'scope': ConfigurationScope.APPLICATION, 'description': nls.localize('window.nativeTabs', "Enables macOS Sierra window tabs. Note that changes require a full restart to apply and that native tabs will disable a custom title bar style if configured."), - 'included': isMacintosh && parseFloat(os.release()) >= 16 // Minimum: macOS Sierra (10.12.x = darwin 16.x) + 'included': isMacintosh && parseFloat(os.release()) >= 17 // Minimum: macOS Sierra (10.13.x = darwin 17.x) }, 'window.nativeFullScreen': { 'type': 'boolean', @@ -341,3 +332,32 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; } }); })(); + +// JSON Schemas +(function registerJSONSchemas(): void { + const argvDefinitionFileSchemaId = 'vscode://schemas/argv'; + const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); + + jsonRegistry.registerSchema(argvDefinitionFileSchemaId, { + id: argvDefinitionFileSchemaId, + allowComments: true, + allowTrailingCommas: true, + description: 'VSCode static command line definition file', + type: 'object', + additionalProperties: false, + properties: { + locale: { + type: 'string', + description: nls.localize('argv.locale', 'The display Language to use. Picking a different language requires the associated language pack to be installed.') + }, + 'disable-hardware-acceleration': { + type: 'boolean', + description: nls.localize('argv.disableHardwareAcceleration', 'Disables hardware acceleration. ONLY change this option if you encounter graphic issues.') + }, + 'disable-color-correct-rendering': { + type: 'boolean', + description: nls.localize('argv.disableColorCorrectRendering', 'Resolves issues around color profile selection. ONLY change this option if you encounter graphic issues.') + } + } + }); +})(); diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index 076d03a5b1e..0163678d7fd 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -15,7 +15,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; -import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { stat } from 'vs/base/node/pfs'; @@ -24,7 +24,7 @@ import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { webFrame } from 'electron'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ConsoleLogService, MultiplexLogService, ILogService, ConsoleLogInMainService } from 'vs/platform/log/common/log'; -import { StorageService } from 'vs/platform/storage/node/storageService'; +import { NativeStorageService } from 'vs/platform/storage/node/storageService'; import { LoggerChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; import { Schemas } from 'vs/base/common/network'; import { sanitizeFilePath } from 'vs/base/common/extpath'; @@ -43,8 +43,7 @@ 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 { 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 { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; import { SpdLogService } from 'vs/platform/log/node/spdlogService'; import { SignService } from 'vs/platform/sign/node/signService'; @@ -53,14 +52,16 @@ import { FileUserDataProvider } from 'vs/workbench/services/userData/common/file import { basename } from 'vs/base/common/resources'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; +import { ElectronEnvironmentService, IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; -class CodeRendererMain extends Disposable { +class DesktopMain extends Disposable { - private readonly environmentService: WorkbenchEnvironmentService; + private readonly environmentService: NativeWorkbenchEnvironmentService; - constructor(configuration: IWindowConfiguration) { + constructor(private configuration: IWindowConfiguration) { super(); - this.environmentService = new WorkbenchEnvironmentService(configuration, configuration.execPath); + + this.environmentService = new NativeWorkbenchEnvironmentService(configuration, configuration.execPath, configuration.windowId); this.init(); } @@ -95,7 +96,7 @@ class CodeRendererMain extends Disposable { } const filesToWait = this.environmentService.configuration.filesToWait; - const filesToWaitPaths = filesToWait && filesToWait.paths; + const filesToWaitPaths = filesToWait?.paths; [filesToWaitPaths, this.environmentService.configuration.filesToOpenOrCreate, this.environmentService.configuration.filesToDiff].forEach(paths => { if (Array.isArray(paths)) { paths.forEach(path => { @@ -113,18 +114,15 @@ class CodeRendererMain extends Disposable { async open(): Promise { const services = await this.initServices(); + await domContentLoaded(); mark('willStartWorkbench'); // Create Workbench const workbench = new Workbench(document.body, services.serviceCollection, services.logService); - // Layout - this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true, workbench))); - - // Workbench Lifecycle - this._register(workbench.onShutdown(() => this.dispose())); - this._register(workbench.onWillShutdown(event => event.join(services.storageService.close()))); + // Listeners + this.registerListeners(workbench, services.storageService); // Startup const instantiationService = workbench.startup(); @@ -134,18 +132,23 @@ class CodeRendererMain extends Disposable { // Driver if (this.environmentService.configuration.driver) { - instantiationService.invokeFunction(async accessor => this._register(await registerWindowDriver(accessor))); - } - - // Config Exporter - if (this.environmentService.configuration['export-default-configuration']) { - instantiationService.createInstance(DefaultConfigurationExportHelper); + instantiationService.invokeFunction(async accessor => this._register(await registerWindowDriver(accessor, this.configuration.windowId))); } // Logging services.logService.trace('workbench configuration', JSON.stringify(this.environmentService.configuration)); } + private registerListeners(workbench: Workbench, storageService: NativeStorageService): void { + + // Layout + this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true, workbench))); + + // Workbench Lifecycle + this._register(workbench.onShutdown(() => this.dispose())); + this._register(workbench.onWillShutdown(event => event.join(storageService.close()))); + } + private onWindowResize(e: Event, retry: boolean, workbench: Workbench): void { if (e.target === window) { if (window.document && window.document.body && window.document.body.clientWidth === 0) { @@ -164,7 +167,7 @@ class CodeRendererMain extends Disposable { } } - private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: StorageService }> { + private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: NativeStorageService }> { const serviceCollection = new ServiceCollection(); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -173,11 +176,15 @@ class CodeRendererMain extends Disposable { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Main Process - const mainProcessService = this._register(new MainProcessService(this.environmentService.configuration.windowId)); + const mainProcessService = this._register(new MainProcessService(this.configuration.windowId)); serviceCollection.set(IMainProcessService, mainProcessService); // Environment serviceCollection.set(IWorkbenchEnvironmentService, this.environmentService); + serviceCollection.set(IElectronEnvironmentService, new ElectronEnvironmentService( + this.configuration.windowId, + this.environmentService.sharedIPCHandle + )); // Product serviceCollection.set(IProductService, { _serviceBrand: undefined, ...product }); @@ -210,7 +217,7 @@ class CodeRendererMain extends Disposable { const connection = remoteAgentService.getConnection(); if (connection) { const channel = connection.getChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME); - const remoteFileSystemProvider = this._register(new RemoteExtensionsFileSystemProvider(channel, remoteAgentService.getEnvironment())); + const remoteFileSystemProvider = this._register(new RemoteFileSystemProvider(channel, remoteAgentService.getEnvironment())); fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider); } @@ -328,9 +335,9 @@ class CodeRendererMain extends Disposable { } } - private async createStorageService(payload: IWorkspaceInitializationPayload, 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, this.environmentService); + const storageService = new NativeStorageService(globalStorageDatabase, logService, this.environmentService); try { await storageService.initialize(payload); @@ -359,7 +366,7 @@ class CodeRendererMain extends Disposable { else { loggers.push( new ConsoleLogService(this.environmentService.configuration.logLevel), - new SpdLogService(`renderer${this.environmentService.configuration.windowId}`, environmentService.logsPath, this.environmentService.configuration.logLevel) + new SpdLogService(`renderer${this.configuration.windowId}`, environmentService.logsPath, this.environmentService.configuration.logLevel) ); } @@ -368,7 +375,7 @@ class CodeRendererMain extends Disposable { } export function main(configuration: IWindowConfiguration): Promise { - const renderer = new CodeRendererMain(configuration); + const renderer = new DesktopMain(configuration); return renderer.open(); } diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 6cc69b81369..23ea962fdf8 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -9,13 +9,12 @@ import * as errors from 'vs/base/common/errors'; import { equals, deepClone, assign } from 'vs/base/common/objects'; import * as DOM from 'vs/base/browser/dom'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IAction, Action } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { IFileService } from 'vs/platform/files/common/files'; import { toResource, IUntitledResourceInput, SideBySideEditor, pathsToEditors } from 'vs/workbench/common/editor'; import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWindowsService, IWindowService, IWindowSettings, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest, IRunActionInWindowRequest, IRunKeybindingInWindowRequest, getTitleBarStyle } from 'vs/platform/windows/common/windows'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IWindowSettings, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest, IRunActionInWindowRequest, IRunKeybindingInWindowRequest, getTitleBarStyle } from 'vs/platform/windows/common/windows'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { IWorkbenchThemeService, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService'; import * as browser from 'vs/base/browser/browser'; @@ -23,14 +22,14 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c import { IResourceInput } from 'vs/platform/editor/common/editor'; 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 { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction, SubmenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { RunOnceScheduler } from 'vs/base/common/async'; 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 { IWorkspaceFolderCreationData, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; import { isRootUser, isWindows, isMacintosh, isLinux } from 'vs/base/common/platform'; import product from 'vs/platform/product/common/product'; @@ -50,9 +49,8 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IUpdateService } from 'vs/platform/update/common/update'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IPreferencesService } from '../services/preferences/common/preferences'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IMenubarService, IMenubarData, IMenubarMenu, IMenubarKeybinding, IMenubarMenuItemSubmenu, IMenubarMenuItemAction, MenubarMenuItem } from 'vs/platform/menubar/node/menubar'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { withNullAsUndefined, assertIsDefined } from 'vs/base/common/types'; import { IOpenerService, OpenOptions } from 'vs/platform/opener/common/opener'; import { Schemas } from 'vs/base/common/network'; import { IElectronService } from 'vs/platform/electron/node/electron'; @@ -61,17 +59,7 @@ import { getBaseLabel } from 'vs/base/common/labels'; import { ITunnelService, extractLocalHostUriMetaDataForPortMapping } from 'vs/platform/remote/common/tunnel'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; - -const TextInputActions: IAction[] = [ - new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))), - new Action('redo', nls.localize('redo', "Redo"), undefined, true, () => Promise.resolve(document.execCommand('redo'))), - new Separator(), - new Action('editor.action.clipboardCutAction', nls.localize('cut', "Cut"), undefined, true, () => Promise.resolve(document.execCommand('cut'))), - new Action('editor.action.clipboardCopyAction', nls.localize('copy', "Copy"), undefined, true, () => Promise.resolve(document.execCommand('copy'))), - new Action('editor.action.clipboardPasteAction', nls.localize('paste', "Paste"), undefined, true, () => Promise.resolve(document.execCommand('paste'))), - new Separator(), - new Action('editor.action.selectAll', nls.localize('selectAll', "Select All"), undefined, true, () => Promise.resolve(document.execCommand('selectAll'))) -]; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; export class ElectronWindow extends Disposable { @@ -90,14 +78,12 @@ export class ElectronWindow extends Disposable { constructor( @IEditorService private readonly editorService: EditorServiceImpl, - @IWindowService private readonly windowService: IWindowService, @IConfigurationService private readonly configurationService: IConfigurationService, @ITitleService private readonly titleService: ITitleService, @IWorkbenchThemeService protected themeService: IWorkbenchThemeService, @INotificationService private readonly notificationService: INotificationService, @ICommandService private readonly commandService: ICommandService, @IKeybindingService private readonly keybindingService: IKeybindingService, - @IContextMenuService private readonly contextMenuService: IContextMenuService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, @IFileService private readonly fileService: IFileService, @@ -112,7 +98,8 @@ export class ElectronWindow extends Disposable { @IOpenerService private readonly openerService: IOpenerService, @IElectronService private readonly electronService: IElectronService, @ITunnelService private readonly tunnelService: ITunnelService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService ) { super(); @@ -205,7 +192,7 @@ export class ElectronWindow extends Disposable { // High Contrast Events ipc.on('vscode:enterHighContrast', async () => { const windowConfig = this.configurationService.getValue('window'); - if (windowConfig && windowConfig.autoDetectHighContrast) { + if (windowConfig?.autoDetectHighContrast) { await this.lifecycleService.when(LifecyclePhase.Ready); this.themeService.setColorTheme(VS_HC_THEME, undefined); } @@ -213,7 +200,7 @@ export class ElectronWindow extends Disposable { ipc.on('vscode:leaveHighContrast', async () => { const windowConfig = this.configurationService.getValue('window'); - if (windowConfig && windowConfig.autoDetectHighContrast) { + if (windowConfig?.autoDetectHighContrast) { await this.lifecycleService.when(LifecyclePhase.Ready); this.themeService.restoreColorTheme(); } @@ -239,9 +226,6 @@ export class ElectronWindow extends Disposable { } })); - // Context menu support in input/textarea - window.document.addEventListener('contextmenu', e => this.onContextMenu(e)); - // Listen to visible editor changes this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange())); @@ -269,7 +253,7 @@ export class ElectronWindow extends Disposable { // Maximize/Restore on doubleclick (for macOS custom title) if (isMacintosh && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { - const titlePart = this.layoutService.getContainer(Parts.TITLEBAR_PART); + const titlePart = assertIsDefined(this.layoutService.getContainer(Parts.TITLEBAR_PART)); this._register(DOM.addDisposableListener(titlePart, DOM.EventType.DBLCLICK, e => { DOM.EventHelper.stop(e); @@ -300,21 +284,6 @@ export class ElectronWindow extends Disposable { } } - private onContextMenu(e: MouseEvent): void { - if (e.target instanceof HTMLElement) { - const target = e.target; - if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) { - DOM.EventHelper.stop(e, true); - - this.contextMenuService.showContextMenu({ - getAnchor: () => e, - getActions: () => TextInputActions, - onHide: () => target.focus() // fixes https://github.com/Microsoft/vscode/issues/52948 - }); - } - } - } - private updateWindowZoomLevel(): void { const windowConfig: IWindowsConfiguration = this.configurationService.getValue(); @@ -390,7 +359,7 @@ export class ElectronWindow extends Disposable { this.setupOpenHandlers(); // 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.electronEnvironmentService.windowId)); // Integrity warning this.integrityService.isPure().then(res => this.titleService.updateProperties({ isPure: res.isPure })); @@ -454,7 +423,7 @@ export class ElectronWindow extends Disposable { this.openerService.registerExternalUriResolver({ resolveExternalUri: async (uri: URI, options?: OpenOptions) => { - if (options && options.allowTunneling) { + if (options?.allowTunneling) { const portMappingRequest = extractLocalHostUriMetaDataForPortMapping(uri); if (portMappingRequest) { const tunnel = await this.tunnelService.openTunnel(portMappingRequest.port); @@ -474,7 +443,7 @@ export class ElectronWindow extends Disposable { private shouldOpenExternal(resource: URI, options?: OpenOptions) { const scheme = resource.scheme.toLowerCase(); const preferOpenExternal = (scheme === Schemas.mailto || scheme === Schemas.http || scheme === Schemas.https); - return (options && options.openExternal) || preferOpenExternal; + return options?.openExternal || preferOpenExternal; } private updateTouchbarMenu(): void { @@ -663,8 +632,8 @@ export class ElectronWindow extends Disposable { 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 } }); + if (diffMode && resources.length === 2 && resources[0].resource && resources[1].resource) { + 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 @@ -680,8 +649,7 @@ export class ElectronWindow extends Disposable { class NativeMenubarControl extends MenubarControl { constructor( @IMenuService menuService: IMenuService, - @IWindowService windowService: IWindowService, - @IWindowsService windowsService: IWindowsService, + @IWorkspacesService workspacesService: IWorkspacesService, @IContextKeyService contextKeyService: IContextKeyService, @IKeybindingService keybindingService: IKeybindingService, @IConfigurationService configurationService: IConfigurationService, @@ -690,15 +658,15 @@ class NativeMenubarControl extends MenubarControl { @IStorageService storageService: IStorageService, @INotificationService notificationService: INotificationService, @IPreferencesService preferencesService: IPreferencesService, - @IEnvironmentService environmentService: IEnvironmentService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IAccessibilityService accessibilityService: IAccessibilityService, @IMenubarService private readonly menubarService: IMenubarService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService ) { super( menuService, - windowService, - windowsService, + workspacesService, contextKeyService, keybindingService, configurationService, @@ -724,21 +692,26 @@ class NativeMenubarControl extends MenubarControl { } } - this.windowService.getRecentlyOpened().then((recentlyOpened) => { - this.recentlyOpened = recentlyOpened; + (async () => { + this.recentlyOpened = await this.workspacesService.getRecentlyOpened(); this.doUpdateMenubar(true); - }); + })(); this.registerListeners(); } protected doUpdateMenubar(firstTime: boolean): void { + // Since the native menubar is shared between windows (main process) + // only allow the focused window to update the menubar + if (!this.hostService.hasFocus) { + return; + } // Send menus to main process to be rendered by Electron const menubarData = { menus: {}, keybindings: {} }; if (this.getMenubarMenus(menubarData)) { - this.menubarService.updateMenubar(this.windowService.windowId, menubarData); + this.menubarService.updateMenubar(this.electronEnvironmentService.windowId, menubarData); } } @@ -774,8 +747,8 @@ class NativeMenubarControl extends MenubarControl { const submenu = { items: [] }; if (!this.menus[menuItem.item.submenu]) { - this.menus[menuItem.item.submenu] = this.menuService.createMenu(menuItem.item.submenu, this.contextKeyService); - this._register(this.menus[menuItem.item.submenu]!.onDidChange(() => this.updateMenubar())); + const menu = this.menus[menuItem.item.submenu] = this.menuService.createMenu(menuItem.item.submenu, this.contextKeyService); + this._register(menu.onDidChange(() => this.updateMenubar())); } const menuToDispose = this.menuService.createMenu(menuItem.item.submenu, this.contextKeyService); diff --git a/src/vs/workbench/services/accessibility/node/accessibilityService.ts b/src/vs/workbench/services/accessibility/node/accessibilityService.ts index ac9bb03fd85..1c698443b36 100644 --- a/src/vs/workbench/services/accessibility/node/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/node/accessibilityService.ts @@ -10,19 +10,30 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/abstractAccessibilityService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; + +interface AccessibilityMetrics { + enabled: boolean; +} +type AccessibilityMetricsClassification = { + enabled: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; +}; export class AccessibilityService extends AbstractAccessibilityService implements IAccessibilityService { _serviceBrand: undefined; private _accessibilitySupport = AccessibilitySupport.Unknown; + private didSendTelemetry = false; constructor( - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IContextKeyService readonly contextKeyService: IContextKeyService, - @IConfigurationService readonly configurationService: IConfigurationService + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IContextKeyService contextKeyService: IContextKeyService, + @IConfigurationService configurationService: IConfigurationService, + @ITelemetryService private readonly _telemetryService: ITelemetryService ) { super(contextKeyService, configurationService); + this.setAccessibilitySupport(environmentService.configuration.accessibilitySupport ? AccessibilitySupport.Enabled : AccessibilitySupport.Disabled); } alwaysUnderlineAccessKeys(): Promise { @@ -51,14 +62,14 @@ export class AccessibilityService extends AbstractAccessibilityService implement this._accessibilitySupport = accessibilitySupport; this._onDidChangeAccessibilitySupport.fire(); + + if (!this.didSendTelemetry && accessibilitySupport === AccessibilitySupport.Enabled) { + this._telemetryService.publicLog2('accessibility', { enabled: true }); + this.didSendTelemetry = true; + } } getAccessibilitySupport(): AccessibilitySupport { - if (this._accessibilitySupport === AccessibilitySupport.Unknown) { - const config = this.environmentService.configuration; - this._accessibilitySupport = (config && config.accessibilitySupport) ? AccessibilitySupport.Enabled : AccessibilitySupport.Disabled; - } - return this._accessibilitySupport; } } diff --git a/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts b/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts new file mode 100644 index 00000000000..b5a2b2d0c0a --- /dev/null +++ b/src/vs/workbench/services/authToken/electron-browser/authTokenService.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 { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Emitter, Event } from 'vs/base/common/event'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; + +export class AuthTokenService extends Disposable implements IAuthTokenService { + + _serviceBrand: undefined; + + private readonly channel: IChannel; + + private _status: AuthTokenStatus = AuthTokenStatus.Disabled; + get status(): AuthTokenStatus { return this._status; } + private _onDidChangeStatus: Emitter = this._register(new Emitter()); + readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + + constructor( + @ISharedProcessService sharedProcessService: ISharedProcessService + ) { + super(); + this.channel = sharedProcessService.getChannel('authToken'); + this.channel.call('_getInitialStatus').then(status => { + this.updateStatus(status); + this._register(this.channel.listen('onDidChangeStatus')(status => this.updateStatus(status))); + }); + } + + getToken(): Promise { + return this.channel.call('getToken'); + } + + updateToken(token: string): Promise { + return this.channel.call('updateToken', [token]); + } + + refreshToken(): Promise { + return this.channel.call('getToken'); + } + + deleteToken(): Promise { + return this.channel.call('deleteToken'); + } + + private async updateStatus(status: AuthTokenStatus): Promise { + this._status = status; + this._onDidChangeStatus.fire(status); + } + +} + +registerSingleton(IAuthTokenService, AuthTokenService); diff --git a/src/vs/workbench/services/backup/common/backup.ts b/src/vs/workbench/services/backup/common/backup.ts index 0f13f6c8a42..61f89319ae7 100644 --- a/src/vs/workbench/services/backup/common/backup.ts +++ b/src/vs/workbench/services/backup/common/backup.ts @@ -6,8 +6,6 @@ import { URI } from 'vs/base/common/uri'; import { createDecorator } 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'); @@ -88,7 +86,3 @@ 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))!); -} diff --git a/src/vs/workbench/services/backup/common/backupFileService.ts b/src/vs/workbench/services/backup/common/backupFileService.ts index de81c2b7d58..3227c161765 100644 --- a/src/vs/workbench/services/backup/common/backupFileService.ts +++ b/src/vs/workbench/services/backup/common/backupFileService.ts @@ -429,13 +429,13 @@ export class InMemoryBackupFileService implements IBackupFileService { return Promise.resolve(); } - resolveBackupContent(backupResource: URI): Promise> { + async resolveBackupContent(backupResource: URI): Promise> { const snapshot = this.backups.get(backupResource.toString()); if (snapshot) { - return Promise.resolve({ value: createTextBufferFactoryFromSnapshot(snapshot) }); + return { value: createTextBufferFactoryFromSnapshot(snapshot) }; } - return Promise.reject('Unexpected backup resource to resolve'); + throw new Error('Unexpected backup resource to resolve'); } getWorkspaceFileBackups(): Promise { diff --git a/src/vs/workbench/services/backup/electron-browser/backup.ts b/src/vs/workbench/services/backup/electron-browser/backup.ts new file mode 100644 index 00000000000..6d6bfd34246 --- /dev/null +++ b/src/vs/workbench/services/backup/electron-browser/backup.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 { URI } from 'vs/base/common/uri'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { joinPath, relativePath } from 'vs/base/common/resources'; + +export function toBackupWorkspaceResource(backupWorkspacePath: string, environmentService: IEnvironmentService): URI { + return joinPath(environmentService.userRoamingDataHome, relativePath(URI.file(environmentService.userDataPath), URI.file(backupWorkspacePath))!); +} diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts similarity index 99% rename from src/vs/workbench/services/backup/test/node/backupFileService.test.ts rename to src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts index 80809f4d14d..02fae436721 100644 --- a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts @@ -20,7 +20,7 @@ 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 { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService } from 'vs/platform/files/common/files'; @@ -46,10 +46,10 @@ 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 { +class TestBackupEnvironmentService extends NativeWorkbenchEnvironmentService { constructor(backupPath: string) { - super({ ...parseArgs(process.argv, OPTIONS), ...{ backupPath, 'user-data-dir': userdataDir } } as IWindowConfiguration, process.execPath); + super({ ...parseArgs(process.argv, OPTIONS), ...{ backupPath, 'user-data-dir': userdataDir } } as IWindowConfiguration, process.execPath, 0); } } diff --git a/src/vs/platform/clipboard/browser/clipboardService.ts b/src/vs/workbench/services/clipboard/browser/clipboardService.ts similarity index 100% rename from src/vs/platform/clipboard/browser/clipboardService.ts rename to src/vs/workbench/services/clipboard/browser/clipboardService.ts diff --git a/src/vs/platform/clipboard/electron-browser/clipboardService.ts b/src/vs/workbench/services/clipboard/electron-browser/clipboardService.ts similarity index 75% rename from src/vs/platform/clipboard/electron-browser/clipboardService.ts rename to src/vs/workbench/services/clipboard/electron-browser/clipboardService.ts index 3b269b200fc..623385c0a79 100644 --- a/src/vs/platform/clipboard/electron-browser/clipboardService.ts +++ b/src/vs/workbench/services/clipboard/electron-browser/clipboardService.ts @@ -7,10 +7,11 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { clipboard } from 'electron'; import { URI } from 'vs/base/common/uri'; import { isMacintosh } from 'vs/base/common/platform'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -export class ClipboardService implements IClipboardService { +export class NativeClipboardService implements IClipboardService { - private static FILE_FORMAT = 'code/file-list'; // Clipboard format for files + private static readonly FILE_FORMAT = 'code/file-list'; // Clipboard format for files _serviceBrand: undefined; @@ -42,16 +43,16 @@ export class ClipboardService implements IClipboardService { writeResources(resources: URI[]): void { if (resources.length) { - clipboard.writeBuffer(ClipboardService.FILE_FORMAT, this.resourcesToBuffer(resources)); + clipboard.writeBuffer(NativeClipboardService.FILE_FORMAT, this.resourcesToBuffer(resources)); } } readResources(): URI[] { - return this.bufferToResources(clipboard.readBuffer(ClipboardService.FILE_FORMAT)); + return this.bufferToResources(clipboard.readBuffer(NativeClipboardService.FILE_FORMAT)); } hasResources(): boolean { - return clipboard.has(ClipboardService.FILE_FORMAT); + return clipboard.has(NativeClipboardService.FILE_FORMAT); } private resourcesToBuffer(resources: URI[]): Buffer { @@ -75,3 +76,5 @@ export class ClipboardService implements IClipboardService { } } } + +registerSingleton(IClipboardService, NativeClipboardService, true); diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index 589d4fa7fc5..d3af9e42aee 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -465,7 +465,7 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork } private consolidate(): void { - this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel); + this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel, this.workspaceConfigurationModelParser.tasksModel); } private watchWorkspaceConfigurationFile(): IDisposable { @@ -509,7 +509,7 @@ class CachedWorkspaceConfiguration extends Disposable implements IWorkspaceConfi const contents = await this.configurationCache.read(key); this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(key.key); this.workspaceConfigurationModelParser.parseContent(contents); - this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel); + this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel, this.workspaceConfigurationModelParser.tasksModel); } catch (e) { } } diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 5df245052bf..1dad86d6bec 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -33,7 +33,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic public _serviceBrand: undefined; - private workspace: Workspace; + private workspace!: Workspace; private completeWorkspaceBarrier: Barrier; private readonly configurationCache: IConfigurationCache; private _configuration: Configuration; @@ -59,10 +59,10 @@ export class WorkspaceService extends Disposable implements IConfigurationServic protected readonly _onDidChangeWorkbenchState: Emitter = this._register(new Emitter()); public readonly onDidChangeWorkbenchState: Event = this._onDidChangeWorkbenchState.event; - private configurationEditingService: ConfigurationEditingService; - private jsonEditingService: JSONEditingService; - - private cyclicDependencyReady: Function; + // TODO@sandeep debt with cyclic dependencies + private configurationEditingService!: ConfigurationEditingService; + private jsonEditingService!: JSONEditingService; + private cyclicDependencyReady!: Function; private cyclicDependency = new Promise(resolve => this.cyclicDependencyReady = resolve); constructor( diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index a5f15850dbf..a470043aa73 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -15,6 +15,7 @@ export const machineSettingsSchemaId = 'vscode://schemas/settings/machine'; export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace'; export const folderSettingsSchemaId = 'vscode://schemas/settings/folder'; export const launchSchemaId = 'vscode://schemas/launch'; +export const tasksSchemaId = 'vscode://schemas/tasks'; export const LOCAL_MACHINE_SCOPES = [ConfigurationScope.APPLICATION, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]; export const REMOTE_MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.MACHINE_OVERRIDABLE]; diff --git a/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts index d0458c430a5..ead4e246a36 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditingService.ts @@ -409,7 +409,7 @@ export class ConfigurationEditingService { return false; } const parseErrors: json.ParseError[] = []; - json.parse(model.getValue(), parseErrors); + json.parse(model.getValue(), parseErrors, { allowTrailingComma: true, allowEmptyContent: true }); return parseErrors.length > 0; } @@ -428,11 +428,6 @@ export class ConfigurationEditingService { if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, target, operation); } - - // Workspace tasks are not supported - if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === EditableConfigurationTarget.WORKSPACE) { - return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET, target, operation); - } } // Target cannot be workspace or folder if no workspace opened diff --git a/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts index 7a30ad06477..9d2f6ad88df 100644 --- a/src/vs/workbench/services/configuration/common/configurationModels.ts +++ b/src/vs/workbench/services/configuration/common/configurationModels.ts @@ -17,11 +17,13 @@ export class WorkspaceConfigurationModelParser extends ConfigurationModelParser private _folders: IStoredWorkspaceFolder[] = []; private _settingsModelParser: ConfigurationModelParser; private _launchModel: ConfigurationModel; + private _tasksModel: ConfigurationModel; constructor(name: string) { super(name); this._settingsModelParser = new ConfigurationModelParser(name, WORKSPACE_SCOPES); this._launchModel = new ConfigurationModel(); + this._tasksModel = new ConfigurationModel(); } get folders(): IStoredWorkspaceFolder[] { @@ -36,6 +38,10 @@ export class WorkspaceConfigurationModelParser extends ConfigurationModelParser return this._launchModel; } + get tasksModel(): ConfigurationModel { + return this._tasksModel; + } + reprocessWorkspaceSettings(): void { this._settingsModelParser.parse(); } @@ -44,6 +50,7 @@ export class WorkspaceConfigurationModelParser extends ConfigurationModelParser this._folders = (raw['folders'] || []) as IStoredWorkspaceFolder[]; this._settingsModelParser.parseRaw(raw['settings']); this._launchModel = this.createConfigurationModelFrom(raw, 'launch'); + this._tasksModel = this.createConfigurationModelFrom(raw, 'tasks'); return super.doParseRaw(raw); } diff --git a/src/vs/workbench/services/configuration/common/jsonEditingService.ts b/src/vs/workbench/services/configuration/common/jsonEditingService.ts index f6ffc3ef655..10f76510c7e 100644 --- a/src/vs/workbench/services/configuration/common/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/common/jsonEditingService.ts @@ -98,7 +98,7 @@ export class JSONEditingService implements IJSONEditingService { private hasParseErrors(model: ITextModel): boolean { const parseErrors: json.ParseError[] = []; - json.parse(model.getValue(), parseErrors); + json.parse(model.getValue(), parseErrors, { allowTrailingComma: true, allowEmptyContent: true }); return parseErrors.length > 0; } 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 c3fc2b97536..7ad581196cc 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 @@ -39,14 +39,14 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro import { IFileService } from 'vs/platform/files/common/files'; import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; import { KeybindingsEditingService, IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; -import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; -class TestEnvironmentService extends WorkbenchEnvironmentService { +class TestEnvironmentService extends NativeWorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath, 0); } get appSettingsHome() { return this._appSettingsHome; } @@ -185,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: undefined, notify: null!, error: null!, info: null!, warn: null!, status: null! }); + instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: undefined, notify: null!, error: null!, info: null!, warn: null!, status: null!, setFilter: 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 0319242c43f..cb1792bd9f0 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 @@ -45,13 +45,13 @@ import { IConfigurationCache } from 'vs/workbench/services/configuration/common/ 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 { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -class TestEnvironmentService extends WorkbenchEnvironmentService { +class TestEnvironmentService extends NativeWorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath, 0); } get appSettingsHome() { return this._appSettingsHome; } @@ -1406,6 +1406,53 @@ suite('WorkspaceConfigurationService-Multiroot', () => { }); }); + + test('get tasks configuration', () => { + const expectedTasksConfiguration = { + 'version': '2.0.0', + 'tasks': [ + { + 'label': 'Run Dev', + 'type': 'shell', + 'command': './scripts/code.sh', + 'windows': { + 'command': '.\\scripts\\code.bat' + }, + 'problemMatcher': [] + } + ] + }; + return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'tasks', value: expectedTasksConfiguration }], true) + .then(() => testObject.reloadConfiguration()) + .then(() => { + const actual = testObject.getValue('tasks'); + assert.deepEqual(actual, expectedTasksConfiguration); + }); + }); + + test('inspect tasks configuration', () => { + const expectedTasksConfiguration = { + 'version': '2.0.0', + 'tasks': [ + { + 'label': 'Run Dev', + 'type': 'shell', + 'command': './scripts/code.sh', + 'windows': { + 'command': '.\\scripts\\code.bat' + }, + 'problemMatcher': [] + } + ] + }; + return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'tasks', value: expectedTasksConfiguration }], true) + .then(() => testObject.reloadConfiguration()) + .then(() => { + const actual = testObject.inspect('tasks').workspace; + assert.deepEqual(actual, expectedTasksConfiguration); + }); + }); + test('update user configuration', () => { return testObject.updateValue('configurationService.workspace.testSetting', 'userValue', ConfigurationTarget.USER) .then(() => assert.equal(testObject.getValue('configurationService.workspace.testSetting'), 'userValue')); @@ -1483,25 +1530,17 @@ suite('WorkspaceConfigurationService-Multiroot', () => { .then(() => assert.deepEqual(testObject.getValue('tasks', { resource: workspace.folders[0].uri }), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] })); }); - test('update tasks configuration in a workspace is not supported', () => { - const workspace = workspaceContextService.getWorkspace(); - return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true) - .then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET)); - }); - test('update launch configuration in a workspace', () => { const workspace = workspaceContextService.getWorkspace(); return testObject.updateValue('launch', { 'version': '1.0.0', configurations: [{ 'name': 'myLaunch' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true) .then(() => assert.deepEqual(testObject.getValue('launch'), { 'version': '1.0.0', configurations: [{ 'name': 'myLaunch' }] })); }); - test('task configurations are not read from workspace', () => { - return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'tasks', value: { 'version': '1.0' } }], true) - .then(() => testObject.reloadConfiguration()) - .then(() => { - const actual = testObject.inspect('tasks.version'); - assert.equal(actual.workspace, undefined); - }); + test('update tasks configuration in a workspace', () => { + const workspace = workspaceContextService.getWorkspace(); + const tasks = { 'version': '2.0.0', tasks: [{ 'label': 'myTask' }] }; + return testObject.updateValue('tasks', tasks, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true) + .then(() => assert.deepEqual(testObject.getValue('tasks'), tasks)); }); test('configuration of newly added folder is available on configuration change event', async () => { diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index 882b085ff97..220b9d988e9 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -25,7 +25,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export abstract class BaseConfigurationResolverService extends AbstractVariableResolverService { - static INPUT_OR_COMMAND_VARIABLES_PATTERN = /\${((input|command):(.*?))}/g; + static readonly INPUT_OR_COMMAND_VARIABLES_PATTERN = /\${((input|command):(.*?))}/g; constructor( envVariables: IProcessEnvironment, @@ -88,10 +88,10 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR public async resolveWithInteractionReplace(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise { // resolve any non-interactive variables and any contributed variables - config = await this.resolveAny(folder, config); + config = this.resolveAny(folder, config); // resolve input variables in the order in which they are encountered - return this.resolveWithInteraction(folder, config, section, variables, true).then(mapping => { + return this.resolveWithInteraction(folder, config, section, variables).then(mapping => { // finally substitute evaluated command variables (if there are any) if (!mapping) { return null; @@ -103,7 +103,7 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR }); } - public async resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary, skipContributed: boolean = false): Promise | undefined> { + public async resolveWithInteraction(folder: IWorkspaceFolder | undefined, config: any, section?: string, variables?: IStringDictionary): Promise | undefined> { // resolve any non-interactive variables and any contributed variables const resolved = await this.resolveAnyMap(folder, config); config = resolved.newConfig; @@ -180,6 +180,11 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR throw new Error(nls.localize('commandVariable.noStringType', "Cannot substitute command variable '{0}' because command did not return a result of type string.", commandId)); } break; + default: + // Try to resolve it as a contributed variable + if (this._contributedVariables.has(variable)) { + result = await this._contributedVariables.get(variable)!(); + } } if (typeof result === 'string') { @@ -208,6 +213,11 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR } } } + this._contributedVariables.forEach((value, contributed: string) => { + if ((variables.indexOf(contributed) < 0) && (object.indexOf('${' + contributed + '}') >= 0)) { + variables.push(contributed); + } + }); } else if (Types.isArray(object)) { object.forEach(value => { this.findVariables(value, variables); diff --git a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts index ea98be3d578..df0da9e454f 100644 --- a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts @@ -20,7 +20,7 @@ export interface IConfigurationResolverService { * Recursively resolves all variables in the given config and returns a copy of it with substituted values. * Command variables are only substituted if a "commandValueMapping" dictionary is given and if it contains an entry for the command. */ - resolveAny(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise; + resolveAny(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): any; /** * Recursively resolves all variables (including commands and user input) in the given config and returns a copy of it with substituted values. diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts index 469a3ea58b8..c6f302d1b3c 100644 --- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -27,12 +27,12 @@ export interface IVariableResolveContext { export class AbstractVariableResolverService implements IConfigurationResolverService { - static VARIABLE_REGEXP = /\$\{(.*?)\}/g; - static VARIABLE_REGEXP_SINGLE = /\$\{(.*?)\}/; + static readonly VARIABLE_REGEXP = /\$\{(.*?)\}/g; + static readonly VARIABLE_REGEXP_SINGLE = /\$\{(.*?)\}/; _serviceBrand: undefined; - private _contributedVariables: Map Promise> = new Map(); + protected _contributedVariables: Map Promise> = new Map(); constructor( private _context: IVariableResolveContext, @@ -53,7 +53,8 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return this.recursiveResolve(root ? root.uri : undefined, value); } - private async resolveAnyBase(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): Promise { + public resolveAnyBase(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): any { + const result = objects.deepClone(config) as any; // hoist platform specific attributes to top level @@ -71,16 +72,16 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe delete result.linux; // substitute all variables recursively in string values - return this.recursiveResolvePromise(workspaceFolder ? workspaceFolder.uri : undefined, result, commandValueMapping, resolvedVariables); + return this.recursiveResolve(workspaceFolder ? workspaceFolder.uri : undefined, result, commandValueMapping, resolvedVariables); } - public resolveAny(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise { + public resolveAny(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): any { return this.resolveAnyBase(workspaceFolder, config, commandValueMapping); } - protected async resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }> { + public resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): { newConfig: any, resolvedVariables: Map } { const resolvedVariables = new Map(); - const newConfig = await this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables); + const newConfig = this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables); return { newConfig, resolvedVariables }; } @@ -116,23 +117,6 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return value; } - private async recursiveResolvePromise(folderUri: uri | undefined, value: any, commandValueMapping?: IStringDictionary, resolvedVariables?: Map): Promise { - if (types.isString(value)) { - return this.resolveStringPromise(folderUri, value, commandValueMapping, resolvedVariables); - } else if (types.isArray(value)) { - return Promise.all(value.map(s => this.recursiveResolvePromise(folderUri, s, commandValueMapping, resolvedVariables))); - } else if (types.isObject(value)) { - let result: IStringDictionary | string[]> = Object.create(null); - const keys = Object.keys(value); - for (let key of keys) { - const replaced = await this.resolveStringPromise(folderUri, key, commandValueMapping, resolvedVariables); - result[replaced] = await this.recursiveResolvePromise(folderUri, value[key], commandValueMapping, resolvedVariables); - } - return result; - } - return value; - } - private resolveString(folderUri: uri | undefined, value: string, commandValueMapping: IStringDictionary | undefined, resolvedVariables?: Map): string { // loop through all variables occurrences in 'value' @@ -150,37 +134,6 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return replaced; } - private async resolveStringPromise(folderUri: uri | undefined, value: string, commandValueMapping: IStringDictionary | undefined, resolvedVariables?: Map): Promise { - // loop through all variables occurrences in 'value' - const matches = value.match(AbstractVariableResolverService.VARIABLE_REGEXP); - const replaces: Map = new Map(); - if (!matches) { - return value; - } - for (const match of matches) { - const evaluate = await this.evaluateSingleContributedVariable(match, match.match(AbstractVariableResolverService.VARIABLE_REGEXP_SINGLE)![1]); - if (evaluate !== match) { - replaces.set(match, evaluate); - } - } - - const replaced = value.replace(AbstractVariableResolverService.VARIABLE_REGEXP, (match: string, variable: string) => { - - let resolvedValue = this.evaluateSingleVariable(match, variable, folderUri, commandValueMapping); - if ((resolvedValue === match) && (replaces.has(match))) { - resolvedValue = replaces.get(match)!; - } - - if (resolvedVariables) { - resolvedVariables.set(variable, resolvedValue); - } - - return resolvedValue; - }); - - return replaced; - } - private evaluateSingleVariable(match: string, variable: string, folderUri: uri | undefined, commandValueMapping: IStringDictionary | undefined): string { // try to separate variable arguments from variable name @@ -323,25 +276,19 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return match; default: - return match; + try { + return this.resolveFromMap(match, variable, commandValueMapping, undefined); + } catch (error) { + return match; + } } } } } - private async evaluateSingleContributedVariable(match: string, variable: string): Promise { - if (this._contributedVariables.has(variable)) { - const contributedValue: string | undefined = await this._contributedVariables.get(variable)!(); - if (contributedValue !== undefined) { - return contributedValue; - } - } - return match; - } - - private resolveFromMap(match: string, argument: string | undefined, commandValueMapping: IStringDictionary | undefined, prefix: string): string { + private resolveFromMap(match: string, argument: string | undefined, commandValueMapping: IStringDictionary | undefined, prefix: string | undefined): string { if (argument && commandValueMapping) { - const v = commandValueMapping[prefix + ':' + argument]; + const v = (prefix === undefined) ? commandValueMapping[argument] : commandValueMapping[prefix + ':' + argument]; if (typeof v === 'string') { return v; } 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 6b29d49b2eb..41396579fb8 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 @@ -19,7 +19,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import * as Types from 'vs/base/common/types'; import { EditorType } from 'vs/editor/common/editorCommon'; import { Selection } from 'vs/editor/common/core/selection'; -import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -494,7 +494,7 @@ suite('Configuration Resolver Service', () => { 'name': '${' + variable + '}', }; configurationResolverService!.contributeVariable(variable, async () => { return buildTask; }); - return configurationResolverService!.resolveAny(workspace, configuration).then(result => { + return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration).then(result => { assert.deepEqual(result, { 'name': `${buildTask}` }); @@ -642,9 +642,9 @@ class MockInputsConfigurationService extends TestConfigurationService { } } -class MockWorkbenchEnvironmentService extends WorkbenchEnvironmentService { +class MockWorkbenchEnvironmentService extends NativeWorkbenchEnvironmentService { constructor(env: platform.IProcessEnvironment) { - super({ userEnv: env } as IWindowConfiguration, process.execPath); + super({ userEnv: env } as IWindowConfiguration, process.execPath, 0); } } diff --git a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index 410b7e8ed50..cea0688e45f 100644 --- a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -138,10 +138,19 @@ class NativeContextMenuService extends Disposable implements IContextMenuService // Normal Menu Item else { + let type: 'radio' | 'checkbox' | undefined = undefined; + if (!!entry.checked) { + if (typeof delegate.getCheckedActionsRepresentation === 'function') { + type = delegate.getCheckedActionsRepresentation(entry); + } else { + type = 'checkbox'; + } + } + const item: IContextMenuItem = { label: unmnemonicLabel(entry.label), - checked: !!entry.checked || !!entry.radio, - type: !!entry.checked ? 'checkbox' : !!entry.radio ? 'radio' : undefined, + checked: !!entry.checked, + type, enabled: !!entry.enabled, click: event => { @@ -188,4 +197,4 @@ class NativeContextMenuService extends Disposable implements IContextMenuService } } -registerSingleton(IContextMenuService, ContextMenuService, true); \ No newline at end of file +registerSingleton(IContextMenuService, ContextMenuService, true); diff --git a/src/vs/workbench/services/credentials/browser/credentialsService.ts b/src/vs/workbench/services/credentials/browser/credentialsService.ts index 20946f64ae1..d50c058d3aa 100644 --- a/src/vs/workbench/services/credentials/browser/credentialsService.ts +++ b/src/vs/workbench/services/credentials/browser/credentialsService.ts @@ -6,6 +6,7 @@ import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { find } from 'vs/base/common/arrays'; export interface ICredentialsProvider { getPassword(service: string, account: string): Promise; @@ -14,7 +15,7 @@ export interface ICredentialsProvider { deletePassword(service: string, account: string): Promise; findPassword(service: string): Promise; - findCredentials(service: string): Promise>; + findCredentials(service: string): Promise>; } export class BrowserCredentialsService implements ICredentialsService { @@ -47,7 +48,7 @@ export class BrowserCredentialsService implements ICredentialsService { return this.credentialsProvider.findPassword(service); } - findCredentials(service: string): Promise> { + findCredentials(service: string): Promise> { return this.credentialsProvider.findCredentials(service); } } @@ -88,17 +89,12 @@ class InMemoryCredentialsProvider implements ICredentialsProvider { return credential ? credential.password : null; } - private doFindPassword(service: string, account?: string): ICredential | null { - for (const credential of this.credentials) { - if (credential.service === service && (typeof account !== 'string' || credential.account === account)) { - return credential; - } - } - - return null; + private doFindPassword(service: string, account?: string): ICredential | undefined { + return find(this.credentials, credential => + credential.service === service && (typeof account !== 'string' || credential.account === account)); } - async findCredentials(service: string): Promise> { + async findCredentials(service: string): Promise> { return this.credentials .filter(credential => credential.service === service) .map(({ account, password }) => ({ account, password })); diff --git a/src/vs/workbench/services/credentials/common/credentials.ts b/src/vs/workbench/services/credentials/common/credentials.ts new file mode 100644 index 00000000000..6fcb7dffaa0 --- /dev/null +++ b/src/vs/workbench/services/credentials/common/credentials.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 { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const ICredentialsService = createDecorator('ICredentialsService'); + +export interface ICredentialsService { + + _serviceBrand: undefined; + + getPassword(service: string, account: string): Promise; + setPassword(service: string, account: string, password: string): Promise; + deletePassword(service: string, account: string): Promise; + findPassword(service: string): Promise; + findCredentials(service: string): Promise>; +} diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 69a276b3bc4..45842b7fa45 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -20,7 +20,7 @@ export interface IDecorationData { readonly bubble?: boolean; } -export interface IDecoration { +export interface IDecoration extends IDisposable { readonly tooltip: string; readonly labelClassName: string; readonly badgeClassName: string; @@ -28,7 +28,7 @@ export interface IDecoration { export interface IDecorationsProvider { readonly label: string; - readonly onDidChange: Event; + readonly onDidChange: Event; provideDecorations(uri: URI, token: CancellationToken): IDecorationData | Promise | undefined; } diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index a10d68678a5..625b120eb8e 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,18 +7,18 @@ import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; -import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; import { LinkedList } from 'vs/base/common/linkedList'; import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { IdGenerator } from 'vs/base/common/idGenerator'; -import { Iterator } from 'vs/base/common/iterator'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { localize } from 'vs/nls'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; class DecorationRule { @@ -38,6 +38,8 @@ class DecorationRule { readonly itemBadgeClassName: string; readonly bubbleBadgeClassName: string; + private _refCounter: number = 0; + constructor(data: IDecorationData | IDecorationData[]) { this.data = data; this.itemColorClassName = DecorationRule._classNames.nextId(); @@ -45,6 +47,14 @@ class DecorationRule { this.bubbleBadgeClassName = DecorationRule._classNames.nextId(); } + acquire(): void { + this._refCounter += 1; + } + + release(): boolean { + return --this._refCounter === 0; + } + appendCSSRules(element: HTMLStyleElement, theme: ITheme): void { if (!Array.isArray(this.data)) { this._appendForOne(this.data, element, theme); @@ -75,9 +85,10 @@ class DecorationRule { } // bubble badge + // TODO @misolori update bubble badge to use class name instead of unicode createCSSRule( `.${this.bubbleBadgeClassName}::after`, - `content: "\uf052"; color: ${getColor(theme, color)}; font-family: octicons; font-size: 14px; padding-right: 14px; opacity: 0.4;`, + `content: "\uea71"; color: ${getColor(theme, color)}; font-family: codicon; font-size: 14px; padding-right: 14px; opacity: 0.4;`, element ); } @@ -87,33 +98,23 @@ class DecorationRule { removeCSSRulesContainingSelector(this.itemBadgeClassName, element); removeCSSRulesContainingSelector(this.bubbleBadgeClassName, element); } - - isUnused(): boolean { - return !document.querySelector(`.${this.itemColorClassName}`) - && !document.querySelector(`.${this.itemBadgeClassName}`) - && !document.querySelector(`.${this.bubbleBadgeClassName}`); - } } -class DecorationStyles extends Disposable { +class DecorationStyles { private readonly _styleElement = createStyleSheet(); private readonly _decorationRules = new Map(); + private readonly _dispoables = new DisposableStore(); constructor( private _themeService: IThemeService, ) { - super(); - this._register(this._themeService.onThemeChange(this._onThemeChange, this)); + this._themeService.onThemeChange(this._onThemeChange, this, this._dispoables); } dispose(): void { - super.dispose(); - - const parent = this._styleElement.parentElement; - if (parent) { - parent.removeChild(this._styleElement); - } + this._dispoables.dispose(); + this._styleElement.remove(); } asDecoration(data: IDecorationData[], onlyChildren: boolean): IDecoration { @@ -131,6 +132,8 @@ class DecorationStyles extends Disposable { rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); } + rule.acquire(); + let labelClassName = rule.itemColorClassName; let badgeClassName = rule.itemBadgeClassName; let tooltip = data.filter(d => !isFalsyOrWhitespace(d.tooltip)).map(d => d.tooltip).join(' • '); @@ -144,7 +147,14 @@ class DecorationStyles extends Disposable { return { labelClassName, badgeClassName, - tooltip + tooltip, + dispose: () => { + if (rule && rule.release()) { + this._decorationRules.delete(key); + rule.removeCSSRules(this._styleElement); + rule = undefined; + } + } }; } @@ -154,34 +164,6 @@ class DecorationStyles extends Disposable { rule.appendCSSRules(this._styleElement, this._themeService.getTheme()); }); } - - cleanUp(iter: Iterator): void { - // remove every rule for which no more - // decoration (data) is kept. this isn't cheap - let usedDecorations = new Set(); - for (let e = iter.next(); !e.done; e = iter.next()) { - e.value.data.forEach((value, key) => { - if (value && !(value instanceof DecorationDataRequest)) { - usedDecorations.add(DecorationRule.keyOf(value)); - } - }); - } - this._decorationRules.forEach((value, index) => { - const { data } = value; - if (value.isUnused()) { - let remove: boolean = false; - if (Array.isArray(data)) { - remove = data.some(data => !usedDecorations.has(DecorationRule.keyOf(data))); - } else if (!usedDecorations.has(DecorationRule.keyOf(data))) { - remove = true; - } - if (remove) { - value.removeCSSRules(this._styleElement); - this._decorationRules.delete(index); - } - } - }); - } } class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { @@ -223,11 +205,11 @@ class DecorationProviderWrapper { private readonly _dispoable: IDisposable; constructor( - private readonly _provider: IDecorationsProvider, + readonly provider: IDecorationsProvider, private readonly _uriEmitter: Emitter, private readonly _flushEmitter: Emitter ) { - this._dispoable = this._provider.onDidChange(uris => { + this._dispoable = this.provider.onDidChange(uris => { if (!uris) { // flush event -> drop all data, can affect everything this.data.clear(); @@ -291,7 +273,7 @@ class DecorationProviderWrapper { } const source = new CancellationTokenSource(); - const dataOrThenable = this._provider.provideDecorations(uri, source.token); + const dataOrThenable = this.provider.provideDecorations(uri, source.token); if (!isThenable | undefined>(dataOrThenable)) { // sync -> we have a result now return this._keepItem(uri, dataOrThenable); @@ -324,7 +306,7 @@ class DecorationProviderWrapper { } } -export class FileDecorationsService implements IDecorationsService { +export class DecorationsService implements IDecorationsService { _serviceBrand: undefined; @@ -332,7 +314,6 @@ export class FileDecorationsService implements IDecorationsService { private readonly _onDidChangeDecorationsDelayed = new Emitter(); private readonly _onDidChangeDecorations = new Emitter(); private readonly _decorationStyles: DecorationStyles; - private readonly _disposables: IDisposable[]; readonly onDidChangeDecorations: Event = Event.any( this._onDidChangeDecorations.event, @@ -344,29 +325,16 @@ export class FileDecorationsService implements IDecorationsService { ); constructor( - @IThemeService themeService: IThemeService + @IThemeService themeService: IThemeService, + @ILogService private readonly _logService: ILogService, ) { this._decorationStyles = new DecorationStyles(themeService); - - // every so many events we check if there are - // css styles that we don't need anymore - let count = 0; - let reg = this.onDidChangeDecorations(() => { - if (++count % 17 === 0) { - this._decorationStyles.cleanUp(this._data.iterator()); - } - }); - - this._disposables = [ - reg, - this._decorationStyles - ]; } dispose(): void { - dispose(this._disposables); - dispose(this._onDidChangeDecorations); - dispose(this._onDidChangeDecorationsDelayed); + this._decorationStyles.dispose(); + this._onDidChangeDecorations.dispose(); + this._onDidChangeDecorationsDelayed.dispose(); } registerDecorationsProvider(provider: IDecorationsProvider): IDisposable { @@ -396,10 +364,12 @@ export class FileDecorationsService implements IDecorationsService { let data: IDecorationData[] = []; let containsChildren: boolean = false; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { + const { label } = next.value.provider; next.value.getOrRetrieve(uri, includeChildren, (deco, isChild) => { if (!isChild || deco.bubble) { data.push(deco); containsChildren = isChild || containsChildren; + this._logService.trace('DecorationsService#getDecoration#getOrRetrieve', label, deco, isChild, uri); } }); } @@ -419,4 +389,4 @@ function getColor(theme: ITheme, color: string | undefined) { return 'inherit'; } -registerSingleton(IDecorationsService, FileDecorationsService); +registerSingleton(IDecorationsService, DecorationsService, true); diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index bd6a66f3fbb..2f1298ea85b 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -4,22 +4,23 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; +import { DecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; import { IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { ConsoleLogService } from 'vs/platform/log/common/log'; suite('DecorationsService', function () { - let service: FileDecorationsService; + let service: DecorationsService; setup(function () { if (service) { service.dispose(); } - service = new FileDecorationsService(new TestThemeService()); + service = new DecorationsService(new TestThemeService(), new ConsoleLogService()); }); test('Async provider, async/evented result', function () { @@ -29,7 +30,7 @@ suite('DecorationsService', function () { service.registerDecorationsProvider(new class implements IDecorationsProvider { readonly label: string = 'Test'; - readonly onDidChange: Event = Event.None; + readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; return new Promise(resolve => { @@ -62,7 +63,7 @@ suite('DecorationsService', function () { service.registerDecorationsProvider(new class implements IDecorationsProvider { readonly label: string = 'Test'; - readonly onDidChange: Event = Event.None; + readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; return { color: 'someBlue', tooltip: 'Z' }; @@ -80,7 +81,7 @@ suite('DecorationsService', function () { let reg = service.registerDecorationsProvider(new class implements IDecorationsProvider { readonly label: string = 'Test'; - readonly onDidChange: Event = Event.None; + readonly onDidChange: Event = Event.None; provideDecorations(uri: URI) { callCounter += 1; return { color: 'someBlue', tooltip: 'J' }; @@ -155,7 +156,7 @@ suite('DecorationsService', function () { let provider = new class implements IDecorationsProvider { _onDidChange = new Emitter(); - onDidChange: Event = this._onDidChange.event; + onDidChange: Event = this._onDidChange.event; label: string = 'foo'; diff --git a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts index fc73f88de8f..f8d717d76a5 100644 --- a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts @@ -14,15 +14,14 @@ import { Schemas } from 'vs/base/common/network'; import * as resources from 'vs/base/common/resources'; import { IInstantiationService, } from 'vs/platform/instantiation/common/instantiation'; import { SimpleFileDialog } from 'vs/workbench/services/dialogs/browser/simpleFileDialog'; -import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; +import { WORKSPACE_EXTENSION, isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; -import { isWeb } from 'vs/base/common/platform'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -export class AbstractFileDialogService { +export abstract class AbstractFileDialogService { _serviceBrand: undefined; @@ -79,15 +78,7 @@ export class AbstractFileDialogService { return this.defaultFilePath(schemeFilter); } - protected addFileSchemaIfNeeded(schema: string): string[] { - // Include File schema unless the schema is web - // Don't allow untitled schema through. - if (isWeb) { - return schema === Schemas.untitled ? [Schemas.file] : [schema]; - } else { - return schema === Schemas.untitled ? [Schemas.file] : (schema !== Schemas.file ? [schema, Schemas.file] : [schema]); - } - } + protected abstract addFileSchemaIfNeeded(schema: string): string[]; protected async pickFileFolderAndOpenSimplified(schema: string, options: IPickAndOpenOptions, preferNewWindow: boolean): Promise { const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder'); @@ -100,9 +91,9 @@ export class AbstractFileDialogService { const toOpen: IWindowOpenable = stat.isDirectory ? { folderUri: uri } : { fileUri: uri }; if (stat.isDirectory || options.forceNewWindow || preferNewWindow) { - return this.hostService.openInWindow([toOpen], { forceNewWindow: options.forceNewWindow }); + return this.hostService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); } else { - return this.openerService.open(uri); + return this.openerService.open(uri, { fromUserGesture: true }); } } } @@ -114,9 +105,9 @@ export class AbstractFileDialogService { const uri = await this.pickResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); if (uri) { if (options.forceNewWindow || preferNewWindow) { - return this.hostService.openInWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); + return this.hostService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); } else { - return this.openerService.open(uri); + return this.openerService.open(uri, { fromUserGesture: true }); } } } @@ -127,7 +118,7 @@ export class AbstractFileDialogService { const uri = await this.pickResource({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); if (uri) { - return this.hostService.openInWindow([{ folderUri: uri }], { forceNewWindow: options.forceNewWindow }); + return this.hostService.openWindow([{ folderUri: uri }], { forceNewWindow: options.forceNewWindow }); } } @@ -138,7 +129,7 @@ export class AbstractFileDialogService { const uri = await this.pickResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, filters, availableFileSystems }); if (uri) { - return this.hostService.openInWindow([{ workspaceUri: uri }], { forceNewWindow: options.forceNewWindow }); + return this.hostService.openWindow([{ workspaceUri: uri }], { forceNewWindow: options.forceNewWindow }); } } @@ -185,11 +176,7 @@ export class AbstractFileDialogService { return !this.environmentService.configuration.remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME; } - protected getFileSystemSchema(options: { availableFileSystems?: string[], defaultUri?: URI }): string { + protected getFileSystemSchema(options: { availableFileSystems?: readonly string[], defaultUri?: URI }): string { return options.availableFileSystems && options.availableFileSystems[0] || this.getSchemeFilterForWindow(); } } - -function isUntitledWorkspace(path: URI, environmentService: IWorkbenchEnvironmentService): boolean { - return resources.isEqualOrParent(path, environmentService.untitledWorkspacesHome); -} diff --git a/src/vs/workbench/services/dialogs/browser/dialogService.ts b/src/vs/workbench/services/dialogs/browser/dialogService.ts index 495d0ea725f..f67f9aa064c 100644 --- a/src/vs/workbench/services/dialogs/browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/dialogService.ts @@ -129,7 +129,7 @@ export class DialogService implements IDialogService { navigator.userAgent ); - const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail }); + const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail, cancelId: 1 }); if (choice === 0) { this.clipboardService.writeText(detail); diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts index 845e31adc9a..a82239f1701 100644 --- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts @@ -7,6 +7,7 @@ import { IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialo import { URI } from 'vs/base/common/uri'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { AbstractFileDialogService } from 'vs/workbench/services/dialogs/browser/abstractFileDialogService'; +import { Schemas } from 'vs/base/common/network'; export class FileDialogService extends AbstractFileDialogService implements IFileDialogService { @@ -64,6 +65,10 @@ export class FileDialogService extends AbstractFileDialogService implements IFil const schema = this.getFileSystemSchema(options); return this.showOpenDialogSimplified(schema, options); } + + protected addFileSchemaIfNeeded(schema: string): string[] { + return schema === Schemas.untitled ? [Schemas.file] : [schema]; + } } registerSingleton(IFileDialogService, FileDialogService, true); diff --git a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts index ca0d3d75602..4d1a4cface3 100644 --- a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts @@ -35,6 +35,7 @@ import { ICommandHandler } from 'vs/platform/commands/common/commands'; import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { toResource } from 'vs/workbench/common/editor'; +import { normalizeDriveLetter } from 'vs/base/common/labels'; export namespace OpenLocalFileCommand { export const ID = 'workbench.action.files.openLocalFile'; @@ -210,7 +211,7 @@ export class SimpleFileDialog { return resources.toLocalResource(URI.from({ scheme: this.scheme, path }), this.scheme === Schemas.file ? undefined : this.remoteAuthority); } - private getScheme(available: string[] | undefined, defaultUri: URI | undefined): string { + private getScheme(available: readonly string[] | undefined, defaultUri: URI | undefined): string { if (available) { if (defaultUri && (available.indexOf(defaultUri.scheme) >= 0)) { return defaultUri.scheme; @@ -255,16 +256,6 @@ export class SimpleFileDialog { homedir = resources.dirname(this.options.defaultUri); this.trailing = resources.basename(this.options.defaultUri); } - // append extension - if (isSave && !ext && this.options.filters) { - for (let i = 0; i < this.options.filters.length; i++) { - if (this.options.filters[i].extensions[0] !== '*') { - ext = '.' + this.options.filters[i].extensions[0]; - this.trailing = this.trailing ? this.trailing + ext : ext; - break; - } - } - } } return new Promise(async (resolve) => { @@ -321,7 +312,7 @@ export class SimpleFileDialog { isAcceptHandled = true; isResolving++; if (this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) { - this.options.availableFileSystems.shift(); + this.options.availableFileSystems = this.options.availableFileSystems.slice(1); } this.filePickBox.hide(); if (isSave) { @@ -382,28 +373,7 @@ export class SimpleFileDialog { }); 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.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 filePickBoxUri = this.filePickBoxValue(); - let updated: UpdateResult = UpdateResult.NotUpdated; - 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 { - // Since any text can be entered in the input box, there is potential for error causing input. If this happens, do nothing. - } + return this.handleValueChange(value); }); this.filePickBox.onDidHide(() => { this.hidden = true; @@ -424,6 +394,31 @@ export class SimpleFileDialog { }); } + private async handleValueChange(value: string) { + try { + // onDidChangeValue can also be triggered by the auto complete, so if it looks like the auto complete, don't do anything + 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 filePickBoxUri = this.filePickBoxValue(); + let updated: UpdateResult = UpdateResult.NotUpdated; + 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 { + // Since any text can be entered in the input box, there is potential for error causing input. If this happens, do nothing. + } + } + private isBadSubpath(value: string) { return this.badPath && (value.length > this.badPath.length) && equalsIgnoreCase(value.substring(0, this.badPath.length), this.badPath); } @@ -486,7 +481,7 @@ export class SimpleFileDialog { 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); + this.insertText(newPath, this.basenameWithTrailingSlash(item.uri)); } else if ((item.label === '..') && startsWithIgnoreCase(this.filePickBox.value, newPath)) { this.filePickBox.valueSelection = [newPath.length, this.filePickBox.value.length]; this.insertText(newPath, ''); @@ -523,6 +518,16 @@ export class SimpleFileDialog { return undefined; } + private root(value: URI) { + let lastDir = value; + let dir = resources.dirname(value); + while (!resources.isEqual(lastDir, dir)) { + lastDir = dir; + dir = resources.dirname(dir); + } + return dir; + } + private async tryUpdateItems(value: string, valueUri: URI): Promise { if ((value.length > 0) && ((value[value.length - 1] === '~') || (value[0] === '~'))) { let newDir = this.userHome; @@ -531,6 +536,11 @@ export class SimpleFileDialog { } await this.updateItems(newDir, true); return UpdateResult.Updated; + } else if (value === '\\') { + valueUri = this.root(this.currentFolder); + value = this.pathFromUri(valueUri); + await this.updateItems(valueUri, true); + return UpdateResult.Updated; } 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 { @@ -602,7 +612,7 @@ export class SimpleFileDialog { this.autoCompletePathSegment = ''; return false; } - const itemBasename = this.trimTrailingSlash(quickPickItem.label); + const itemBasename = quickPickItem.label; // 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. @@ -611,7 +621,7 @@ export class SimpleFileDialog { this.activeItem = quickPickItem; if (force) { // clear any selected text - this.insertText(this.userEnteredPathSegment, ''); + document.execCommand('insertText', false, ''); } return false; } else if (!force && (itemBasename.length >= startingBasename.length) && equalsIgnoreCase(itemBasename.substr(0, startingBasename.length), startingBasename)) { @@ -621,7 +631,7 @@ export class SimpleFileDialog { this.autoCompletePathSegment = ''; this.filePickBox.activeItems = [quickPickItem]; return true; - } else if (force && (!equalsIgnoreCase(quickPickItem.label, (this.userEnteredPathSegment + this.autoCompletePathSegment)))) { + } else if (force && (!equalsIgnoreCase(this.basenameWithTrailingSlash(quickPickItem.uri), (this.userEnteredPathSegment + this.autoCompletePathSegment)))) { this.userEnteredPathSegment = ''; this.autoCompletePathSegment = this.trimTrailingSlash(itemBasename); this.activeItem = quickPickItem; @@ -640,8 +650,13 @@ export class SimpleFileDialog { private insertText(wholeValue: string, insertText: string) { if (this.filePickBox.inputHasFocus()) { document.execCommand('insertText', false, insertText); + if (this.filePickBox.value !== wholeValue) { + this.filePickBox.value = wholeValue; + this.handleValueChange(wholeValue); + } } else { this.filePickBox.value = wholeValue; + this.handleValueChange(wholeValue); } } @@ -807,7 +822,7 @@ export class SimpleFileDialog { } private pathFromUri(uri: URI, endWithSeparator: boolean = false): string { - let result: string = uri.fsPath.replace(/\n/g, ''); + let result: string = normalizeDriveLetter(uri.fsPath).replace(/\n/g, ''); if (this.separator === '/') { result = result.replace(/\\/g, this.separator); } else { @@ -848,7 +863,7 @@ export class SimpleFileDialog { } private createBackItem(currFolder: URI): FileQuickPickItem | null { - const parentFolder = resources.dirname(currFolder)!; + const parentFolder = resources.dirname(currFolder); if (!resources.isEqual(currFolder, parentFolder, true)) { return { label: '..', uri: resources.addTrailingPathSeparator(parentFolder, this.separator), isFolder: true }; } @@ -913,7 +928,7 @@ export class SimpleFileDialog { try { const stat = await this.fileService.resolve(fullPath); if (stat.isDirectory) { - filename = this.basenameWithTrailingSlash(fullPath); + filename = resources.basename(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)) { diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 3c564000389..43caf27af2e 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -43,10 +43,11 @@ export class DialogService implements IDialogService { _serviceBrand: undefined; - private impl: IDialogService; + private nativeImpl: IDialogService; + private customImpl: IDialogService; constructor( - @IConfigurationService configurationService: IConfigurationService, + @IConfigurationService private configurationService: IConfigurationService, @ILogService logService: ILogService, @ILayoutService layoutService: ILayoutService, @IThemeService themeService: IThemeService, @@ -56,27 +57,32 @@ export class DialogService implements IDialogService { @IClipboardService clipboardService: IClipboardService, @IElectronService electronService: IElectronService ) { + this.customImpl = new HTMLDialogService(logService, layoutService, themeService, keybindingService, productService, clipboardService); + this.nativeImpl = new NativeDialogService(logService, sharedProcessService, electronService, clipboardService); + } - // Use HTML based dialogs - if (configurationService.getValue('workbench.dialogs.customEnabled') === true) { - this.impl = new HTMLDialogService(logService, layoutService, themeService, keybindingService, productService, clipboardService); - } - // Electron dialog service - else { - this.impl = new NativeDialogService(logService, sharedProcessService, electronService, clipboardService); - } + private get useCustomDialog(): boolean { + return this.configurationService.getValue('workbench.dialogs.customEnabled') === true; } confirm(confirmation: IConfirmation): Promise { - return this.impl.confirm(confirmation); + if (this.useCustomDialog) { + return this.customImpl.confirm(confirmation); + } + + return this.nativeImpl.confirm(confirmation); } show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions | undefined): Promise { - return this.impl.show(severity, message, buttons, options); + if (this.useCustomDialog) { + return this.customImpl.show(severity, message, buttons, options); + } + + return this.nativeImpl.show(severity, message, buttons, options); } about(): Promise { - return this.impl.about(); + return this.nativeImpl.about(); } } diff --git a/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts index bd521b7437c..a4873580a8d 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { SaveDialogOptions, OpenDialogOptions } from 'electron'; -import { INativeOpenDialogOptions } from 'vs/platform/windows/common/windows'; +import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -46,8 +46,8 @@ export class FileDialogService extends AbstractFileDialogService implements IFil private shouldUseSimplified(schema: string): { useSimplified: boolean, isSetting: boolean } { const setting = (this.configurationService.getValue('files.simpleDialog.enable') === true); - - return { useSimplified: (schema !== Schemas.file) || setting, isSetting: (schema === Schemas.file) && setting }; + const newWindowSetting = (this.configurationService.getValue('window.openFilesInNewWindow') === 'on'); + return { useSimplified: (schema !== Schemas.file) || setting, isSetting: newWindowSetting }; } async pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { @@ -149,7 +149,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil const defaultUri = options.defaultUri; - const newOptions: OpenDialogOptions = { + const newOptions: OpenDialogOptions & { properties: string[] } = { title: options.title, defaultPath: defaultUri && defaultUri.fsPath, buttonLabel: options.openLabel, @@ -157,23 +157,29 @@ export class FileDialogService extends AbstractFileDialogService implements IFil properties: [] }; - newOptions.properties!.push('createDirectory'); + newOptions.properties.push('createDirectory'); if (options.canSelectFiles) { - newOptions.properties!.push('openFile'); + newOptions.properties.push('openFile'); } if (options.canSelectFolders) { - newOptions.properties!.push('openDirectory'); + newOptions.properties.push('openDirectory'); } if (options.canSelectMany) { - newOptions.properties!.push('multiSelections'); + newOptions.properties.push('multiSelections'); } const result = await this.electronService.showOpenDialog(newOptions); return result && Array.isArray(result.filePaths) && result.filePaths.length > 0 ? result.filePaths.map(URI.file) : undefined; } + + protected addFileSchemaIfNeeded(schema: string): string[] { + // Include File schema unless the schema is web + // Don't allow untitled schema through. + return schema === Schemas.untitled ? [Schemas.file] : (schema !== Schemas.file ? [schema, Schemas.file] : [schema]); + } } registerSingleton(IFileDialogService, FileDialogService, true); diff --git a/src/vs/workbench/services/editor/browser/codeEditorService.ts b/src/vs/workbench/services/editor/browser/codeEditorService.ts index b21827ee93c..27cf3bbdf59 100644 --- a/src/vs/workbench/services/editor/browser/codeEditorService.ts +++ b/src/vs/workbench/services/editor/browser/codeEditorService.ts @@ -22,7 +22,7 @@ export class CodeEditorService extends CodeEditorServiceImpl { super(themeService); } - getActiveCodeEditor(): ICodeEditor | undefined { + getActiveCodeEditor(): ICodeEditor | null { const activeTextEditorWidget = this.editorService.activeTextEditorWidget; if (isCodeEditor(activeTextEditorWidget)) { return activeTextEditorWidget; @@ -32,10 +32,10 @@ export class CodeEditorService extends CodeEditorServiceImpl { return activeTextEditorWidget.getModifiedEditor(); } - return undefined; + return null; } - openCodeEditor(input: IResourceInput, source: ICodeEditor | undefined, sideBySide?: boolean): Promise { + openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise { // Special case: If the active editor is a diff editor and the request to open originates and // targets the modified side of it, we just apply the request there to prevent opening the modified @@ -62,7 +62,7 @@ export class CodeEditorService extends CodeEditorServiceImpl { return this.doOpenCodeEditor(input, source, sideBySide); } - private async doOpenCodeEditor(input: IResourceInput, _source: ICodeEditor | undefined, sideBySide?: boolean): Promise { + 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(); @@ -71,7 +71,7 @@ export class CodeEditorService extends CodeEditorServiceImpl { } } - return undefined; + return null; } } diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index a056de4bf9d..9a1f593fa48 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -15,7 +15,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { Schemas } from 'vs/base/common/network'; import { Event, Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; -import { basename } from 'vs/base/common/resources'; +import { basename, isEqual } from 'vs/base/common/resources'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { localize } from 'vs/nls'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, IEditorReplacement, GroupChangeKind, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -152,17 +152,16 @@ export class EditorService extends Disposable implements EditorServiceImpl { for (const handler of this.openEditorHandlers) { const result = handler(event.editor, event.options, group); - if (result && result.override) { - event.prevent((() => result.override!.then(editor => withNullAsUndefined(editor)))); + const override = result?.override; + if (override) { + event.prevent((() => override.then(editor => withNullAsUndefined(editor)))); break; } } } get activeControl(): IVisibleEditor | undefined { - const activeGroup = this.editorGroupService.activeGroup; - - return activeGroup ? activeGroup.activeControl : undefined; + return this.editorGroupService.activeGroup?.activeControl; } get activeTextEditorWidget(): ICodeEditor | IDiffEditor | undefined { @@ -306,7 +305,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { const groupsByLastActive = this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE); // Respect option to reveal an editor if it is already visible in any group - if (options && options.revealIfVisible) { + if (options?.revealIfVisible) { for (const group of groupsByLastActive) { if (group.isActive(input)) { targetGroup = group; @@ -318,7 +317,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { // Respect option to reveal an editor if it is open (not necessarily visible) // Still prefer to reveal an editor in a group where the editor is active though. if (!targetGroup) { - if ((options && options.revealIfOpened) || this.configurationService.getValue('workbench.editor.revealIfOpen')) { + if (options?.revealIfOpened || this.configurationService.getValue('workbench.editor.revealIfOpen')) { let groupWithInputActive: IEditorGroup | undefined = undefined; let groupWithInputOpened: IEditorGroup | undefined = undefined; @@ -464,7 +463,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { } const resourceInput = editor as IResourceInput | IUntitledResourceInput; - if (resourceInput.resource && resource.toString() === resourceInput.resource.toString()) { + if (resourceInput.resource && isEqual(resource, resourceInput.resource)) { return editorInGroup; } } 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 54096dfc116..98e93a57adb 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -43,7 +43,7 @@ export class TestEditorInput extends EditorInput implements IFileEditorInput { resolve(): Promise { return Promise.resolve(null); } matches(other: TestEditorInput): boolean { return other && this.resource.toString() === other.resource.toString() && other instanceof TestEditorInput; } setEncoding(encoding: string) { } - getEncoding(): string { return null!; } + getEncoding() { return undefined; } setPreferredEncoding(encoding: string) { } setMode(mode: string) { } setPreferredMode(mode: string) { } 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 f3c781424b3..c55ecf8cc50 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -54,10 +54,10 @@ export class TestEditorInput extends EditorInput implements IFileEditorInput { constructor(private resource: URI) { super(); } getTypeId() { return 'testEditorInputForEditorService'; } - resolve(): Promise { return !this.fails ? Promise.resolve(null) : Promise.reject(new Error('fails')); } + resolve(): Promise { return !this.fails ? Promise.resolve(null) : Promise.reject(new Error('fails')); } matches(other: TestEditorInput): boolean { return other && other.resource && this.resource.toString() === other.resource.toString() && other instanceof TestEditorInput; } setEncoding(encoding: string) { } - getEncoding(): string { return null!; } + getEncoding() { return undefined; } setPreferredEncoding(encoding: string) { } setMode(mode: string) { } setPreferredMode(mode: string) { } diff --git a/src/vs/workbench/services/electron/electron-browser/electronEnvironmentService.ts b/src/vs/workbench/services/electron/electron-browser/electronEnvironmentService.ts new file mode 100644 index 00000000000..ead4c15e1ac --- /dev/null +++ b/src/vs/workbench/services/electron/electron-browser/electronEnvironmentService.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IElectronEnvironmentService = createDecorator('electronEnvironmentService'); + +export interface IElectronEnvironmentService { + + _serviceBrand: undefined; + + readonly windowId: number; + + readonly sharedIPCHandle: string; +} + +export class ElectronEnvironmentService implements IElectronEnvironmentService { + + _serviceBrand: undefined; + + constructor( + public readonly windowId: number, + public readonly sharedIPCHandle: string + ) { } +} diff --git a/src/vs/platform/electron/electron-browser/electronService.ts b/src/vs/workbench/services/electron/electron-browser/electronService.ts similarity index 54% rename from src/vs/platform/electron/electron-browser/electronService.ts rename to src/vs/workbench/services/electron/electron-browser/electronService.ts index b1c6db59d4f..eebb9bace06 100644 --- a/src/vs/platform/electron/electron-browser/electronService.ts +++ b/src/vs/workbench/services/electron/electron-browser/electronService.ts @@ -5,8 +5,9 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; +import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; export class ElectronService { @@ -14,8 +15,10 @@ export class ElectronService { constructor( @IMainProcessService mainProcessService: IMainProcessService, - @IWindowService windowService: IWindowService + @IElectronEnvironmentService electronEnvironmentService: IElectronEnvironmentService ) { - return createSimpleChannelProxy(mainProcessService.getChannel('electron'), windowService.windowId); + return createChannelSender(mainProcessService.getChannel('electron'), { context: electronEnvironmentService.windowId }); } } + +registerSingleton(IElectronService, ElectronService, true); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index b31602466f5..075d54f4d54 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -9,198 +9,313 @@ import { IProcessEnvironment } from 'vs/base/common/platform'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; -import { BACKUPS, IDebugParams, IExtensionHostDebugParams } from 'vs/platform/environment/common/environment'; +import { BACKUPS, IExtensionHostDebugParams } from 'vs/platform/environment/common/environment'; import { LogLevel } from 'vs/platform/log/common/log'; import { IPath, IPathsToWaitFor, IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api'; import product from 'vs/platform/product/common/product'; +import { serializableToMap } from 'vs/base/common/map'; +import { memoize } from 'vs/base/common/decorators'; export class BrowserWindowConfiguration implements IWindowConfiguration { - _: any[]; + constructor(private readonly options: IBrowserWorkbenchEnvironmentConstructionOptions, private readonly environment: IWorkbenchEnvironmentService) { } - machineId: string; - windowId: number; - logLevel: LogLevel; + //#region PROPERLY CONFIGURED IN DESKTOP + WEB - mainPid: number; + @memoize + get sessionId(): string { return generateUuid(); } - appRoot: string; - execPath: string; - isInitialStartup?: boolean; + @memoize + get remoteAuthority(): string | undefined { return this.options.remoteAuthority; } - userEnv: IProcessEnvironment; + @memoize + get connectionToken(): string | undefined { return this.options.connectionToken || this.getCookieValue('vscode-tkn'); } + + @memoize + get backupWorkspaceResource(): URI { return joinPath(this.environment.backupHome, this.options.workspaceId); } + + // Currently unsupported in web + get filesToOpenOrCreate(): IPath[] | undefined { return undefined; } + get filesToDiff(): IPath[] | undefined { return undefined; } + + //#endregion + + + //#region TODO MOVE TO NODE LAYER + + _!: any[]; + + windowId!: number; + mainPid!: number; + + logLevel!: LogLevel; + + appRoot!: string; + execPath!: string; + backupPath?: string; nodeCachedDataDir?: string; - backupPath?: string; - backupWorkspaceResource?: URI; + userEnv!: IProcessEnvironment; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; - remoteAuthority?: string; - connectionToken?: string; - zoomLevel?: number; fullscreen?: boolean; maximized?: boolean; highContrast?: boolean; - frameless?: boolean; accessibilitySupport?: boolean; partsSplashPath?: string; - perfStartTime?: number; - perfAppReady?: number; - perfWindowLoadTime?: number; - perfEntries: ExportData; + isInitialStartup?: boolean; + perfEntries!: ExportData; - filesToOpenOrCreate?: IPath[]; - filesToDiff?: IPath[]; filesToWait?: IPathsToWaitFor; - termProgram?: string; + + //#endregion + + private getCookieValue(name: string): string | undefined { + const m = document.cookie.match('(^|[^;]+)\\s*' + name + '\\s*=\\s*([^;]+)'); // See https://stackoverflow.com/a/25490531 + + return m ? m.pop() : undefined; + } } -interface IBrowserWorkbenchEnvironemntConstructionOptions extends IWorkbenchConstructionOptions { +interface IBrowserWorkbenchEnvironmentConstructionOptions extends IWorkbenchConstructionOptions { workspaceId: string; logsPath: URI; } +interface IExtensionHostDebugEnvironment { + params: IExtensionHostDebugParams; + isExtensionDevelopment: boolean; + extensionDevelopmentLocationURI: URI[]; + extensionTestsLocationURI?: URI; +} + export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironmentService { _serviceBrand: undefined; - readonly configuration: IWindowConfiguration = new BrowserWindowConfiguration(); + //#region PROPERLY CONFIGURED IN DESKTOP + WEB - constructor(readonly options: IBrowserWorkbenchEnvironemntConstructionOptions) { - this.args = { _: [] }; - this.logsPath = options.logsPath.path; - this.logFile = joinPath(options.logsPath, 'window.log'); - this.appRoot = '/web/'; - this.appNameLong = 'Visual Studio Code - Web'; + @memoize + get isBuilt(): boolean { return !!product.commit; } - this.configuration.remoteAuthority = options.remoteAuthority; - this.configuration.machineId = generateUuid(); - this.userRoamingDataHome = URI.file('/User').with({ scheme: Schemas.userData }); - this.settingsResource = joinPath(this.userRoamingDataHome, 'settings.json'); - this.settingsSyncPreviewResource = 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, options.workspaceId); - this.configuration.connectionToken = options.connectionToken || getCookieValue('vscode-tkn'); + @memoize + get logsPath(): string { return this.options.logsPath.path; } - this.debugExtensionHost = { - port: null, - break: false - }; + @memoize + get logFile(): URI { return joinPath(this.options.logsPath, 'window.log'); } - this.untitledWorkspacesHome = URI.from({ scheme: Schemas.untitled, path: 'Workspaces' }); + @memoize + get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.userData }); } - 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(pair[0], decodeURIComponent(pair[1])); - } - } + @memoize + get settingsResource(): URI { return joinPath(this.userRoamingDataHome, 'settings.json'); } - const edp = map.get('edp'); - if (edp) { - this.extensionDevelopmentLocationURI = [URI.parse(edp)]; - this.isExtensionDevelopment = true; - } + @memoize + get settingsSyncPreviewResource(): URI { return joinPath(this.userRoamingDataHome, '.settings.json'); } - const di = map.get('di'); - if (di) { - this.debugExtensionHost.debugId = di; - } + @memoize + get userDataSyncLogResource(): URI { return joinPath(this.options.logsPath, 'userDataSync.log'); } - const ibe = map.get('ibe'); - if (ibe) { - this.debugExtensionHost.port = parseInt(ibe); - this.debugExtensionHost.break = false; - } + @memoize + get keybindingsResource(): URI { return joinPath(this.userRoamingDataHome, 'keybindings.json'); } + + @memoize + get keyboardLayoutResource(): URI { return joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); } + + @memoize + get backupHome(): URI { return joinPath(this.userRoamingDataHome, BACKUPS); } + + @memoize + get untitledWorkspacesHome(): URI { return joinPath(this.userRoamingDataHome, 'Workspaces'); } + + private _extensionHostDebugEnvironment: IExtensionHostDebugEnvironment | undefined = undefined; + get debugExtensionHost(): IExtensionHostDebugParams { + if (!this._extensionHostDebugEnvironment) { + this._extensionHostDebugEnvironment = this.resolveExtensionHostDebugEnvironment(); } + + return this._extensionHostDebugEnvironment.params; } - 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; - settingsSyncPreviewResource: 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; - mainIPCHandle: string; - sharedIPCHandle: string; - nodeCachedDataDir?: string; - installSourcePath: string; - disableUpdates: boolean; - disableCrashReporter: boolean; - driverHandle?: string; - driverVerbose: boolean; - galleryMachineIdResource?: URI; - readonly logFile: URI; + get isExtensionDevelopment(): boolean { + if (!this._extensionHostDebugEnvironment) { + this._extensionHostDebugEnvironment = this.resolveExtensionHostDebugEnvironment(); + } + return this._extensionHostDebugEnvironment.isExtensionDevelopment; + } + + get extensionDevelopmentLocationURI(): URI[] { + if (!this._extensionHostDebugEnvironment) { + this._extensionHostDebugEnvironment = this.resolveExtensionHostDebugEnvironment(); + } + + return this._extensionHostDebugEnvironment.extensionDevelopmentLocationURI; + } + + get extensionTestsLocationURI(): URI | undefined { + if (!this._extensionHostDebugEnvironment) { + this._extensionHostDebugEnvironment = this.resolveExtensionHostDebugEnvironment(); + } + + return this._extensionHostDebugEnvironment.extensionTestsLocationURI; + } + + @memoize get webviewExternalEndpoint(): string { // TODO: get fallback from product.json - return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}') - .replace('{{commit}}', product.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44'); + return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}').replace('{{commit}}', product.commit || 'b53811e67e65c6a564a80e1c412ca2b13de02907'); } + @memoize get webviewResourceRoot(): string { - return `${this.webviewExternalEndpoint}/vscode-resource{{resource}}`; + return `${this.webviewExternalEndpoint}/vscode-resource/{{resource}}`; } + @memoize get webviewCspSource(): string { - return this.webviewExternalEndpoint - .replace('{{uuid}}', '*'); + return this.webviewExternalEndpoint.replace('{{uuid}}', '*'); + } + + // Currently not configurable in web + get disableExtensions() { return false; } + get extensionsPath(): string | undefined { return undefined; } + get verbose(): boolean { return false; } + get disableUpdates(): boolean { return false; } + get logExtensionHostCommunication(): boolean { return false; } + + //#endregion + + + //#region TODO MOVE TO NODE LAYER + + private _configuration: IWindowConfiguration | undefined = undefined; + get configuration(): IWindowConfiguration { + if (!this._configuration) { + this._configuration = new BrowserWindowConfiguration(this.options, this); + } + + return this._configuration; + } + + args = { _: [] }; + + wait!: boolean; + status!: boolean; + log?: string; + + mainIPCHandle!: string; + sharedIPCHandle!: string; + + nodeCachedDataDir?: string; + + argvResource!: URI; + + disableCrashReporter!: boolean; + + driverHandle?: string; + driverVerbose!: boolean; + + installSourcePath!: string; + + builtinExtensionsPath!: string; + + globalStorageHome!: string; + workspaceStorageHome!: string; + + backupWorkspacesPath!: string; + + machineSettingsHome!: URI; + machineSettingsResource!: URI; + + userHome!: string; + userDataPath!: string; + appRoot!: string; + appSettingsHome!: URI; + execPath!: string; + cliPath!: string; + + //#endregion + + + //#region TODO ENABLE IN WEB + + galleryMachineIdResource?: URI; + + //#endregion + + constructor(readonly options: IBrowserWorkbenchEnvironmentConstructionOptions) { } + + private resolveExtensionHostDebugEnvironment(): IExtensionHostDebugEnvironment { + const extensionHostDebugEnvironment: IExtensionHostDebugEnvironment = { + params: { + port: null, + break: false + }, + isExtensionDevelopment: false, + extensionDevelopmentLocationURI: [] + }; + + // Fill in selected extra environmental properties + if (this.options.workspaceProvider && Array.isArray(this.options.workspaceProvider.payload)) { + const environment = serializableToMap(this.options.workspaceProvider.payload); + for (const [key, value] of environment) { + switch (key) { + case 'extensionDevelopmentPath': + extensionHostDebugEnvironment.extensionDevelopmentLocationURI = [URI.parse(value)]; + extensionHostDebugEnvironment.isExtensionDevelopment = true; + break; + case 'extensionTestsPath': + extensionHostDebugEnvironment.extensionTestsLocationURI = URI.parse(value); + break; + case 'debugId': + extensionHostDebugEnvironment.params.debugId = value; + break; + case 'inspect-brk-extensions': + extensionHostDebugEnvironment.params.port = parseInt(value); + extensionHostDebugEnvironment.params.break = false; + break; + } + } + } else { + // TODO@Ben remove me once environment is adopted + 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(pair[0], decodeURIComponent(pair[1])); + } + } + + const edp = map.get('extensionDevelopmentPath'); + if (edp) { + extensionHostDebugEnvironment.extensionDevelopmentLocationURI = [URI.parse(edp)]; + extensionHostDebugEnvironment.isExtensionDevelopment = true; + } + + const di = map.get('debugId'); + if (di) { + extensionHostDebugEnvironment.params.debugId = di; + } + + const ibe = map.get('inspect-brk-extensions'); + if (ibe) { + extensionHostDebugEnvironment.params.port = parseInt(ibe); + extensionHostDebugEnvironment.params.break = false; + } + } + } + + return extensionHostDebugEnvironment; } } - -/** - * See https://stackoverflow.com/a/25490531 - */ -function getCookieValue(name: string): string | undefined { - const m = document.cookie.match('(^|[^;]+)\\s*' + name + '\\s*=\\s*([^;]+)'); - return m ? m.pop() : undefined; -} diff --git a/src/vs/workbench/services/environment/common/environmentService.ts b/src/vs/workbench/services/environment/common/environmentService.ts index b19a45caf00..4728f3e5102 100644 --- a/src/vs/workbench/services/environment/common/environmentService.ts +++ b/src/vs/workbench/services/environment/common/environmentService.ts @@ -5,7 +5,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { IEnvironmentService, IDebugParams } from 'vs/platform/environment/common/environment'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api'; import { URI } from 'vs/base/common/uri'; @@ -20,15 +20,8 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService { readonly options?: IWorkbenchConstructionOptions; readonly logFile: URI; - readonly logExtensionHostCommunication: boolean; - - readonly debugSearch: IDebugParams; readonly webviewExternalEndpoint: string; readonly webviewResourceRoot: string; readonly webviewCspSource: string; - - readonly skipGettingStarted: boolean | undefined; - readonly skipReleaseNotes: boolean | undefined; - } diff --git a/src/vs/workbench/services/environment/node/environmentService.ts b/src/vs/workbench/services/environment/electron-browser/environmentService.ts similarity index 60% rename from src/vs/workbench/services/environment/node/environmentService.ts rename to src/vs/workbench/services/environment/electron-browser/environmentService.ts index accc37ed923..903c6457566 100644 --- a/src/vs/workbench/services/environment/node/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-browser/environmentService.ts @@ -3,50 +3,46 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EnvironmentService, parseSearchPort } from 'vs/platform/environment/node/environmentService'; +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'; +import { toBackupWorkspaceResource } from 'vs/workbench/services/backup/electron-browser/backup'; import { join } from 'vs/base/common/path'; -import { IDebugParams } from 'vs/platform/environment/common/environment'; import product from 'vs/platform/product/common/product'; -export class WorkbenchEnvironmentService extends EnvironmentService implements IWorkbenchEnvironmentService { +export class NativeWorkbenchEnvironmentService extends EnvironmentService implements IWorkbenchEnvironmentService { _serviceBrand: undefined; + @memoize get webviewExternalEndpoint(): string { const baseEndpoint = 'https://{{uuid}}.vscode-webview-test.com/{{commit}}'; - return baseEndpoint.replace('{{commit}}', product.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44'); + + return baseEndpoint.replace('{{commit}}', product.commit || 'b53811e67e65c6a564a80e1c412ca2b13de02907'); } - readonly webviewResourceRoot = 'vscode-resource:{{resource}}'; - readonly webviewCspSource = 'vscode-resource:'; + @memoize + get webviewResourceRoot(): string { return 'vscode-resource://{{resource}}'; } - constructor( - readonly configuration: IWindowConfiguration, - execPath: string - ) { - super(configuration, execPath); - - this.configuration.backupWorkspaceResource = this.configuration.backupPath ? toBackupWorkspaceResource(this.configuration.backupPath, this) : undefined; - } - - get skipGettingStarted(): boolean { return !!this.args['skip-getting-started']; } - - get skipReleaseNotes(): boolean { return !!this.args['skip-release-notes']; } + @memoize + get webviewCspSource(): string { return 'vscode-resource:'; } @memoize get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.userData }); } @memoize - get logFile(): URI { return URI.file(join(this.logsPath, `renderer${this.configuration.windowId}.log`)); } + get logFile(): URI { return URI.file(join(this.logsPath, `renderer${this.windowId}.log`)); } - get logExtensionHostCommunication(): boolean { return !!this.args.logExtensionHostCommunication; } + constructor( + readonly configuration: IWindowConfiguration, + execPath: string, + private readonly windowId: number + ) { + super(configuration, execPath); - @memoize - get debugSearch(): IDebugParams { return parseSearchPort(this.args, this.isBuilt); } + this.configuration.backupWorkspaceResource = this.configuration.backupPath ? toBackupWorkspaceResource(this.configuration.backupPath, this) : undefined; + } } diff --git a/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts index 927b11bf516..c64ba121c87 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts @@ -6,7 +6,7 @@ import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionIdentifier, DidInstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionIdentifier } 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'; @@ -15,7 +15,7 @@ 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/common/extensionsUtil'; +import { canExecuteOnUI } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -26,8 +26,8 @@ export class ExtensionEnablementService extends Disposable implements IExtension _serviceBrand: undefined; - private readonly _onEnablementChanged = new Emitter(); - public readonly onEnablementChanged: Event = this._onEnablementChanged.event; + private readonly _onEnablementChanged = new Emitter(); + public readonly onEnablementChanged: Event = this._onEnablementChanged.event; private readonly storageManger: StorageManager; @@ -43,7 +43,6 @@ export class ExtensionEnablementService extends Disposable implements IExtension super(); this.storageManger = this._register(new StorageManager(storageService)); this._register(this.storageManger.onDidChange(extensions => this.onDidChangeStorage(extensions))); - this._register(extensionManagementService.onDidInstallExtension(this._onDidInstallExtension, this)); this._register(extensionManagementService.onDidUninstallExtension(this._onDidUninstallExtension, this)); } @@ -148,7 +147,7 @@ export class ExtensionEnablementService extends Disposable implements IExtension private _isDisabledByExtensionKind(extension: IExtension): boolean { if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { - if (!isUIExtension(extension.manifest, this.productService, this.configurationService)) { + if (!canExecuteOnUI(extension.manifest, this.productService, this.configurationService)) { // workspace extensions must run on the remote, but UI extensions can run on either side const server = this.extensionManagementServerService.remoteExtensionManagementServer; return this.extensionManagementServerService.getExtensionManagementServer(extension.location) !== server; @@ -286,16 +285,6 @@ export class ExtensionEnablementService extends Disposable implements IExtension this._onEnablementChanged.fire(extensions); } - private _onDidInstallExtension(event: DidInstallExtensionEvent): void { - if (event.local && event.operation === InstallOperation.Install) { - const wasDisabled = !this.isEnabled(event.local); - this._reset(event.local.identifier); - if (wasDisabled) { - this._onEnablementChanged.fire([event.local]); - } - } - } - private _onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void { if (!error) { this._reset(identifier); diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts index 88dbaf94d49..ed03aa24701 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts @@ -44,7 +44,7 @@ export interface IExtensionEnablementService { /** * Event to listen on for extension enablement changes */ - onEnablementChanged: Event; + readonly onEnablementChanged: Event; /** * Returns the enablement state for the given extension diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index 42a624ae731..63844f5d12a 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -15,7 +15,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur 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 { prefersExecuteOnUI } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IProductService } from 'vs/platform/product/common/productService'; import { Schemas } from 'vs/base/common/network'; import { IDownloadService } from 'vs/platform/download/common/download'; @@ -93,7 +93,7 @@ export class ExtensionManagementService extends Disposable implements IExtension 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) + const dependentNonUIExtensions = installedExtensions.filter(i => !prefersExecuteOnUI(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))); @@ -152,7 +152,7 @@ export class ExtensionManagementService extends Disposable implements IExtension const [local] = await Promise.all(this.servers.map(server => this.installVSIX(vsix, server))); return local; } - if (isUIExtension(manifest, this.productService, this.configurationService)) { + if (prefersExecuteOnUI(manifest, this.productService, this.configurationService)) { // Install only on local server return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer); } @@ -190,7 +190,7 @@ export class ExtensionManagementService extends Disposable implements IExtension // 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)) { + if (prefersExecuteOnUI(manifest, this.productService, this.configurationService)) { // Install only on local server return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery); } 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 88955149380..93bc95313b8 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,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import * as sinon from 'sinon'; -import { IExtensionManagementService, DidUninstallExtensionEvent, ILocalExtension, DidInstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, DidUninstallExtensionEvent, ILocalExtension, DidInstallExtensionEvent } 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'; @@ -71,12 +71,11 @@ suite('ExtensionEnablementService Test', () => { let testObject: IExtensionEnablementService; const didUninstallEvent = new Emitter(); - const didInstallEvent = new Emitter(); 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(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, getInstalled: () => Promise.resolve([] as ILocalExtension[]) } as IExtensionManagementService); instantiationService.stub(IExtensionManagementServerService, { localExtensionManagementServer: { extensionManagementService: instantiationService.get(IExtensionManagementService) @@ -338,90 +337,6 @@ suite('ExtensionEnablementService Test', () => { 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.DisabledGlobally); - didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); - assert.ok(testObject.isEnabled(local)); - 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.DisabledGlobally); - didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); - assert.ok(!testObject.isEnabled(local)); - 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.DisabledGlobally); - return new Promise((c, e) => { - testObject.onEnablementChanged(([e]) => { - if (e.identifier.id === local.identifier.id) { - c(); - } - }); - didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); - }); - }); - - 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.DisabledGlobally); - testObject.onEnablementChanged(target); - didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); - assert.ok(!target.called); - }); - - test('test installing an extension re-eanbles it when workspace disabled', async () => { - const local = aLocalExtension('pub.a'); - 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.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.DisabledWorkspace); - didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); - assert.ok(!testObject.isEnabled(local)); - 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.DisabledWorkspace); - return new Promise((c, e) => { - testObject.onEnablementChanged(([e]) => { - if (e.identifier.id === local.identifier.id) { - c(); - } - }); - didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); - }); - }); - - 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.DisabledWorkspace); - testObject.onEnablementChanged(target); - didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); - assert.ok(!target.called); - }); - - test('test installing an extension should not fire enablement change event when extension is not disabled', async () => { - const target = sinon.spy(); - const local = aLocalExtension('pub.a'); - testObject.onEnablementChanged(target); - didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); - assert.ok(!target.called); - }); - test('test remove an extension from disablement list when uninstalled', async () => { const extension = aLocalExtension('pub.a'); await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); @@ -480,7 +395,7 @@ suite('ExtensionEnablementService Test', () => { test('test extension is disabled when disabled in enviroment', async () => { const extension = aLocalExtension('pub.a'); instantiationService.stub(IWorkbenchEnvironmentService, { disableExtensions: ['pub.a'] } as IWorkbenchEnvironmentService); - instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, onDidInstallExtension: didInstallEvent.event, getInstalled: () => Promise.resolve([extension, aLocalExtension('pub.b')]) } as IExtensionManagementService); + instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.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.DisabledByEnvironemt); diff --git a/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts new file mode 100644 index 00000000000..f2d816cca9e --- /dev/null +++ b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; +import * as dom from 'vs/base/browser/dom'; +import { Schemas } from 'vs/base/common/network'; + +class ExtensionResourceLoaderService implements IExtensionResourceLoaderService { + + _serviceBrand: undefined; + + constructor( + @IFileService private readonly _fileService: IFileService + ) { } + + async readExtensionResource(uri: URI): Promise { + uri = dom.asDomUri(uri); + + if (uri.scheme !== Schemas.http && uri.scheme !== Schemas.https) { + const result = await this._fileService.readFile(uri); + return result.value.toString(); + } + + const response = await fetch(uri.toString(true)); + if (response.status !== 200) { + throw new Error(response.statusText); + } + return response.text(); + + } +} + +registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService); diff --git a/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts new file mode 100644 index 00000000000..300a54b0842 --- /dev/null +++ b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IExtensionResourceLoaderService = createDecorator('extensionResourceLoaderService'); + +/** + * A service useful for reading resources from within extensions. + */ +export interface IExtensionResourceLoaderService { + _serviceBrand: undefined; + + /** + * Read a certain resource within an extension. + */ + readExtensionResource(uri: URI): Promise; +} diff --git a/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts new file mode 100644 index 00000000000..2acf10e0b53 --- /dev/null +++ b/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.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 { URI } from 'vs/base/common/uri'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; + +class ExtensionResourceLoaderService implements IExtensionResourceLoaderService { + + _serviceBrand: undefined; + + constructor( + @IFileService private readonly _fileService: IFileService + ) { } + + async readExtensionResource(uri: URI): Promise { + const result = await this._fileService.readFile(uri); + return result.value.toString(); + } +} + +registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService); diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts index 000e5f7b4ab..d164f2c1275 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -20,7 +20,7 @@ import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEn import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { WebWorkerExtensionHostStarter } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter'; import { URI } from 'vs/base/common/uri'; -import { isWebExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { canExecuteOnWeb } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { FetchFileSystemProvider } from 'vs/workbench/services/extensions/browser/webWorkerFileSystemProvider'; @@ -85,14 +85,14 @@ export class ExtensionService extends AbstractExtensionService implements IExten protected _createExtensionHosts(_isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] { const result: ExtensionHostProcessManager[] = []; - const webExtensions = this.getExtensions().then(extensions => extensions.filter(ext => isWebExtension(ext, this._configService))); + const webExtensions = this.getExtensions().then(extensions => extensions.filter(ext => canExecuteOnWeb(ext, this._productService, this._configService))); const webHostProcessWorker = this._instantiationService.createInstance(WebWorkerExtensionHostStarter, true, webExtensions, URI.file(this._environmentService.logsPath).with({ scheme: this._environmentService.logFile.scheme })); const webHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, webHostProcessWorker, null, initialActivationEvents); result.push(webHostProcessManager); const remoteAgentConnection = this._remoteAgentService.getConnection(); if (remoteAgentConnection) { - const remoteExtensions = this.getExtensions().then(extensions => extensions.filter(ext => !isWebExtension(ext, this._configService))); + const remoteExtensions = this.getExtensions().then(extensions => extensions.filter(ext => !canExecuteOnWeb(ext, this._productService, this._configService))); const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, remoteExtensions, this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory); const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); result.push(remoteExtHostProcessManager); @@ -111,7 +111,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten let result: DeltaExtensionsResult; // local: only enabled and web'ish extension - localExtensions = localExtensions.filter(ext => this._isEnabled(ext) && isWebExtension(ext, this._configService)); + localExtensions = localExtensions!.filter(ext => this._isEnabled(ext) && canExecuteOnWeb(ext, this._productService, this._configService)); this._checkEnableProposedApi(localExtensions); if (!remoteEnv) { @@ -119,7 +119,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten } else { // remote: only enabled and none-web'ish extension - remoteEnv.extensions = remoteEnv.extensions.filter(extension => this._isEnabled(extension) && !isWebExtension(extension, this._configService)); + remoteEnv.extensions = remoteEnv.extensions.filter(extension => this._isEnabled(extension) && !canExecuteOnWeb(extension, this._productService, this._configService)); this._checkEnableProposedApi(remoteEnv.extensions); // in case of overlap, the remote wins diff --git a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index c969bd3df55..c63f391949e 100644 --- a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -9,13 +9,13 @@ import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/li import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService, ExtensionsLabel } 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'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IURLHandler, IURLService } from 'vs/platform/url/common/url'; +import { IURLHandler, IURLService, IOpenURLOptions } from 'vs/platform/url/common/url'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -23,16 +23,47 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution, Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; 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); } +class ConfirmedExtensionIdStorage { + + get extensions(): string[] { + const confirmedExtensionIdsJson = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); + + try { + return JSON.parse(confirmedExtensionIdsJson); + } catch { + return []; + } + } + + constructor(private storageService: IStorageService) { } + + has(id: string): boolean { + return this.extensions.indexOf(id) > -1; + } + + add(id: string): void { + this.set([...this.extensions, id]); + } + + set(ids: string[]): void { + this.storageService.store(CONFIRMED_EXTENSIONS_STORAGE_KEY, JSON.stringify(ids), StorageScope.GLOBAL); + } +} + export const IExtensionUrlHandler = createDecorator('extensionUrlHandler'); export interface IExtensionUrlHandler { @@ -56,6 +87,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { private extensionHandlers = new Map(); private uriBuffer = new Map(); + private storage: ConfirmedExtensionIdStorage; private disposable: IDisposable; constructor( @@ -70,11 +102,13 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { @IStorageService private readonly storageService: IStorageService, @IConfigurationService private readonly configurationService: IConfigurationService ) { + this.storage = new ConfirmedExtensionIdStorage(storageService); + const interval = setInterval(() => this.garbageCollect(), THIRTY_SECONDS); const urlToHandleValue = this.storageService.get(URL_TO_HANDLE, StorageScope.WORKSPACE); if (urlToHandleValue) { this.storageService.remove(URL_TO_HANDLE, StorageScope.WORKSPACE); - this.handleURL(URI.revive(JSON.parse(urlToHandleValue)), true); + this.handleURL(URI.revive(JSON.parse(urlToHandleValue)), { trusted: true }); } this.disposable = combinedDisposable( @@ -86,7 +120,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { setTimeout(() => cache.forEach(uri => this.handleURL(uri))); } - async handleURL(uri: URI, confirmed?: boolean): Promise { + async handleURL(uri: URI, options?: IOpenURLOptions): Promise { if (!isExtensionId(uri.authority)) { return false; } @@ -100,13 +134,15 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return true; } - if (!confirmed) { - const confirmedExtensionIds = this.getConfirmedExtensionIds(); - confirmed = confirmedExtensionIds.has(ExtensionIdentifier.toKey(extensionId)); + let showConfirm: boolean; + if (options && options.trusted) { + showConfirm = false; + } else { + showConfirm = !this.isConfirmed(ExtensionIdentifier.toKey(extensionId)); } - if (!confirmed) { - let uriString = uri.toString(); + if (showConfirm) { + let uriString = uri.toString(false); if (uriString.length > 40) { uriString = `${uriString.substring(0, 30)}...${uriString.substring(uriString.length - 5)}`; @@ -127,7 +163,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } if (result.checkboxChecked) { - await this.addConfirmedExtensionIdToStorage(extensionId); + this.storage.add(ExtensionIdentifier.toKey(extensionId)); } } @@ -136,7 +172,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { if (handler) { if (!wasHandlerAvailable) { // forward it directly - return await handler.handleURL(uri); + return await handler.handleURL(uri, options); } // let the ExtensionUrlHandler instance handle this @@ -288,11 +324,12 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.uriBuffer = uriBuffer; } - private getConfirmedExtensionIds(): Set { - const ids = this.getConfirmedExtensionIdsFromConfiguration() - .map(extensionId => ExtensionIdentifier.toKey(extensionId)); + private isConfirmed(id: string): boolean { + if (this.storage.has(id)) { + return true; + } - return new Set(ids); + return this.getConfirmedExtensionIdsFromConfiguration().indexOf(id) > -1; } private getConfirmedExtensionIdsFromConfiguration(): Array { @@ -305,14 +342,6 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return confirmedExtensionIds; } - private async addConfirmedExtensionIdToStorage(extensionId: string): Promise { - const confirmedExtensionIds = this.configurationService.getValue>(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY); - const set = new Set(confirmedExtensionIds); - set.add(extensionId); - - await this.configurationService.updateValue(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY, [...set.values()]); - } - dispose(): void { this.disposable.dispose(); this.extensionHandlers.clear(); @@ -343,11 +372,52 @@ class ExtensionUrlBootstrapHandler implements IWorkbenchContribution, IURLHandle ExtensionUrlBootstrapHandler.disposable = urlService.registerHandler(this); } - handleURL(uri: URI): Promise { + async handleURL(uri: URI): Promise { + if (!isExtensionId(uri.authority)) { + return false; + } + ExtensionUrlBootstrapHandler._cache.push(uri); - return Promise.resolve(true); + return true; } } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(ExtensionUrlBootstrapHandler, LifecyclePhase.Ready); + +export class ManageAuthorizedExtensionURIsAction extends Action { + + static readonly ID = 'workbench.extensions.action.manageAuthorizedExtensionURIs'; + static readonly LABEL = localize('manage', "Manage Authorized Extension URIs..."); + + private storage: ConfirmedExtensionIdStorage; + + constructor( + id = ManageAuthorizedExtensionURIsAction.ID, + label = ManageAuthorizedExtensionURIsAction.LABEL, + @IStorageService readonly storageService: IStorageService, + @IQuickInputService private readonly quickInputService: IQuickInputService + ) { + super(id, label, undefined, true); + this.storage = new ConfirmedExtensionIdStorage(storageService); + } + + async run(): Promise { + const items = this.storage.extensions.map(label => ({ label, picked: true } as IQuickPickItem)); + + if (items.length === 0) { + return; + } + + const result = await this.quickInputService.pick(items, { canPickMany: true }); + + if (!result) { + return; + } + + this.storage.set(result.map(item => item.label)); + } +} + +const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ManageAuthorizedExtensionURIsAction, ManageAuthorizedExtensionURIsAction.ID, ManageAuthorizedExtensionURIsAction.LABEL), `Extensions: Manage Authorized Extension URIs...`, ExtensionsLabel); diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts index 406331cb2bc..e74228ce1dc 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts @@ -113,6 +113,10 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter { return undefined; } + enableInspectPort(): Promise { + return Promise.resolve(false); + } + private async _createExtHostInitData(): Promise { const [telemetryInfo, extensionDescriptions] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._extensions]); const workspace = this._contextService.getWorkspace(); diff --git a/src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts b/src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts index 13afbbcce1f..c0e53c971a5 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts @@ -3,14 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IFileSystemProvider, FileSystemProviderCapabilities, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileSystemProviderError, FileSystemProviderErrorCode } from 'vs/platform/files/common/files'; - +import { FileSystemProviderCapabilities, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileSystemProviderError, FileSystemProviderErrorCode, IFileSystemProviderWithFileReadWriteCapability } from 'vs/platform/files/common/files'; import { Event } from 'vs/base/common/event'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { NotImplementedError } from 'vs/base/common/errors'; -export class FetchFileSystemProvider implements IFileSystemProvider { +export class FetchFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability { readonly capabilities = FileSystemProviderCapabilities.Readonly + FileSystemProviderCapabilities.FileReadWrite + FileSystemProviderCapabilities.PathCaseSensitive; readonly onDidChangeCapabilities = Event.None; diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index 65d4c2f70ac..9833bbfb888 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -256,8 +256,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx return result; } - public getInspectPort(): number { - return 0; + public getInspectPort(_tryEnableInspector: boolean): Promise { + return Promise.resolve(0); } public async setRemoteEnvironment(env: { [key: string]: string | null }): Promise { @@ -459,9 +459,10 @@ class ProposedApiController { // Make enabled proposed API be lowercase for case insensitive comparison this.enableProposedApiFor = (environmentService.args['enable-proposed-api'] || []).map(id => id.toLowerCase()); - this.enableProposedApiForAll = !environmentService.isBuilt || - (!!environmentService.extensionDevelopmentLocationURI && productService.nameLong !== 'Visual Studio Code') || - (this.enableProposedApiFor.length === 0 && 'enable-proposed-api' in environmentService.args); + this.enableProposedApiForAll = + !environmentService.isBuilt || // always allow proposed API when running out of sources + (!!environmentService.extensionDevelopmentLocationURI && productService.quality !== 'stable') || // do not allow proposed API against stable builds when developing an extension + (this.enableProposedApiFor.length === 0 && 'enable-proposed-api' in environmentService.args); // always allow proposed API if --enable-proposed-api is provided without extension ID this.productAllowProposedApi = new Set(); if (isNonEmptyArray(productService.extensionAllowedProposedApi)) { diff --git a/src/vs/workbench/services/extensions/common/extensionDevOptions.ts b/src/vs/workbench/services/extensions/common/extensionDevOptions.ts index 66a35aadda1..ba9a9ba9fee 100644 --- a/src/vs/workbench/services/extensions/common/extensionDevOptions.ts +++ b/src/vs/workbench/services/extensions/common/extensionDevOptions.ts @@ -29,7 +29,7 @@ export function parseExtensionDevOptions(environmentService: IEnvironmentService let isExtensionDevDebug = debugOk && typeof environmentService.debugExtensionHost.port === 'number'; let isExtensionDevDebugBrk = debugOk && !!environmentService.debugExtensionHost.break; - let isExtensionDevTestFromCli = isExtensionDevHost && !!environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.break; + let isExtensionDevTestFromCli = isExtensionDevHost && !!environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.debugId; return { isExtensionDevHost, isExtensionDevDebug, diff --git a/src/vs/workbench/services/extensions/common/extensionHostMain.ts b/src/vs/workbench/services/extensions/common/extensionHostMain.ts index 16356a4a96c..da1dc8e9a9e 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostMain.ts @@ -6,7 +6,7 @@ import { timeout } from 'vs/base/common/async'; import * as errors from 'vs/base/common/errors'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import { IURITransformer } from 'vs/base/common/uriIpc'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol'; @@ -22,10 +22,6 @@ import { IExtHostRpcService, ExtHostRpcService } from 'vs/workbench/api/common/e import { IURITransformerService, URITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostExtensionService, IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; -// we don't (yet) throw when extensions parse -// uris that have no scheme -setUriThrowOnMissingScheme(false); - export interface IExitFn { (code?: number): any; } diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts index 3aff4a5e57f..8950a9e8c96 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts @@ -57,7 +57,7 @@ export class ExtensionHostProcessManager extends Disposable { constructor( public readonly isLocal: boolean, extensionHostProcessWorker: IExtensionHostStarter, - private readonly _remoteAuthority: string, + private readonly _remoteAuthority: string | null, initialActivationEvents: string[], @IInstantiationService private readonly _instantiationService: IInstantiationService, @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, @@ -185,7 +185,7 @@ export class ExtensionHostProcessManager extends Disposable { this._extensionHostProcessRPCProtocol = new RPCProtocol(protocol, logger); this._register(this._extensionHostProcessRPCProtocol.onDidChangeResponsiveState((responsiveState: ResponsiveState) => this._onDidChangeResponsiveState.fire(responsiveState))); const extHostContext: IExtHostContext = { - remoteAuthority: this._remoteAuthority, + remoteAuthority: this._remoteAuthority! /* TODO: sandy081, remove not-null assertion */, getProxy: (identifier: ProxyIdentifier): T => this._extensionHostProcessRPCProtocol!.getProxy(identifier), set: (identifier: ProxyIdentifier, instance: R): R => this._extensionHostProcessRPCProtocol!.set(identifier, instance), assertRegistered: (identifiers: ProxyIdentifier[]): void => this._extensionHostProcessRPCProtocol!.assertRegistered(identifiers), @@ -238,8 +238,11 @@ export class ExtensionHostProcessManager extends Disposable { }); } - public getInspectPort(): number { + public async getInspectPort(tryEnableInspector: boolean): Promise { if (this._extensionHostProcessWorker) { + if (tryEnableInspector) { + await this._extensionHostProcessWorker.enableInspectPort(); + } let port = this._extensionHostProcessWorker.getInspectPort(); if (port) { return port; @@ -248,10 +251,6 @@ export class ExtensionHostProcessManager extends Disposable { return 0; } - public canProfileExtensionHost(): boolean { - return this._extensionHostProcessWorker && Boolean(this._extensionHostProcessWorker.getInspectPort()); - } - public async resolveAuthority(remoteAuthority: string): Promise { const authorityPlusIndex = remoteAuthority.indexOf('+'); if (authorityPlusIndex === -1) { @@ -361,7 +360,7 @@ class RPCLogger implements IRPCProtocolLogger { } interface ExtHostLatencyResult { - remoteAuthority: string; + remoteAuthority: string | null; up: number; down: number; latency: number; diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index d68777ae83b..074447cab22 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -89,6 +89,7 @@ export interface IExtensionHostStarter { start(): Promise | null; getInspectPort(): number | undefined; + enableInspectPort(): Promise; dispose(): void; } @@ -212,7 +213,7 @@ export interface IExtensionService { * Return the inspect port or `0`, the latter means inspection * is not possible. */ - getInspectPort(): number; + getInspectPort(tryEnableInspector: boolean): Promise; /** * Restarts the extension host. @@ -270,7 +271,7 @@ export class NullExtensionService implements IExtensionService { getExtension() { return Promise.resolve(undefined); } readExtensionPointContributions(_extPoint: IExtensionPoint): Promise[]> { return Promise.resolve(Object.create(null)); } getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { return Object.create(null); } - getInspectPort(): number { return 0; } + getInspectPort(_tryEnableInspector: boolean): Promise { return Promise.resolve(0); } restartExtensionHost(): void { } async setRemoteEnvironment(_env: { [key: string]: string | null }): Promise { } canAddExtension(): boolean { return false; } diff --git a/src/vs/workbench/services/extensions/common/extensionsRegistry.ts b/src/vs/workbench/services/extensions/common/extensionsRegistry.ts index 4f2765ac997..08d1fb90be7 100644 --- a/src/vs/workbench/services/extensions/common/extensionsRegistry.ts +++ b/src/vs/workbench/services/extensions/common/extensionsRegistry.ts @@ -146,6 +146,18 @@ export class ExtensionPoint implements IExtensionPoint { } } +const extensionKindSchema = { + 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.") + ], +}; + const schemaId = 'vscode://schemas/vscode-extensions'; export const schema = { properties: { @@ -346,16 +358,22 @@ export const schema = { }, 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' + oneOf: [{ type: 'array', items: extensionKindSchema }, extensionKindSchema], + default: 'workspace', + defaultSnippets: [ + { + body: ['ui', 'workspace'], + description: nls.localize('extensionKind.ui-workspace', "Define an extension which can run on either side, with a preference towards running on the local machine.") + }, + { + body: ['workspace', 'ui'], + description: nls.localize('extensionKind.workspace-ui', "Define an extension which can run on either side, with a preference towards running on the remote machine.") + }, + { + body: [], + description: nls.localize('extensionKind.empty', "Define an extension which cannot run in a remote context, neither on the local, nor on the remote machine.") + } + ] }, scripts: { type: 'object', diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts index 49b2d270c04..83fdf37fb67 100644 --- a/src/vs/workbench/services/extensions/common/extensionsUtil.ts +++ b/src/vs/workbench/services/extensions/common/extensionsUtil.ts @@ -4,55 +4,114 @@ *--------------------------------------------------------------------------------------------*/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { IExtensionManifest, ExtensionKind, ExtensionIdentifier } 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 { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { IProductService } from 'vs/platform/product/common/productService'; -export function isWebExtension(manifest: IExtensionManifest, configurationService: IConfigurationService): boolean { - const extensionKind = getExtensionKind(manifest, configurationService); - return extensionKind === 'web'; +export function prefersExecuteOnUI(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean { + const extensionKind = getExtensionKind(manifest, productService, configurationService); + return (extensionKind.length > 0 && extensionKind[0] === 'ui'); } -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; - } - } +export function canExecuteOnUI(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean { + const extensionKind = getExtensionKind(manifest, productService, configurationService); + return extensionKind.some(kind => kind === 'ui'); } -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]; +export function canExecuteOnWeb(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean { + const extensionKind = getExtensionKind(manifest, productService, configurationService); + return extensionKind.some(kind => kind === 'web'); +} + +export function getExtensionKind(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): ExtensionKind[] { + // check in config + let result = getConfiguredExtensionKind(manifest, configurationService); + if (typeof result !== 'undefined') { + return toArray(result); + } + + // check the manifest itself + result = manifest.extensionKind; + if (typeof result !== 'undefined') { + return toArray(result); + } + + // check product.json + result = getProductExtensionKind(manifest, productService); + if (typeof result !== 'undefined') { + return toArray(result); + } + + // Not an UI extension if it has main + if (manifest.main) { + return ['workspace']; + } + + // Not an UI extension if it has dependencies or an extension pack + if (isNonEmptyArray(manifest.extensionDependencies) || isNonEmptyArray(manifest.extensionPack)) { + return ['workspace']; + } + + if (manifest.contributes) { + // Not an UI extension if it has no ui contributions + for (const contribution of Object.keys(manifest.contributes)) { + if (!isUIExtensionPoint(contribution)) { + return ['workspace']; + } } } - return manifest.extensionKind; + + return ['ui', 'workspace']; +} + +let _uiExtensionPoints: Set | null = null; +function isUIExtensionPoint(extensionPoint: string): boolean { + if (_uiExtensionPoints === null) { + const uiExtensionPoints = new Set(); + ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').forEach(e => { + uiExtensionPoints.add(e.name); + }); + _uiExtensionPoints = uiExtensionPoints; + } + return _uiExtensionPoints.has(extensionPoint); +} + +let _productExtensionKindsMap: Map | null = null; +function getProductExtensionKind(manifest: IExtensionManifest, productService: IProductService): ExtensionKind | ExtensionKind[] | undefined { + if (_productExtensionKindsMap === null) { + const productExtensionKindsMap = new Map(); + if (productService.extensionKind) { + for (const id of Object.keys(productService.extensionKind)) { + productExtensionKindsMap.set(ExtensionIdentifier.toKey(id), productService.extensionKind[id]); + } + } + _productExtensionKindsMap = productExtensionKindsMap; + } + + const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name); + return _productExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId)); +} + +let _configuredExtensionKindsMap: Map | null = null; +function getConfiguredExtensionKind(manifest: IExtensionManifest, configurationService: IConfigurationService): ExtensionKind | ExtensionKind[] | undefined { + if (_configuredExtensionKindsMap === null) { + const configuredExtensionKindsMap = new Map(); + const configuredExtensionKinds = configurationService.getValue<{ [key: string]: ExtensionKind | ExtensionKind[] }>('remote.extensionKind') || {}; + for (const id of Object.keys(configuredExtensionKinds)) { + configuredExtensionKindsMap.set(ExtensionIdentifier.toKey(id), configuredExtensionKinds[id]); + } + _configuredExtensionKindsMap = configuredExtensionKindsMap; + } + + const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name); + return _configuredExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId)); +} + +function toArray(extensionKind: ExtensionKind | ExtensionKind[]): ExtensionKind[] { + if (Array.isArray(extensionKind)) { + return extensionKind; + } + return [extensionKind]; } diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts index 8dfa1bd4522..83b800cad49 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts @@ -225,6 +225,10 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH return undefined; } + enableInspectPort(): Promise { + return Promise.resolve(false); + } + dispose(): void { super.dispose(); diff --git a/src/vs/workbench/services/extensions/common/rpcProtocol.ts b/src/vs/workbench/services/extensions/common/rpcProtocol.ts index c3cd43edd6a..d1464a513a3 100644 --- a/src/vs/workbench/services/extensions/common/rpcProtocol.ts +++ b/src/vs/workbench/services/extensions/common/rpcProtocol.ts @@ -58,7 +58,7 @@ const noop = () => { }; export class RPCProtocol extends Disposable implements IRPCProtocol { - private static UNRESPONSIVE_TIME = 3 * 1000; // 3s + private static readonly UNRESPONSIVE_TIME = 3 * 1000; // 3s private readonly _onDidChangeResponsiveState: Emitter = this._register(new Emitter()); public readonly onDidChangeResponsiveState: Event = this._onDidChangeResponsiveState.event; @@ -364,12 +364,16 @@ export class RPCProtocol extends Disposable implements IRPCProtocol { const pendingReply = this._pendingRPCReplies[callId]; delete this._pendingRPCReplies[callId]; - let err: Error | null = null; - if (value && value.$isError) { - err = new Error(); - err.name = value.name; - err.message = value.message; - err.stack = value.stack; + let err: any = undefined; + if (value) { + if (value.$isError) { + err = new Error(); + err.name = value.name; + err.message = value.message; + err.stack = value.stack; + } else { + err = value; + } } pendingReply.resolveErr(err); } @@ -539,10 +543,16 @@ class MessageBuffer { const el = arr[i]; const elType = arrType[i]; size += 1; // arg type - if (elType === ArgType.String) { - size += this.sizeLongString(el); - } else { - size += this.sizeVSBuffer(el); + switch (elType) { + case ArgType.String: + size += this.sizeLongString(el); + break; + case ArgType.VSBuffer: + size += this.sizeVSBuffer(el); + break; + case ArgType.Undefined: + // empty... + break; } } return size; @@ -553,19 +563,25 @@ class MessageBuffer { for (let i = 0, len = arr.length; i < len; i++) { const el = arr[i]; const elType = arrType[i]; - if (elType === ArgType.String) { - this.writeUInt8(ArgType.String); - this.writeLongString(el); - } else { - this.writeUInt8(ArgType.VSBuffer); - this.writeVSBuffer(el); + switch (elType) { + case ArgType.String: + this.writeUInt8(ArgType.String); + this.writeLongString(el); + break; + case ArgType.VSBuffer: + this.writeUInt8(ArgType.VSBuffer); + this.writeVSBuffer(el); + break; + case ArgType.Undefined: + this.writeUInt8(ArgType.Undefined); + break; } } } - public readMixedArray(): Array { + public readMixedArray(): Array { const arrLen = this._buff.readUInt8(this._offset); this._offset += 1; - let arr: Array = new Array(arrLen); + let arr: Array = new Array(arrLen); for (let i = 0; i < arrLen; i++) { const argType = this.readUInt8(); switch (argType) { @@ -575,6 +591,9 @@ class MessageBuffer { case ArgType.VSBuffer: arr[i] = this.readVSBuffer(); break; + case ArgType.Undefined: + arr[i] = undefined; + break; } } return arr; @@ -583,17 +602,20 @@ class MessageBuffer { class MessageIO { - private static _arrayContainsBuffer(arr: any[]): boolean { + private static _arrayContainsBufferOrUndefined(arr: any[]): boolean { for (let i = 0, len = arr.length; i < len; i++) { if (arr[i] instanceof VSBuffer) { return true; } + if (typeof arr[i] === 'undefined') { + return true; + } } return false; } public static serializeRequest(req: number, rpcId: number, method: string, args: any[], usesCancellationToken: boolean, replacer: JSONStringifyReplacer | null): VSBuffer { - if (this._arrayContainsBuffer(args)) { + if (this._arrayContainsBufferOrUndefined(args)) { let massagedArgs: VSBuffer[] = []; let massagedArgsType: ArgType[] = []; for (let i = 0, len = args.length; i < len; i++) { @@ -601,6 +623,9 @@ class MessageIO { if (arg instanceof VSBuffer) { massagedArgs[i] = arg; massagedArgsType[i] = ArgType.VSBuffer; + } else if (typeof arg === 'undefined') { + massagedArgs[i] = VSBuffer.alloc(0); + massagedArgsType[i] = ArgType.Undefined; } else { massagedArgs[i] = VSBuffer.fromString(safeStringify(arg, replacer)); massagedArgsType[i] = ArgType.String; @@ -725,7 +750,7 @@ class MessageIO { } public static serializeReplyErr(req: number, err: any): VSBuffer { - if (err instanceof Error) { + if (err) { return this._serializeReplyErrEror(req, err); } return this._serializeReplyErrEmpty(req); @@ -768,5 +793,6 @@ const enum MessageType { const enum ArgType { String = 1, - VSBuffer = 2 + VSBuffer = 2, + Undefined = 3 } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 1963444f46f..87de5701125 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -16,7 +16,7 @@ import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { IRemoteConsoleLog, log } from 'vs/base/common/console'; import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteConsoleUtil'; -import { findFreePort, randomPort } from 'vs/base/node/ports'; +import { findFreePort } from 'vs/base/node/ports'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; import { generateRandomPipeName, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; @@ -37,7 +37,7 @@ import { parseExtensionDevOptions } from '../common/extensionDevOptions'; import { VSBuffer } from 'vs/base/common/buffer'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions'; -import { isEqualOrParent } from 'vs/base/common/resources'; +import { isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { IHostService } from 'vs/workbench/services/host/browser/host'; export class ExtensionHostProcessWorker implements IExtensionHostStarter { @@ -45,6 +45,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>(); public readonly onExit: Event<[number, string]> = this._onExit.event; + private readonly _onDidSetInspectPort = new Emitter(); + private readonly _toDispose = new DisposableStore(); private readonly _isExtensionDevHost: boolean; @@ -127,10 +129,10 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { if (!this._messageProtocol) { this._messageProtocol = Promise.all([ this._tryListenOnPipe(), - !this._environmentService.args['disable-inspect'] ? this._tryFindDebugPort() : Promise.resolve(null) + this._tryFindDebugPort() ]).then(data => { const pipeName = data[0]; - const portData = data[1]; + const portNumber = data[1]; const opts = { env: objects.mixin(objects.deepClone(process.env), { @@ -151,16 +153,11 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { silent: true }; - if (portData && portData.actual) { + if (portNumber !== 0) { opts.execArgv = [ '--nolazy', - (this._isExtensionDevDebugBrk ? '--inspect-brk=' : '--inspect=') + portData.actual + (this._isExtensionDevDebugBrk ? '--inspect-brk=' : '--inspect=') + portNumber ]; - if (!portData.expected) { - // No one asked for 'inspect' or 'inspect-brk', only us. We add another - // option such that the extension host can manipulate the execArgv array - opts.env.VSCODE_PREVENT_FOREIGN_INSPECT = true; - } } const crashReporterOptions = undefined; // TODO@electron pass this in as options to the extension host after verifying this actually works @@ -173,10 +170,10 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { // Catch all output coming from the extension host process type Output = { data: string, format: string[] }; - this._extensionHostProcess.stdout.setEncoding('utf8'); - this._extensionHostProcess.stderr.setEncoding('utf8'); - const onStdout = Event.fromNodeEventEmitter(this._extensionHostProcess.stdout, 'data'); - const onStderr = Event.fromNodeEventEmitter(this._extensionHostProcess.stderr, 'data'); + this._extensionHostProcess.stdout!.setEncoding('utf8'); + this._extensionHostProcess.stderr!.setEncoding('utf8'); + const onStdout = Event.fromNodeEventEmitter(this._extensionHostProcess.stdout!, 'data'); + const onStderr = Event.fromNodeEventEmitter(this._extensionHostProcess.stderr!, 'data'); const onOutput = Event.any( Event.map(onStdout, o => ({ data: `%c${o}`, format: [''] })), Event.map(onStderr, o => ({ data: `%c${o}`, format: ['color: red'] })) @@ -198,6 +195,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { } if (!this._inspectPort) { this._inspectPort = Number(inspectorUrlMatch[2]); + this._onDidSetInspectPort.fire(); } } else { console.group('Extension Host'); @@ -218,11 +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 (portData) { - if (this._isExtensionDevHost && portData.actual && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { - this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portData.actual); + if (portNumber) { + if (this._isExtensionDevHost && portNumber && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { + this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portNumber); } - this._inspectPort = portData.actual; + this._inspectPort = portNumber; + this._onDidSetInspectPort.fire(); } // Help in case we fail to start it @@ -275,29 +274,31 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { /** * Find a free port if extension host debugging is enabled. */ - private _tryFindDebugPort(): Promise<{ expected: number; actual: number }> { - let expected: number; - let startPort = randomPort(); - if (typeof this._environmentService.debugExtensionHost.port === 'number') { - startPort = expected = this._environmentService.debugExtensionHost.port; + private async _tryFindDebugPort(): Promise { + + if (typeof this._environmentService.debugExtensionHost.port !== 'number') { + return 0; } - 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:'); - } else { - if (expected && port !== expected) { - 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:'); - } else { - console.info(`%c[Extension Host] %cdebugger listening on port ${port}`, 'color: blue', 'color:'); - } - } - return resolve({ expected, actual: port }); - }); - }); + + const expected = this._environmentService.debugExtensionHost.port; + const port = await findFreePort(expected, 10 /* try 10 ports */, 5000 /* try up to 5 seconds */); + + if (!port) { + console.warn('%c[Extension Host] %cCould not find a free port for debugging', 'color: blue', 'color:'); + return 0; + } + + if (port !== expected) { + 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:'); + } else { + console.info(`%c[Extension Host] %cdebugger listening on port ${port}`, 'color: blue', 'color:'); + } + return port; + + } private _tryExtHostHandshake(): Promise { @@ -409,7 +410,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { configuration: withNullAsUndefined(workspace.configuration), id: workspace.id, name: this._labelService.getWorkspaceLabel(workspace), - isUntitled: workspace.configuration ? isEqualOrParent(workspace.configuration, this._environmentService.untitledWorkspacesHome) : false + isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false }, remote: { authority: this._environmentService.configuration.remoteAuthority, @@ -430,19 +431,19 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { private _logExtensionHostMessage(entry: IRemoteConsoleLog) { - // Send to local console unless we run tests from cli - if (!this._isExtensionDevTestFromCli) { - log(entry, 'Extension Host'); - } - - // Log on main side if running tests from cli if (this._isExtensionDevTestFromCli) { - logRemoteEntry(this._logService, entry); - } - // Broadcast to other windows if we are in development mode - else if (this._environmentService.debugExtensionHost.debugId && (!this._environmentService.isBuilt || this._isExtensionDevHost)) { - this._extensionHostDebugService.logToSession(this._environmentService.debugExtensionHost.debugId, entry); + // Log on main side if running tests from cli + logRemoteEntry(this._logService, entry); + } else { + + // Send to local console + log(entry, 'Extension Host'); + + // Broadcast to other windows if we are in development mode + if (this._environmentService.debugExtensionHost.debugId && (!this._environmentService.isBuilt || this._isExtensionDevHost)) { + this._extensionHostDebugService.logToSession(this._environmentService.debugExtensionHost.debugId, entry); + } } } @@ -466,6 +467,37 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { this._onExit.fire([code, signal]); } + public async enableInspectPort(): Promise { + if (typeof this._inspectPort === 'number') { + return true; + } + + if (!this._extensionHostProcess) { + return false; + } + + interface ProcessExt { + _debugProcess?(n: number): any; + } + + if (typeof (process)._debugProcess === 'function') { + // use (undocumented) _debugProcess feature of node + (process)._debugProcess!(this._extensionHostProcess.pid); + await Promise.race([Event.toPromise(this._onDidSetInspectPort.event), timeout(1000)]); + return typeof this._inspectPort === 'number'; + + } else if (!platform.isWindows) { + // use KILL USR1 on non-windows platforms (fallback) + this._extensionHostProcess.kill('SIGUSR1'); + await Promise.race([Event.toPromise(this._onDidSetInspectPort.event), timeout(1000)]); + return typeof this._inspectPort === 'number'; + + } else { + // not supported... + return false; + } + } + public getInspectPort(): number | undefined { return withNullAsUndefined(this._inspectPort); } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 3511f45c56e..bdcbe53192d 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -19,13 +19,12 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur 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 as isUIExtensionFunc } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { getExtensionKind } 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 { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager'; @@ -38,6 +37,7 @@ import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints' import { flatten } from 'vs/base/common/arrays'; import { IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; class DeltaExtensionsQueueItem { constructor( @@ -67,10 +67,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten @IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService, @IConfigurationService private readonly _configurationService: IConfigurationService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, - @IWindowService protected readonly _windowService: IWindowService, @IStaticExtensionsService private readonly _staticExtensions: IStaticExtensionsService, @IElectronService private readonly _electronService: IElectronService, - @IHostService private readonly _hostService: IHostService + @IHostService private readonly _hostService: IHostService, + @IElectronEnvironmentService private readonly _electronEnvironmentService: IElectronEnvironmentService ) { super( instantiationService, @@ -93,7 +93,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten this._remoteExtensionsEnvironmentData = new Map(); - this._extensionHostLogsLocation = URI.file(path.join(this._environmentService.logsPath, `exthost${this._windowService.windowId}`)); + this._extensionHostLogsLocation = URI.file(path.join(this._environmentService.logsPath, `exthost${this._electronEnvironmentService.windowId}`)); this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner); this._deltaExtensionsQueue = []; @@ -434,8 +434,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten } protected async _scanAndHandleExtensions(): Promise { - const isUIExtension = (extension: IExtensionDescription) => isUIExtensionFunc(extension, this._productService, this._configurationService); - this._extensionScanner.startScanningExtensions(this.createLogger()); const remoteAuthority = this._environmentService.configuration.remoteAuthority; @@ -505,14 +503,42 @@ export class ExtensionService extends AbstractExtensionService implements IExten // remove disabled extensions remoteEnv.extensions = remove(remoteEnv.extensions, extension => this._isDisabled(extension)); + // Determine where each extension will execute, based on extensionKind + const isInstalledLocally = new Set(); + localExtensions.forEach(ext => isInstalledLocally.add(ExtensionIdentifier.toKey(ext.identifier))); + + const isInstalledRemotely = new Set(); + remoteEnv.extensions.forEach(ext => isInstalledRemotely.add(ExtensionIdentifier.toKey(ext.identifier))); + + const enum RunningLocation { None, Local, Remote } + const pickRunningLocation = (extension: IExtensionDescription): RunningLocation => { + for (const extensionKind of getExtensionKind(extension, this._productService, this._configurationService)) { + if (extensionKind === 'ui') { + // a ui extension can run on both sides for now... + if (isInstalledLocally.has(ExtensionIdentifier.toKey(extension.identifier))) { + return RunningLocation.Local; + } + if (isInstalledRemotely.has(ExtensionIdentifier.toKey(extension.identifier))) { + return RunningLocation.Remote; + } + } else if (extensionKind === 'workspace') { + if (isInstalledRemotely.has(ExtensionIdentifier.toKey(extension.identifier))) { + return RunningLocation.Remote; + } + } + } + return RunningLocation.None; + }; + + const runningLocation = new Map(); + localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext))); + remoteEnv.extensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext))); + // remove non-UI extensions from the local extensions - localExtensions = remove(localExtensions, extension => !extension.isBuiltin && !isUIExtension(extension)); + localExtensions = localExtensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === RunningLocation.Local); // in case of UI extensions overlap, the local extension wins - remoteEnv.extensions = remove(remoteEnv.extensions, localExtensions.filter(extension => isUIExtension(extension))); - - // in case of other extensions overlap, the remote extension wins - localExtensions = remove(localExtensions, remoteEnv.extensions); + remoteEnv.extensions = remoteEnv.extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === RunningLocation.Remote); // save for remote extension's init data this._remoteExtensionsEnvironmentData.set(remoteAuthority, remoteEnv); @@ -537,22 +563,20 @@ export class ExtensionService extends AbstractExtensionService implements IExten this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions()); } - public getInspectPort(): number { + public async getInspectPort(tryEnableInspector: boolean): Promise { if (this._extensionHostProcessManagers.length > 0) { - return this._extensionHostProcessManagers[0].getInspectPort(); + return this._extensionHostProcessManagers[0].getInspectPort(tryEnableInspector); } return 0; } public _onExtensionHostExit(code: number): void { - // Expected development extension termination: When the extension host goes down we also shutdown the window - if (!this._isExtensionDevTestFromCli) { - this._electronService.closeWindow(); - } - - // When CLI testing make sure to exit with proper exit code - else { + if (this._isExtensionDevTestFromCli) { + // When CLI testing make sure to exit with proper exit code ipc.send('vscode:exit', code); + } else { + // Expected development extension termination: When the extension host goes down we also shutdown the window + this._electronService.closeWindow(); } } } diff --git a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts index 7a83c73e05c..01d77a89124 100644 --- a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts +++ b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts @@ -11,7 +11,7 @@ import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common 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 { prefersExecuteOnUI } 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'; @@ -116,7 +116,7 @@ export class RemoteExtensionManagementChannelClient extends ExtensionManagementC 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) { + if (manifest && prefersExecuteOnUI(manifest, this.productService, this.configurationService) === uiExtension) { result.set(extension.identifier.id.toLowerCase(), extension); extensionsManifests.push(manifest); } diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index 9f5a14f6cb0..9955c682758 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -222,7 +222,7 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise { unhandledPromises.splice(idx, 1); console.warn(`rejected promise not handled within 1 second: ${e}`); - if (e.stack) { + if (e && e.stack) { console.warn(`stack trace: ${e.stack}`); } onUnexpectedError(reason); @@ -275,20 +275,6 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise { const protocol = await createExtHostProtocol(); diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index 4d08f7645a0..9961f497f49 100644 --- a/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -51,7 +51,7 @@ class ExtensionManifestParser extends ExtensionManifestHandler { return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => { const errors: json.ParseError[] = []; const manifest = json.parse(manifestContents.toString(), errors); - if (errors.length === 0) { + if (errors.length === 0 && json.getNodeType(manifest) === 'object') { if (manifest.__metadata) { manifest.uuid = manifest.__metadata.id; } @@ -104,6 +104,9 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { this._log.error(this._absoluteFolderPath, nls.localize('jsonsParseReportErrors', "Failed to parse {0}: {1}.", localized, getParseErrorMessage(error.error))); }); }; + const reportInvalidFormat = (localized: string | null): void => { + this._log.error(this._absoluteFolderPath, nls.localize('jsonInvalidFormat', "Invalid format {0}: JSON object expected.", localized)); + }; let extension = path.extname(this._absoluteManifestPath); let basename = this._absoluteManifestPath.substr(0, this._absoluteManifestPath.length - extension.length); @@ -118,6 +121,9 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { if (errors.length > 0) { reportErrors(translationPath, errors); return { values: undefined, default: `${basename}.nls.json` }; + } else if (json.getNodeType(translationBundle) !== 'object') { + reportInvalidFormat(translationPath); + return { values: undefined, default: `${basename}.nls.json` }; } else { let values = translationBundle.contents ? translationBundle.contents.package : undefined; return { values: values, default: `${basename}.nls.json` }; @@ -140,6 +146,9 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { if (errors.length > 0) { reportErrors(messageBundle.localized, errors); return { values: undefined, default: messageBundle.original }; + } else if (json.getNodeType(messages) !== 'object') { + reportInvalidFormat(messageBundle.localized); + return { values: undefined, default: messageBundle.original }; } return { values: messages, default: messageBundle.original }; }, (err) => { @@ -161,6 +170,9 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { if (errors.length > 0) { reportErrors(localizedMessages.default, errors); return extensionDescription; + } else if (json.getNodeType(localizedMessages) !== 'object') { + reportInvalidFormat(localizedMessages.default); + return extensionDescription; } const localized = localizedMessages.values || Object.create(null); ExtensionManifestNLSReplacer._replaceNLStrings(this._nlsConfig, extensionDescription, localized, defaults, this._log, this._absoluteFolderPath); diff --git a/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts b/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts index 6e0669eb0d2..404e8b259f6 100644 --- a/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts +++ b/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts @@ -187,4 +187,28 @@ suite('RPCProtocol', () => { done(null); }); }); + + test('issue #72798: null errors are hard to digest', function (done) { + delegate = (a1: number, a2: number) => { + throw { 'what': 'what' }; + }; + bProxy.$m(4, 1).then((res) => { + assert.fail('unexpected'); + done(null); + }, (err) => { + assert.equal(err.what, 'what'); + done(null); + }); + }); + + test('undefined arguments arrive as null', function () { + delegate = (a1: any, a2: any) => { + assert.equal(typeof a1, 'undefined'); + assert.equal(a2, null); + return 7; + }; + return bProxy.$m(undefined, null).then((res) => { + assert.equal(res, 7); + }); + }); }); diff --git a/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts index 3b5706ce76a..748960c515e 100644 --- a/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts +++ b/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts @@ -35,9 +35,6 @@ self.postMessage = () => console.trace(`'postMessage' has been blocked`); const nativeAddEventLister = addEventListener.bind(self); self.addEventLister = () => console.trace(`'addEventListener' has been blocked`); -self.indexedDB.open = () => console.trace(`'indexedDB.open' has been blocked`); -self.caches.open = () => console.trace(`'indexedDB.caches' has been blocked`); - //#endregion --- const hostUtil = new class implements IHostUtils { diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index c70804f0568..2851a78df2b 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -7,7 +7,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IEditor } from 'vs/editor/common/editorCommon'; import { ITextEditorOptions, IResourceInput, ITextEditorSelection } from 'vs/platform/editor/common/editor'; -import { IEditorInput, IEditor as IBaseEditor, Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorInputFactoryRegistry, toResource, Extensions as EditorInputExtensions, IFileInputFactory, IEditorIdentifier } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditor as IBaseEditor, Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorInputFactoryRegistry, toResource, IEditorIdentifier } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { FileChangesEvent, IFileService, FileChangeType, FILES_EXCLUDE_CONFIG } from 'vs/platform/files/common/files'; @@ -19,7 +19,6 @@ 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 { 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'; @@ -33,6 +32,7 @@ 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'; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; /** * Stores the selection & view state of an editor and allows to compare it to other selection states. @@ -59,7 +59,7 @@ export class TextEditorState { } justifiesNewPushState(other: TextEditorState, event?: ICursorPositionChangedEvent): boolean { - if (event && event.source === 'api') { + if (event?.source === 'api') { return true; // always let API source win (e.g. "Go to definition" should add a history entry) } @@ -120,13 +120,11 @@ export class HistoryService extends Disposable implements IHistoryService { private lastEditLocation: IStackEntry | undefined; - private history!: Array; + private history: Array = []; private recentlyClosedFiles: IRecentlyClosedFile[]; private loaded: boolean; private resourceFilter: ResourceGlobMatcher; - private fileInputFactory: IFileInputFactory; - private canNavigateBackContextKey: IContextKey; private canNavigateForwardContextKey: IContextKey; private canNavigateToLastEditLocationContextKey: IContextKey; @@ -138,7 +136,7 @@ export class HistoryService extends Disposable implements IHistoryService { @IStorageService private readonly storageService: IStorageService, @IConfigurationService private readonly configurationService: IConfigurationService, @IFileService private readonly fileService: IFileService, - @IWindowService private readonly windowService: IWindowService, + @IWorkspacesService private readonly workspacesService: IWorkspacesService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @@ -149,8 +147,6 @@ export class HistoryService extends Disposable implements IHistoryService { this.canNavigateForwardContextKey = (new RawContextKey('canNavigateForward', false)).bindTo(this.contextKeyService); this.canNavigateToLastEditLocationContextKey = (new RawContextKey('canNavigateToLastEditLocation', false)).bindTo(this.contextKeyService); - this.fileInputFactory = Registry.as(EditorInputExtensions.EditorInputFactories).getFileInputFactory(); - this.index = -1; this.lastIndex = -1; this.stack = []; @@ -227,7 +223,7 @@ export class HistoryService extends Disposable implements IHistoryService { } // Remember as last active editor (can be undefined if none opened) - this.lastActiveEditor = activeControl && activeControl.input && activeControl.group ? { editor: activeControl.input, groupId: activeControl.group.id } : undefined; + this.lastActiveEditor = activeControl?.input && activeControl.group ? { editor: activeControl.input, groupId: activeControl.group.id } : undefined; // Dispose old listeners this.activeEditorListeners.clear(); @@ -250,7 +246,11 @@ export class HistoryService extends Disposable implements IHistoryService { // 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.add(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 => { + if (activeEditor) { + this.rememberLastEditLocation(activeEditor, activeTextEditorWidget); + } + }))); } } @@ -482,7 +482,7 @@ export class HistoryService extends Disposable implements IHistoryService { } private handleEditorEventInHistory(editor?: IBaseEditor): void { - const input = editor ? editor.input : undefined; + const input = editor?.input; // Ensure we have at least a name to show and not configured to exclude input if (!input || !input.getName() || !this.include(input)) { @@ -592,7 +592,7 @@ export class HistoryService extends Disposable implements IHistoryService { // stack but we need to keep our currentTextEditorState up to date with // the navigtion that occurs. if (this.navigatingInStack) { - if (codeEditor && control && control.input) { + if (codeEditor && control?.input) { this.currentTextEditorState = new TextEditorState(control.input, codeEditor.getSelection()); } else { this.currentTextEditorState = null; // we navigated to a non text editor @@ -603,7 +603,7 @@ export class HistoryService extends Disposable implements IHistoryService { else { // navigation inside text editor - if (codeEditor && control && control.input) { + if (codeEditor && control?.input) { this.handleTextEditorEvent(control, codeEditor, event); } @@ -611,7 +611,7 @@ export class HistoryService extends Disposable implements IHistoryService { else { this.currentTextEditorState = null; // at this time we have no active text editor view state - if (control && control.input) { + if (control?.input) { this.handleNonTextEditorEvent(control); } } @@ -734,8 +734,9 @@ export class HistoryService extends Disposable implements IHistoryService { } private preferResourceInput(input: IEditorInput): IEditorInput | IResourceInput { - if (this.fileInputFactory.isFileInput(input)) { - return { resource: input.getResource() }; + const resource = input.getResource(); + if (resource && this.fileService.canHandleResource(resource)) { + return { resource: resource }; } return input; @@ -781,7 +782,7 @@ export class HistoryService extends Disposable implements IHistoryService { const input = arg1 as IResourceInput; - this.windowService.removeFromRecentlyOpened([input.resource]); + this.workspacesService.removeFromRecentlyOpened([input.resource]); } private isFileOpened(resource: URI, group: IEditorGroup): boolean { @@ -845,7 +846,7 @@ export class HistoryService extends Disposable implements IHistoryService { const resourceInput = arg2 as IResourceInput; - return resourceInput && resourceInput.resource.toString() === resource.toString(); + return resourceInput?.resource.toString() === resource.toString(); } getHistory(): Array { @@ -924,7 +925,7 @@ export class HistoryService extends Disposable implements IHistoryService { // Editor input: via factory const { editorInputJSON } = serializedEditorHistoryEntry; - if (editorInputJSON && editorInputJSON.deserialized) { + if (editorInputJSON?.deserialized) { const factory = registry.getEditorInputFactory(editorInputJSON.typeId); if (factory) { const input = factory.deserialize(this.instantiationService, editorInputJSON.deserialized); @@ -996,7 +997,7 @@ export class HistoryService extends Disposable implements IHistoryService { resource = (input as IResourceInput).resource; } - if (resource && resource.scheme === filterByScheme) { + if (resource?.scheme === filterByScheme) { return resource; } } diff --git a/src/vs/workbench/services/host/browser/browserHostService.ts b/src/vs/workbench/services/host/browser/browserHostService.ts index 1d3cdcf65f2..4ed69ee646b 100644 --- a/src/vs/workbench/services/host/browser/browserHostService.ts +++ b/src/vs/workbench/services/host/browser/browserHostService.ts @@ -3,60 +3,126 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Event } from 'vs/base/common/event'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IResourceEditor, IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWindowSettings, IWindowOpenable, IOpenInWindowOptions, isFolderToOpen, isWorkspaceToOpen, isFileToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, isFileToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; import { pathsToEditors } from 'vs/workbench/common/editor'; import { IFileService } from 'vs/platform/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; +import { trackFocus } from 'vs/base/browser/dom'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -export class BrowserHostService implements IHostService { +/** + * A workspace to open in the workbench can either be: + * - a workspace file with 0-N folders (via `workspaceUri`) + * - a single folder (via `folderUri`) + * - empty (via `undefined`) + */ +export type IWorkspace = { workspaceUri: URI } | { folderUri: URI } | undefined; + +export interface IWorkspaceProvider { + + /** + * The initial workspace to open. + */ + readonly workspace: IWorkspace; + + /** + * Arbitrary payload from the `IWorkspaceProvider.open` call. + */ + readonly payload?: object; + + /** + * Asks to open a workspace in the current or a new window. + * + * @param workspace the workspace to open. + * @param options optional options for the workspace to open. + * - `reuse`: wether to open inside the current window or a new window + * - `payload`: arbitrary payload that should be made available + * to the opening window via the `IWorkspaceProvider.payload` property. + */ + open(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): Promise; +} + +export class BrowserHostService extends Disposable implements IHostService { _serviceBrand: undefined; + private workspaceProvider: IWorkspaceProvider; + constructor( @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IEditorService private readonly editorService: IEditorService, @IConfigurationService private readonly configurationService: IConfigurationService, @IFileService private readonly fileService: IFileService, - @ILabelService private readonly labelService: ILabelService - ) { } + @ILabelService private readonly labelService: ILabelService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService + ) { + super(); - //#region Window + if (environmentService.options && environmentService.options.workspaceProvider) { + this.workspaceProvider = environmentService.options.workspaceProvider; + } else { + this.workspaceProvider = new class implements IWorkspaceProvider { + readonly workspace = undefined; + async open() { } + }; + } + } - readonly windowCount = Promise.resolve(1); + private _onDidChangeFocus: Event | undefined; + get onDidChangeFocus(): Event { + if (!this._onDidChangeFocus) { + const focusTracker = this._register(trackFocus(window)); + this._onDidChangeFocus = Event.any( + Event.map(focusTracker.onDidFocus, () => this.hasFocus), + Event.map(focusTracker.onDidBlur, () => this.hasFocus) + ); + } - async openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise { - // TODO@Ben delegate to embedder - const { openFolderInNewWindow } = this.shouldOpenNewWindow(options); + return this._onDidChangeFocus; + } + + get hasFocus(): boolean { + return document.hasFocus(); + } + + async focus(): Promise { + window.focus(); + } + + openWindow(options?: IOpenEmptyWindowOptions): Promise; + openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; + openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { + if (Array.isArray(arg1)) { + return this.doOpenWindow(arg1, arg2); + } + + return this.doOpenEmptyWindow(arg1); + } + + private async doOpenWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise { for (let i = 0; i < toOpen.length; i++) { const openable = toOpen[i]; openable.label = openable.label || this.getRecentLabel(openable); // Folder if (isFolderToOpen(openable)) { - const newAddress = `${document.location.origin}${document.location.pathname}?folder=${openable.folderUri.path}`; - if (openFolderInNewWindow) { - window.open(newAddress); - } else { - window.location.href = newAddress; - } + this.workspaceProvider.open({ folderUri: openable.folderUri }, { reuse: this.shouldReuse(options) }); } // Workspace else if (isWorkspaceToOpen(openable)) { - const newAddress = `${document.location.origin}${document.location.pathname}?workspace=${openable.workspaceUri.path}`; - if (openFolderInNewWindow) { - window.open(newAddress); - } else { - window.location.href = newAddress; - } + this.workspaceProvider.open({ workspaceUri: openable.workspaceUri }, { reuse: this.shouldReuse(options) }); } - // File + // File: open via editor service in current window else if (isFileToOpen(openable)) { const inputs: IResourceEditor[] = await pathsToEditors([openable], this.fileService); this.editorService.openEditors(inputs); @@ -76,26 +142,20 @@ export class BrowserHostService implements IHostService { return this.labelService.getUriLabel(openable.fileUri); } - private shouldOpenNewWindow(options: IOpenInWindowOptions = {}): { openFolderInNewWindow: boolean } { + private shouldReuse(options: IOpenWindowOptions = {}): boolean { const windowConfig = this.configurationService.getValue('window'); - const openFolderInNewWindowConfig = (windowConfig && windowConfig.openFoldersInNewWindow) || 'default' /* default */; + const openFolderInNewWindowConfig = windowConfig?.openFoldersInNewWindow || 'default' /* default */; let openFolderInNewWindow = !!options.forceNewWindow && !options.forceReuseWindow; if (!options.forceNewWindow && !options.forceReuseWindow && (openFolderInNewWindowConfig === 'on' || openFolderInNewWindowConfig === 'off')) { openFolderInNewWindow = (openFolderInNewWindowConfig === 'on'); } - return { openFolderInNewWindow }; + return !openFolderInNewWindow; } - async openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { - // TODO@Ben delegate to embedder - const targetHref = `${document.location.origin}${document.location.pathname}?ew=true`; - if (options && options.reuse) { - window.location.href = targetHref; - } else { - window.open(targetHref); - } + private async doOpenEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { + this.workspaceProvider.open(undefined, { reuse: options?.forceReuseWindow }); } async toggleFullScreen(): Promise { @@ -132,12 +192,6 @@ export class BrowserHostService implements IHostService { } } - async focus(): Promise { - window.focus(); - } - - //#endregion - async restart(): Promise { this.reload(); } @@ -145,10 +199,6 @@ export class BrowserHostService implements IHostService { async reload(): Promise { window.location.reload(); } - - async closeWorkspace(): Promise { - return this.openEmptyWindow({ reuse: true }); - } } registerSingleton(IHostService, BrowserHostService, true); diff --git a/src/vs/workbench/services/host/browser/host.ts b/src/vs/workbench/services/host/browser/host.ts index c10c9a08c13..f97c8048de2 100644 --- a/src/vs/workbench/services/host/browser/host.ts +++ b/src/vs/workbench/services/host/browser/host.ts @@ -3,8 +3,9 @@ * 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 { IWindowOpenable, IOpenInWindowOptions, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable, IOpenWindowOptions, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; export const IHostService = createDecorator('hostService'); @@ -12,28 +13,17 @@ export interface IHostService { _serviceBrand: undefined; - //#region Window + //#region Focus /** - * The number of windows that belong to the current client session. + * Emitted when the window focus changes. */ - readonly windowCount: Promise; + readonly onDidChangeFocus: Event; /** - * Opens the provided array of openables in a window with the provided options. + * Find out if the window has focus or not. */ - openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise; - - /** - * Opens an empty window. The optional parameter allows to define if - * a new window should open or the existing one change to an empty. - */ - openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise; - - /** - * Switch between fullscreen and normal window. - */ - toggleFullScreen(): Promise; + readonly hasFocus: boolean; /** * Attempt to bring the window to the foreground and focus it. @@ -42,6 +32,28 @@ export interface IHostService { //#endregion + + //#region Window + + /** + * Opens an empty window. The optional parameter allows to define if + * a new window should open or the existing one change to an empty. + */ + openWindow(options?: IOpenEmptyWindowOptions): Promise; + + /** + * Opens the provided array of openables in a window with the provided options. + */ + openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; + + /** + * Switch between fullscreen and normal window. + */ + toggleFullScreen(): Promise; + + //#endregion + + //#region Lifecycle /** @@ -54,11 +66,5 @@ export interface IHostService { */ reload(): Promise; - /** - * Closes the currently opened folder/workspace and returns to an empty - * window. - */ - closeWorkspace(): Promise; - //#endregion } diff --git a/src/vs/workbench/services/host/electron-browser/desktopHostService.ts b/src/vs/workbench/services/host/electron-browser/desktopHostService.ts index 3f59e6662a1..17d415d16b7 100644 --- a/src/vs/workbench/services/host/electron-browser/desktopHostService.ts +++ b/src/vs/workbench/services/host/electron-browser/desktopHostService.ts @@ -3,33 +3,64 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Event } from 'vs/base/common/event'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IWindowOpenable, IOpenInWindowOptions, isFolderToOpen, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; -export class DesktopHostService implements IHostService { +export class DesktopHostService extends Disposable implements IHostService { _serviceBrand: undefined; constructor( @IElectronService private readonly electronService: IElectronService, @ILabelService private readonly labelService: ILabelService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { } + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService + ) { + super(); - //#region Window + // Resolve initial window focus state + this._hasFocus = document.hasFocus(); + electronService.isWindowFocused().then(focused => this._hasFocus = focused); - get windowCount(): Promise { return this.electronService.getWindowCount(); } + this.registerListeners(); + } - openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise { + private registerListeners(): void { + this._register(this.onDidChangeFocus(focus => this._hasFocus = focus)); + } + + get onDidChangeFocus(): Event { return this._onDidChangeFocus; } + private _onDidChangeFocus: Event = Event.any( + Event.map(Event.filter(this.electronService.onWindowFocus, id => id === this.electronEnvironmentService.windowId), _ => true), + Event.map(Event.filter(this.electronService.onWindowBlur, id => id === this.electronEnvironmentService.windowId), _ => false) + ); + + private _hasFocus: boolean; + get hasFocus(): boolean { return this._hasFocus; } + + openWindow(options?: IOpenEmptyWindowOptions): Promise; + openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; + openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { + if (Array.isArray(arg1)) { + return this.doOpenWindow(arg1, arg2); + } + + return this.doOpenEmptyWindow(arg1); + } + + private doOpenWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise { if (!!this.environmentService.configuration.remoteAuthority) { toOpen.forEach(openable => openable.label = openable.label || this.getRecentLabel(openable)); } - return this.electronService.openInWindow(toOpen, options); + return this.electronService.openWindow(toOpen, options); } private getRecentLabel(openable: IWindowOpenable): string { @@ -44,8 +75,8 @@ export class DesktopHostService implements IHostService { return this.labelService.getUriLabel(openable.fileUri); } - openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { - return this.electronService.openEmptyWindow(options); + private doOpenEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { + return this.electronService.openWindow(options); } toggleFullScreen(): Promise { @@ -56,8 +87,6 @@ export class DesktopHostService implements IHostService { return this.electronService.focusWindow(); } - //#endregion - restart(): Promise { return this.electronService.relaunch(); } @@ -65,10 +94,6 @@ export class DesktopHostService implements IHostService { reload(): Promise { return this.electronService.reload(); } - - closeWorkspace(): Promise { - return this.electronService.closeWorkpsace(); - } } registerSingleton(IHostService, DesktopHostService, true); diff --git a/src/vs/workbench/services/integrity/node/integrityService.ts b/src/vs/workbench/services/integrity/node/integrityService.ts index 127f8011b66..2a749defaac 100644 --- a/src/vs/workbench/services/integrity/node/integrityService.ts +++ b/src/vs/workbench/services/integrity/node/integrityService.ts @@ -82,7 +82,7 @@ export class IntegrityServiceImpl implements IIntegrityService { private _prompt(): void { const storedData = this._storage.get(); - if (storedData && storedData.dontShowPrompt && storedData.commit === product.commit) { + if (storedData?.dontShowPrompt && storedData.commit === product.commit) { return; // Do not prompt } diff --git a/src/vs/platform/issue/electron-browser/issueService.ts b/src/vs/workbench/services/issue/electron-browser/issueService.ts similarity index 69% rename from src/vs/platform/issue/electron-browser/issueService.ts rename to src/vs/workbench/services/issue/electron-browser/issueService.ts index 72502019070..0143cff6f3e 100644 --- a/src/vs/platform/issue/electron-browser/issueService.ts +++ b/src/vs/workbench/services/issue/electron-browser/issueService.ts @@ -5,13 +5,16 @@ import { IIssueService } from 'vs/platform/issue/node/issue'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy'; +import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class IssueService { _serviceBrand: undefined; constructor(@IMainProcessService mainProcessService: IMainProcessService) { - return createSimpleChannelProxy(mainProcessService.getChannel('issue')); + return createChannelSender(mainProcessService.getChannel('issue')); } } + +registerSingleton(IIssueService, IssueService, true); diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 1a2b8e01abd..1f64cf308c8 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -29,7 +29,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; 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 { IHostService } from 'vs/workbench/services/host/browser/host'; 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'; @@ -154,7 +154,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { @INotificationService notificationService: INotificationService, @IEnvironmentService environmentService: IEnvironmentService, @IConfigurationService configurationService: IConfigurationService, - @IWindowService private readonly windowService: IWindowService, + @IHostService private readonly hostService: IHostService, @IExtensionService extensionService: IExtensionService, @IFileService fileService: IFileService, @IKeymapService private readonly keymapService: IKeymapService @@ -291,7 +291,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { // 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; + return this.hostService.hasFocus; } private _resolveKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { diff --git a/src/vs/workbench/services/keybinding/browser/keymapService.ts b/src/vs/workbench/services/keybinding/browser/keymapService.ts index 988fd218f35..755e240d88e 100644 --- a/src/vs/workbench/services/keybinding/browser/keymapService.ts +++ b/src/vs/workbench/services/keybinding/browser/keymapService.ts @@ -19,7 +19,7 @@ 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 { parse, getNodeType } 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'; @@ -482,9 +482,13 @@ class UserKeyboardLayout extends Disposable { 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); + if (getNodeType(value) === 'object') { + const layoutInfo = value.layout; + const mappings = value.rawMapping; + this._keyboardLayout = KeymapInfo.createKeyboardLayoutFromDebugInfo(layoutInfo, mappings, true); + } else { + this._keyboardLayout = null; + } } catch (e) { this._keyboardLayout = null; } diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index a267b3a2634..8e6059322b1 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -250,7 +250,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding private parse(model: ITextModel): { result: IUserFriendlyKeybinding[], parseErrors: json.ParseError[] } { const parseErrors: json.ParseError[] = []; - const result = json.parse(model.getValue(), parseErrors); + const result = json.parse(model.getValue(), parseErrors, { allowEmptyContent: true }); return { result, parseErrors }; } 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 ef234672a77..92cb4333d15 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 @@ -19,7 +19,6 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; @@ -47,13 +46,14 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro import { URI } from 'vs/base/common/uri'; import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; -import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -class TestEnvironmentService extends WorkbenchEnvironmentService { +class TestEnvironmentService extends NativeWorkbenchEnvironmentService { constructor(private _appSettingsHome: URI) { - super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); + super(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath, 0); } get appSettingsHome() { return this._appSettingsHome; } @@ -81,11 +81,12 @@ suite('KeybindingsEditing', () => { instantiationService = new TestInstantiationService(); const environmentService = new TestEnvironmentService(URI.file(testDir)); + + const configService = new TestConfigurationService(); + configService.setUserConfiguration('files', { 'eol': '\n' }); + instantiationService.stub(IEnvironmentService, environmentService); - instantiationService.stub(IConfigurationService, ConfigurationService); - instantiationService.stub(IConfigurationService, 'getValue', { 'eol': '\n' }); - instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', () => { }); - instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', () => { }); + instantiationService.stub(IConfigurationService, configService); instantiationService.stub(IWorkspaceContextService, new TestContextService()); const lifecycleService = new TestLifecycleService(); instantiationService.stub(ILifecycleService, lifecycleService); diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index a5934abc85d..5bee2e89049 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -12,11 +12,10 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWo import { Registry } from 'vs/platform/registry/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace'; -import { isEqual, basenameOrAuthority, isEqualOrParent, basename, joinPath, dirname } from 'vs/base/common/resources'; -import { isWindows } from 'vs/base/common/platform'; +import { isEqual, basenameOrAuthority, basename, joinPath, dirname } from 'vs/base/common/resources'; import { tildify, getPathLabel } from 'vs/base/common/labels'; import { ltrim, endsWith } from 'vs/base/common/strings'; -import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier, isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting } from 'vs/platform/label/common/label'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { match } from 'vs/base/common/glob'; @@ -71,7 +70,7 @@ const sepRegexp = /\//g; const labelMatchingRegexp = /\$\{(scheme|authority|path|(query)\.(.+?))\}/g; function hasDriveLetter(path: string): boolean { - return !!(isWindows && path && path[2] === ':'); + return !!(path && path[2] === ':'); } class ResourceLabelFormattersHandler implements IWorkbenchContribution { @@ -194,7 +193,7 @@ export class LabelService implements ILabelService { if (isWorkspaceIdentifier(workspace)) { // Workspace: Untitled - if (isEqualOrParent(workspace.configPath, this.environmentService.untitledWorkspacesHome)) { + if (isUntitledWorkspace(workspace.configPath, this.environmentService)) { return localize('untitledWorkspace', "Untitled (Workspace)"); } diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index c17ec465ac6..616d872bf57 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -31,11 +31,6 @@ export interface IWorkbenchLayoutService extends ILayoutService { _serviceBrand: undefined; - /** - * Emits when the visibility of the title bar changes. - */ - readonly onTitleBarVisibilityChange: Event; - /** * Emits when the zen mode is enabled or disabled. */ @@ -56,6 +51,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ readonly onPanelPositionChange: Event; + /** + * Emit when part visibility changes + */ + readonly onPartVisibilityChange: Event; + /** * Asks the part service if all parts have been fully restored. For editor part * this means that the contents of editors have loaded. @@ -70,7 +70,7 @@ export interface IWorkbenchLayoutService extends ILayoutService { /** * Returns the parts HTML element, if there is one. */ - getContainer(part: Parts): HTMLElement; + getContainer(part: Parts): HTMLElement | undefined; /** * Returns if the part is visible. @@ -80,7 +80,7 @@ export interface IWorkbenchLayoutService extends ILayoutService { /** * Returns if the part is visible. */ - getDimension(part: Parts): Dimension; + getDimension(part: Parts): Dimension | undefined; /** * Set activity bar hidden or not @@ -114,6 +114,16 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ toggleMaximizedPanel(): void; + /** + * Returns true if the window has a border. + */ + hasWindowBorder(): boolean; + + /** + * Returns the window border radius if any. + */ + getWindowBorderRadius(): string | undefined; + /** * Returns true if the panel is maximized. */ diff --git a/src/vs/platform/lifecycle/browser/lifecycleService.ts b/src/vs/workbench/services/lifecycle/browser/lifecycleService.ts similarity index 89% rename from src/vs/platform/lifecycle/browser/lifecycleService.ts rename to src/vs/workbench/services/lifecycle/browser/lifecycleService.ts index 22ed39ba7ab..41e6b4e34c4 100644 --- a/src/vs/platform/lifecycle/browser/lifecycleService.ts +++ b/src/vs/workbench/services/lifecycle/browser/lifecycleService.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; import { localize } from 'vs/nls'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class BrowserLifecycleService extends AbstractLifecycleService { @@ -61,3 +62,5 @@ export class BrowserLifecycleService extends AbstractLifecycleService { return null; } } + +registerSingleton(ILifecycleService, BrowserLifecycleService); diff --git a/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts similarity index 80% rename from src/vs/platform/lifecycle/electron-browser/lifecycleService.ts rename to src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts index 8505d978cd6..8a859f0d230 100644 --- a/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts +++ b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts @@ -4,16 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { ShutdownReason, StartupKind, handleVetos } from 'vs/platform/lifecycle/common/lifecycle'; +import { ShutdownReason, StartupKind, handleVetos, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage'; import { ipcRenderer as ipc } from 'electron'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { onUnexpectedError } from 'vs/base/common/errors'; import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -export class LifecycleService extends AbstractLifecycleService { +export class NativeLifecycleService extends AbstractLifecycleService { private static readonly LAST_SHUTDOWN_REASON_KEY = 'lifecyle.lastShutdownReason'; @@ -23,7 +24,7 @@ export class LifecycleService extends AbstractLifecycleService { constructor( @INotificationService private readonly notificationService: INotificationService, - @IWindowService private readonly windowService: IWindowService, + @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService, @IStorageService readonly storageService: IStorageService, @ILogService readonly logService: ILogService ) { @@ -35,8 +36,8 @@ export class LifecycleService extends AbstractLifecycleService { } private resolveStartupKind(): StartupKind { - const lastShutdownReason = this.storageService.getNumber(LifecycleService.LAST_SHUTDOWN_REASON_KEY, StorageScope.WORKSPACE); - this.storageService.remove(LifecycleService.LAST_SHUTDOWN_REASON_KEY, StorageScope.WORKSPACE); + const lastShutdownReason = this.storageService.getNumber(NativeLifecycleService.LAST_SHUTDOWN_REASON_KEY, StorageScope.WORKSPACE); + this.storageService.remove(NativeLifecycleService.LAST_SHUTDOWN_REASON_KEY, StorageScope.WORKSPACE); let startupKind: StartupKind; if (lastShutdownReason === ShutdownReason.RELOAD) { @@ -53,7 +54,7 @@ export class LifecycleService extends AbstractLifecycleService { } private registerListeners(): void { - const windowId = this.windowService.windowId; + const windowId = this.electronEnvironmentService.windowId; // Main side indicates that window is about to unload, check for vetos ipc.on('vscode:onBeforeUnload', (_event: unknown, reply: { okChannel: string, cancelChannel: string, reason: ShutdownReason }) => { @@ -91,7 +92,7 @@ export class LifecycleService extends AbstractLifecycleService { // Save shutdown reason to retrieve on next startup this.storageService.onWillSaveState(e => { if (e.reason === WillSaveStateReason.SHUTDOWN) { - this.storageService.store(LifecycleService.LAST_SHUTDOWN_REASON_KEY, this.shutdownReason, StorageScope.WORKSPACE); + this.storageService.store(NativeLifecycleService.LAST_SHUTDOWN_REASON_KEY, this.shutdownReason, StorageScope.WORKSPACE); } }); } @@ -132,3 +133,5 @@ export class LifecycleService extends AbstractLifecycleService { } } } + +registerSingleton(ILifecycleService, NativeLifecycleService); diff --git a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts new file mode 100644 index 00000000000..99394090da8 --- /dev/null +++ b/src/vs/workbench/services/localizations/electron-browser/localizationsService.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 { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; +import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +export class LocalizationsService { + + _serviceBrand: undefined; + + constructor( + @ISharedProcessService sharedProcessService: ISharedProcessService, + ) { + return createChannelSender(sharedProcessService.getChannel('localizations')); + } +} + +registerSingleton(ILocalizationsService, LocalizationsService, true); diff --git a/src/vs/workbench/services/log/common/keyValueLogProvider.ts b/src/vs/workbench/services/log/common/keyValueLogProvider.ts index 8bcdb579c75..0db6b00da32 100644 --- a/src/vs/workbench/services/log/common/keyValueLogProvider.ts +++ b/src/vs/workbench/services/log/common/keyValueLogProvider.ts @@ -17,8 +17,8 @@ export abstract class KeyValueLogProvider extends Disposable implements IFileSys readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.FileReadWrite; readonly onDidChangeCapabilities: Event = Event.None; - private readonly _onDidChangeFile: Emitter = this._register(new Emitter()); - readonly onDidChangeFile: Event = this._onDidChangeFile.event; + private readonly _onDidChangeFile = this._register(new Emitter()); + readonly onDidChangeFile: Event = this._onDidChangeFile.event; private readonly versions: Map = new Map(); diff --git a/src/vs/platform/menubar/electron-browser/menubarService.ts b/src/vs/workbench/services/menubar/electron-browser/menubarService.ts similarity index 68% rename from src/vs/platform/menubar/electron-browser/menubarService.ts rename to src/vs/workbench/services/menubar/electron-browser/menubarService.ts index 4a537c4e6c4..9e4efbada0e 100644 --- a/src/vs/platform/menubar/electron-browser/menubarService.ts +++ b/src/vs/workbench/services/menubar/electron-browser/menubarService.ts @@ -5,13 +5,16 @@ import { IMenubarService } from 'vs/platform/menubar/node/menubar'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy'; +import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class MenubarService { _serviceBrand: undefined; constructor(@IMainProcessService mainProcessService: IMainProcessService) { - return createSimpleChannelProxy(mainProcessService.getChannel('menubar')); + return createChannelSender(mainProcessService.getChannel('menubar')); } } + +registerSingleton(IMenubarService, MenubarService, true); diff --git a/src/vs/workbench/services/mode/common/workbenchModeService.ts b/src/vs/workbench/services/mode/common/workbenchModeService.ts index 0813403571a..f097879bc0d 100644 --- a/src/vs/workbench/services/mode/common/workbenchModeService.ts +++ b/src/vs/workbench/services/mode/common/workbenchModeService.ts @@ -173,7 +173,7 @@ export class WorkbenchModeServiceImpl extends ModeServiceImpl { mime.clearTextMimes(true /* user configured */); // Register based on settings - if (configuration.files && configuration.files.associations) { + if (configuration.files?.associations) { Object.keys(configuration.files.associations).forEach(pattern => { const langId = configuration.files.associations[pattern]; const mimetype = this.getMimeForMode(langId) || `text/x-${langId}`; diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index 552e4e9fc51..80a451c1589 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions, IStatusMessageOptions, NoOpNotification, NeverShowAgainScope } from 'vs/platform/notification/common/notification'; +import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions, IStatusMessageOptions, NoOpNotification, NeverShowAgainScope, NotificationsFilter } from 'vs/platform/notification/common/notification'; import { INotificationsModel, NotificationsModel, ChoiceAction } from 'vs/workbench/common/notifications'; import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; @@ -17,15 +17,16 @@ export class NotificationService extends Disposable implements INotificationServ _serviceBrand: undefined; private _model: INotificationsModel = this._register(new NotificationsModel()); - - get model(): INotificationsModel { - return this._model; - } + get model(): INotificationsModel { return this._model; } constructor(@IStorageService private readonly storageService: IStorageService) { super(); } + setFilter(filter: NotificationsFilter): void { + this._model.setFilter(filter); + } + info(message: NotificationMessage | NotificationMessage[]): void { if (Array.isArray(message)) { message.forEach(m => this.info(m)); @@ -109,7 +110,7 @@ export class NotificationService extends Disposable implements INotificationServ const toDispose = new DisposableStore(); // Handle neverShowAgain option accordingly - if (options && options.neverShowAgain) { + if (options?.neverShowAgain) { const scope = options.neverShowAgain.scope === NeverShowAgainScope.WORKSPACE ? StorageScope.WORKSPACE : StorageScope.GLOBAL; // If the user already picked to not show the notification @@ -162,7 +163,7 @@ export class NotificationService extends Disposable implements INotificationServ // 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 }); + handle = this.notify({ severity, message, actions, sticky: options?.sticky, silent: options?.silent }); Event.once(handle.onDidClose)(() => { diff --git a/src/vs/workbench/services/output/common/outputChannelModel.ts b/src/vs/workbench/services/output/common/outputChannelModel.ts index f3a8ec8ad94..2eade61f069 100644 --- a/src/vs/workbench/services/output/common/outputChannelModel.ts +++ b/src/vs/workbench/services/output/common/outputChannelModel.ts @@ -365,7 +365,7 @@ export class BufferredOutputChannel extends Disposable implements IOutputChannel class BufferedContent { - private static MAX_OUTPUT_LENGTH = 10000 /* Max. number of output lines to show in output */ * 100 /* Guestimated chars per line */; + private static readonly MAX_OUTPUT_LENGTH = 10000 /* Max. number of output lines to show in output */ * 100 /* Guestimated chars per line */; private data: string[] = []; private dataIds: number[] = []; diff --git a/src/vs/workbench/services/output/node/outputChannelModelService.ts b/src/vs/workbench/services/output/electron-browser/outputChannelModelService.ts similarity index 96% rename from src/vs/workbench/services/output/node/outputChannelModelService.ts rename to src/vs/workbench/services/output/electron-browser/outputChannelModelService.ts index 6e3c6e3e905..db944a5df6a 100644 --- a/src/vs/workbench/services/output/node/outputChannelModelService.ts +++ b/src/vs/workbench/services/output/electron-browser/outputChannelModelService.ts @@ -21,6 +21,7 @@ import { toLocalISOString } from 'vs/base/common/date'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Emitter, Event } from 'vs/base/common/event'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; class OutputChannelBackedByFile extends AbstractFileOutputChannelModel implements IOutputChannelModel { @@ -203,6 +204,7 @@ export class OutputChannelModelService extends AsbtractOutputChannelModelService constructor( @IInstantiationService instantiationService: IInstantiationService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService, @IFileService private readonly fileService: IFileService ) { super(instantiationService); @@ -216,7 +218,7 @@ export class OutputChannelModelService extends AsbtractOutputChannelModelService private _outputDir: Promise | null = null; private get outputDir(): Promise { if (!this._outputDir) { - const outputDir = URI.file(join(this.environmentService.logsPath, `output_${this.environmentService.configuration.windowId}_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`)); + const outputDir = URI.file(join(this.environmentService.logsPath, `output_${this.electronEnvironmentService.windowId}_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`)); this._outputDir = this.fileService.createFolder(outputDir).then(() => outputDir); } return this._outputDir; diff --git a/src/vs/workbench/services/panel/common/panelService.ts b/src/vs/workbench/services/panel/common/panelService.ts index d686236e30a..ef626afef88 100644 --- a/src/vs/workbench/services/panel/common/panelService.ts +++ b/src/vs/workbench/services/panel/common/panelService.ts @@ -22,18 +22,18 @@ export interface IPanelService { _serviceBrand: undefined; - readonly onDidPanelOpen: Event<{ panel: IPanel, focus: boolean }>; + readonly onDidPanelOpen: Event<{ readonly panel: IPanel, readonly focus: boolean }>; readonly onDidPanelClose: Event; /** * Opens a panel with the given identifier and pass keyboard focus to it if specified. */ - openPanel(id: string, focus?: boolean): IPanel | null; + openPanel(id: string, focus?: boolean): IPanel | undefined; /** * Returns the current active panel or null if none */ - getActivePanel(): IPanel | null; + getActivePanel(): IPanel | undefined; /** * Returns the panel by id. @@ -43,17 +43,17 @@ export interface IPanelService { /** * Returns all built-in panels following the default order */ - getPanels(): IPanelIdentifier[]; + getPanels(): readonly IPanelIdentifier[]; /** * Returns pinned panels following the visual order */ - getPinnedPanels(): IPanelIdentifier[]; + getPinnedPanels(): readonly IPanelIdentifier[]; /** * Returns the progress indicator for the panel bar. */ - getProgressIndicator(id: string): IProgressIndicator | null; + getProgressIndicator(id: string): IProgressIndicator | undefined; /** * Show an activity in a panel. diff --git a/src/vs/workbench/services/path/common/remotePathService.ts b/src/vs/workbench/services/path/common/remotePathService.ts new file mode 100644 index 00000000000..fa6b20e9c5c --- /dev/null +++ b/src/vs/workbench/services/path/common/remotePathService.ts @@ -0,0 +1,81 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'vs/base/common/path'; +import * as platform from 'vs/base/common/platform'; +import { URI } from 'vs/base/common/uri'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; + +const REMOTE_PATH_SERVICE_ID = 'remotePath'; +export const IRemotePathService = createDecorator(REMOTE_PATH_SERVICE_ID); + +export interface IRemotePathService { + _serviceBrand: undefined; + + path: Promise; + fileURI(path: string): Promise; +} + +/** + * Provides the correct IPath implementation for dealing with paths that refer to locations in the extension host + */ +export class RemotePathService implements IRemotePathService { + _serviceBrand: undefined; + + private _extHostOS: Promise; + + constructor( + @IRemoteAgentService readonly remoteAgentService: IRemoteAgentService + ) { + this._extHostOS = remoteAgentService.getEnvironment().then(remoteEnvironment => { + return remoteEnvironment ? remoteEnvironment.os : platform.OS; + }); + } + + get path(): Promise { + return this._extHostOS.then(os => { + return os === platform.OperatingSystem.Windows ? + path.win32 : + path.posix; + }); + } + + async fileURI(_path: string): Promise { + let authority = ''; + + // normalize to fwd-slashes on windows, + // on other systems bwd-slashes are valid + // filename character, eg /f\oo/ba\r.txt + if ((await this._extHostOS) === platform.OperatingSystem.Windows) { + _path = _path.replace(/\\/g, '/'); + } + + // check for authority as used in UNC shares + // or use the path as given + if (_path[0] === '/' && _path[1] === '/') { + const idx = _path.indexOf('/', 2); + if (idx === -1) { + authority = _path.substring(2); + _path = '/'; + } else { + authority = _path.substring(2, idx); + _path = _path.substring(idx) || '/'; + } + } + + // return new _URI('file', authority, path, '', ''); + return URI.from({ + scheme: 'file', + authority, + path: _path, + query: '', + fragment: '' + }); + } +} + +registerSingleton(IRemotePathService, RemotePathService, true); diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index cbde207476f..db55635c1f9 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -51,11 +51,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic private readonly _onDispose = this._register(new Emitter()); private _defaultUserSettingsUriCounter = 0; - private _defaultUserSettingsContentModel: DefaultSettings; + private _defaultUserSettingsContentModel: DefaultSettings | undefined; private _defaultWorkspaceSettingsUriCounter = 0; - private _defaultWorkspaceSettingsContentModel: DefaultSettings; + private _defaultWorkspaceSettingsContentModel: DefaultSettings | undefined; private _defaultFolderSettingsUriCounter = 0; - private _defaultFolderSettingsContentModel: DefaultSettings; + private _defaultFolderSettingsContentModel: DefaultSettings | undefined; constructor( @IEditorService private readonly editorService: IEditorService, diff --git a/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts b/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts index 39a4fca36bc..362555816ad 100644 --- a/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts +++ b/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts @@ -80,6 +80,8 @@ export class KeybindingsEditorModel extends EditorModel { @IKeybindingService private readonly keybindingsService: IKeybindingService ) { super(); + this._keybindingItems = []; + this._keybindingItemsSortedByPrecedence = []; this.modifierLabels = { ui: UILabelProvider.modifierLabels[os], aria: AriaLabelProvider.modifierLabels[os], diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index e0f621a144a..59dcd697acf 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -429,7 +429,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, export class WorkspaceConfigurationEditorModel extends SettingsEditorModel { - private _configurationGroups: ISettingsGroup[]; + private _configurationGroups: ISettingsGroup[] = []; get configurationGroups(): ISettingsGroup[] { return this._configurationGroups; @@ -448,9 +448,9 @@ export class WorkspaceConfigurationEditorModel extends SettingsEditorModel { export class DefaultSettings extends Disposable { - private _allSettingsGroups: ISettingsGroup[]; - private _content: string; - private _settingsByName: Map; + private _allSettingsGroups: ISettingsGroup[] | undefined; + private _content: string | undefined; + private _settingsByName = new Map(); readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; @@ -467,7 +467,7 @@ export class DefaultSettings extends Disposable { this.initialize(); } - return this._content; + return this._content!; } getSettingsGroups(forceUpdate = false): ISettingsGroup[] { @@ -475,7 +475,7 @@ export class DefaultSettings extends Disposable { this.initialize(); } - return this._allSettingsGroups; + return this._allSettingsGroups!; } private initialize(): void { @@ -1249,7 +1249,7 @@ export function defaultKeybindingsContents(keybindingService: IKeybindingService export class DefaultKeybindingsEditorModel implements IKeybindingsEditorModel { - private _content: string; + private _content: string | undefined; constructor(private _uri: URI, @IKeybindingService private readonly keybindingService: IKeybindingService) { diff --git a/src/vs/workbench/services/progress/browser/media/progressService.css b/src/vs/workbench/services/progress/browser/media/progressService.css index e9d6a1574e8..4cf8a37994b 100644 --- a/src/vs/workbench/services/progress/browser/media/progressService.css +++ b/src/vs/workbench/services/progress/browser/media/progressService.css @@ -11,8 +11,14 @@ 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; +.monaco-workbench .progress-badge > .badge-content::before { + mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMiAyIDE0IDE0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDIgMiAxNCAxNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTZjLTMuODYgMC03LTMuMTQtNy03czMuMTQtNyA3LTdjMy44NTkgMCA3IDMuMTQxIDcgN3MtMy4xNDEgNy03IDd6bTAtMTIuNmMtMy4wODggMC01LjYgMi41MTMtNS42IDUuNnMyLjUxMiA1LjYgNS42IDUuNiA1LjYtMi41MTIgNS42LTUuNi0yLjUxMi01LjYtNS42LTUuNnptMy44NiA3LjFsLTMuMTYtMS44OTZ2LTMuODA0aC0xLjR2NC41OTZsMy44NCAyLjMwNS43Mi0xLjIwMXoiLz48L3N2Zz4="); + -webkit-mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMiAyIDE0IDE0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDIgMiAxNCAxNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTZjLTMuODYgMC03LTMuMTQtNy03czMuMTQtNyA3LTdjMy44NTkgMCA3IDMuMTQxIDcgN3MtMy4xNDEgNy03IDd6bTAtMTIuNmMtMy4wODggMC01LjYgMi41MTMtNS42IDUuNnMyLjUxMiA1LjYgNS42IDUuNiA1LjYtMi41MTIgNS42LTUuNi0yLjUxMi01LjYtNS42LTUuNnptMy44NiA3LjFsLTMuMTYtMS44OTZ2LTMuODA0aC0xLjR2NC41OTZsMy44NCAyLjMwNS43Mi0xLjIwMXoiLz48L3N2Zz4="); + width: 14px; + height: 14px; + position: absolute; + top: 1px; + left: 1px; + background-color: currentColor; + content: ''; } diff --git a/src/vs/workbench/services/progress/browser/progressIndicator.ts b/src/vs/workbench/services/progress/browser/progressIndicator.ts index 1d11c084f7c..5d605ce2c08 100644 --- a/src/vs/workbench/services/progress/browser/progressIndicator.ts +++ b/src/vs/workbench/services/progress/browser/progressIndicator.ts @@ -8,11 +8,14 @@ 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'; +import { IProgressRunner, IProgressIndicator, emptyProgressRunner } from 'vs/platform/progress/common/progress'; +import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; -export class ProgressBarIndicator implements IProgressIndicator { +export class ProgressBarIndicator extends Disposable implements IProgressIndicator { - constructor(private progressbar: ProgressBar) { } + constructor(protected progressbar: ProgressBar) { + super(); + } show(infinite: true, delay?: number): IProgressRunner; show(total: number, delay?: number): IProgressRunner; @@ -55,6 +58,55 @@ export class ProgressBarIndicator implements IProgressIndicator { } } +export class EditorProgressIndicator extends ProgressBarIndicator { + + _serviceBrand: undefined; + + constructor(progressBar: ProgressBar, private readonly group: IEditorGroupView) { + super(progressBar); + + this.registerListeners(); + } + + private registerListeners() { + this._register(this.group.onDidCloseEditor(e => { + if (this.group.isEmpty) { + this.progressbar.stop().hide(); + } + })); + } + + show(infinite: true, delay?: number): IProgressRunner; + show(total: number, delay?: number): IProgressRunner; + show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { + + // No editor open: ignore any progress reporting + if (this.group.isEmpty) { + return emptyProgressRunner; + } + + if (infiniteOrTotal === true) { + return super.show(true, delay); + } + + return super.show(infiniteOrTotal, delay); + } + + async showWhile(promise: Promise, delay?: number): Promise { + + // No editor open: ignore any progress reporting + if (this.group.isEmpty) { + try { + await promise; + } catch (error) { + // ignore + } + } + + return super.showWhile(promise, delay); + } +} + namespace ProgressIndicatorState { export const enum Type { diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index 6c182f1993e..562773832a5 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -7,9 +7,9 @@ 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 { IProgressService, IProgressOptions, IProgressStep, ProgressLocation, IProgress, Progress, IProgressCompositeOptions, IProgressNotificationOptions, IProgressRunner, IProgressIndicator, IProgressWindowOptions } 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 { StatusbarAlignment, IStatusbarService } from 'vs/workbench/services/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'; @@ -45,7 +45,7 @@ export class ProgressService extends Disposable implements IProgressService { super(); } - withProgress(options: IProgressOptions, task: (progress: IProgress) => Promise, onDidCancel?: (choice?: number) => void): Promise { + async withProgress(options: IProgressOptions, task: (progress: IProgress) => Promise, onDidCancel?: (choice?: number) => void): Promise { const { location } = options; if (typeof location === 'string') { if (this.viewletService.getProgressIndicator(location)) { @@ -56,14 +56,14 @@ export class ProgressService extends Disposable implements IProgressService { return this.withPanelProgress(location, task, { ...options, location }); } - return Promise.reject(new Error(`Bad progress location: ${location}`)); + throw new Error(`Bad progress location: ${location}`); } switch (location) { case ProgressLocation.Notification: return this.withNotificationProgress({ ...options, location }, task, onDidCancel); case ProgressLocation.Window: - return this.withWindowProgress(options, task); + return this.withWindowProgress({ ...options, location }, task); case ProgressLocation.Explorer: return this.withViewletProgress('workbench.view.explorer', task, { ...options, location }); case ProgressLocation.Scm: @@ -73,12 +73,12 @@ export class ProgressService extends Disposable implements IProgressService { case ProgressLocation.Dialog: return this.withDialogProgress(options, task, onDidCancel); default: - return Promise.reject(new Error(`Bad progress location: ${location}`)); + throw new Error(`Bad progress location: ${location}`); } } - private withWindowProgress(options: IProgressOptions, callback: (progress: IProgress<{ message?: string }>) => Promise): Promise { - const task: [IProgressOptions, Progress] = [options, new Progress(() => this.updateWindowProgress())]; + private withWindowProgress(options: IProgressWindowOptions, callback: (progress: IProgress<{ message?: string }>) => Promise): Promise { + const task: [IProgressWindowOptions, Progress] = [options, new Progress(() => this.updateWindowProgress())]; const promise = callback(task[1]); @@ -110,6 +110,7 @@ export class ProgressService extends Disposable implements IProgressService { let progressTitle = options.title; let progressMessage = progress.value && progress.value.message; + let progressCommand = (options).command; let text: string; let title: string; @@ -136,7 +137,8 @@ export class ProgressService extends Disposable implements IProgressService { this.globalStatusEntry.value = this.statusbarService.addEntry({ text: `$(sync~spin) ${text}`, - tooltip: title + tooltip: title, + command: progressCommand }, 'status.progress', localize('status.progress', "Progress Message"), StatusbarAlignment.LEFT); } } @@ -308,7 +310,7 @@ export class ProgressService extends Disposable implements IProgressService { return this.withCompositeProgress(this.panelService.getProgressIndicator(panelid), task, options); } - private withCompositeProgress

, R = unknown>(progressIndicator: IProgressIndicator | null, task: (progress: IProgress) => P, options: IProgressCompositeOptions): P { + private withCompositeProgress

, R = unknown>(progressIndicator: IProgressIndicator | undefined, task: (progress: IProgress) => P, options: IProgressCompositeOptions): P { let progressRunner: IProgressRunner | undefined = undefined; const promise = task({ @@ -364,7 +366,7 @@ export class ProgressService extends Disposable implements IProgressService { cancelId: buttons.length - 1, keyEventProcessor: (event: StandardKeyboardEvent) => { const resolved = this.keybindingService.softDispatch(event, this.layoutService.container); - if (resolved && resolved.commandId) { + if (resolved?.commandId) { if (allowableCommands.indexOf(resolved.commandId) === -1) { EventHelper.stop(event, true); } diff --git a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts index c889524ee61..93008e7624b 100644 --- a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts @@ -21,6 +21,7 @@ import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics import { Emitter } from 'vs/base/common/event'; import { ISignService } from 'vs/platform/sign/common/sign'; import { ILogService } from 'vs/platform/log/common/log'; +import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; export abstract class AbstractRemoteAgentService extends Disposable { @@ -69,6 +70,26 @@ export abstract class AbstractRemoteAgentService extends Disposable { return Promise.resolve(undefined); } + + logTelemetry(eventName: string, data: ITelemetryData): Promise { + const connection = this.getConnection(); + if (connection) { + const client = new RemoteExtensionEnvironmentChannelClient(connection.getChannel('remoteextensionsenvironment')); + return client.logTelemetry(eventName, data); + } + + return Promise.resolve(undefined); + } + + flushTelemetry(): Promise { + const connection = this.getConnection(); + if (connection) { + const client = new RemoteExtensionEnvironmentChannelClient(connection.getChannel('remoteextensionsenvironment')); + return client.flushTelemetry(); + } + + return Promise.resolve(undefined); + } } export class RemoteAgentConnection extends Disposable implements IRemoteAgentConnection { diff --git a/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts b/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts index a1877e037aa..93a0c25a574 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts @@ -10,6 +10,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics'; import { RemoteAuthorities } from 'vs/base/common/network'; +import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; export interface IGetEnvironmentDataArguments { language: string; @@ -70,4 +71,12 @@ export class RemoteExtensionEnvironmentChannelClient { disableTelemetry(): Promise { return this.channel.call('disableTelemetry'); } + + logTelemetry(eventName: string, data: ITelemetryData): Promise { + return this.channel.call('logTelemetry', { eventName, data }); + } + + flushTelemetry(): Promise { + return this.channel.call('flushTelemetry'); + } } diff --git a/src/vs/workbench/services/remote/common/remoteAgentService.ts b/src/vs/workbench/services/remote/common/remoteAgentService.ts index 1cda189b53e..9200f1be530 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentService.ts @@ -9,6 +9,7 @@ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics'; import { Event } from 'vs/base/common/event'; import { PersistenConnectionEvent as PersistentConnectionEvent, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; +import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; export const RemoteExtensionLogFileName = 'remoteagent'; @@ -23,6 +24,8 @@ export interface IRemoteAgentService { getEnvironment(bail?: boolean): Promise; getDiagnosticInfo(options: IDiagnosticInfoOptions): Promise; disableTelemetry(): Promise; + logTelemetry(eventName: string, data?: ITelemetryData): Promise; + flushTelemetry(): Promise; } export interface IRemoteAgentConnection { diff --git a/src/vs/workbench/services/remote/node/tunnelService.ts b/src/vs/workbench/services/remote/node/tunnelService.ts index aedae50b120..62b872ac8c9 100644 --- a/src/vs/workbench/services/remote/node/tunnelService.ts +++ b/src/vs/workbench/services/remote/node/tunnelService.ts @@ -16,6 +16,7 @@ import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { ISignService } from 'vs/platform/sign/common/sign'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; +import { findFreePort } from 'vs/base/node/ports'; export async function createRemoteTunnel(options: IConnectionOptions, tunnelRemotePort: number): Promise { const tunnel = new NodeRemoteTunnel(options, tunnelRemotePort); @@ -25,7 +26,7 @@ export async function createRemoteTunnel(options: IConnectionOptions, tunnelRemo class NodeRemoteTunnel extends Disposable implements RemoteTunnel { public readonly tunnelRemotePort: number; - public readonly tunnelLocalPort: number; + public tunnelLocalPort!: number; private readonly _options: IConnectionOptions; private readonly _server: net.Server; @@ -47,7 +48,7 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel { this._server.on('connection', this._connectionListener); this.tunnelRemotePort = tunnelRemotePort; - this.tunnelLocalPort = (this._server.listen(0).address()).port; + } public dispose(): void { @@ -58,6 +59,13 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel { } public async waitForReady(): Promise { + + // try to get the same port number as the remote port number... + const localPort = await findFreePort(this.tunnelRemotePort, 1, 1000); + + // if that fails, the method above returns 0, which works out fine below... + this.tunnelLocalPort = (this._server.listen(localPort).address()).port; + await this._barrier.wait(); return this; } diff --git a/src/vs/workbench/services/search/common/replace.ts b/src/vs/workbench/services/search/common/replace.ts index 764873d247a..2bbbf1ffa58 100644 --- a/src/vs/workbench/services/search/common/replace.ts +++ b/src/vs/workbench/services/search/common/replace.ts @@ -61,9 +61,9 @@ export class ReplacePattern { if (match) { if (this.hasParameters) { if (match[0] === text) { - return text.replace(this._regExp, this.pattern); + return text.replace(this._regExp, this.buildReplaceString(match, preserveCase)); } - let replaceString = text.replace(this._regExp, this.pattern); + let replaceString = text.replace(this._regExp, this.buildReplaceString(match, preserveCase)); return replaceString.substr(match.index, match[0].length - (text.length - replaceString.length)); } return this.buildReplaceString(match, preserveCase); diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index 9c27a27edd0..b3853d663db 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -17,6 +17,7 @@ import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { Event } from 'vs/base/common/event'; import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions } from 'vs/workbench/common/views'; import { Registry } from 'vs/platform/registry/common/platform'; +import { relative } from 'vs/base/common/path'; export const VIEWLET_ID = 'workbench.view.search'; export const PANEL_ID = 'workbench.view.search'; @@ -371,7 +372,8 @@ export function pathIncludedInQuery(queryProps: ICommonQueryProps, fsPath: return !!queryProps.folderQueries && queryProps.folderQueries.every(fq => { const searchPath = fq.folder.fsPath; if (extpath.isEqualOrParent(fsPath, searchPath)) { - return !fq.includePattern || !!glob.match(fq.includePattern, fsPath); + const relPath = relative(searchPath, fsPath); + return !fq.includePattern || !!glob.match(fq.includePattern, relPath); } else { return false; } diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts index 554762af58b..e86530d9db7 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts @@ -79,15 +79,15 @@ export class RipgrepTextSearchEngine { cancel(); }); - rgProc.stdout.on('data', data => { + rgProc.stdout!.on('data', data => { ripgrepParser.handleData(data); }); let gotData = false; - rgProc.stdout.once('data', () => gotData = true); + rgProc.stdout!.once('data', () => gotData = true); let stderr = ''; - rgProc.stderr.on('data', data => { + rgProc.stderr!.on('data', data => { const message = data.toString(); this.outputChannel.appendLine(message); stderr += message; @@ -425,13 +425,14 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] args.push('--pcre2'); } - if (query.isRegExp) { - query.pattern = unicodeEscapesToPCRE2(query.pattern); - } - // Allow $ to match /r/n args.push('--crlf'); + if (query.isRegExp) { + query.pattern = unicodeEscapesToPCRE2(query.pattern); + args.push('--auto-hybrid-regex'); + } + let searchPatternAfterDoubleDashes: Maybe; if (query.isWordMatch) { const regexp = createRegExp(query.pattern, !!query.isRegExp, { wholeWord: query.isWordMatch }); @@ -441,7 +442,6 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] let fixedRegexpQuery = fixRegexNewline(query.pattern); fixedRegexpQuery = fixNewline(fixedRegexpQuery); args.push('--regexp', fixedRegexpQuery); - args.push('--auto-hybrid-regex'); } else { searchPatternAfterDoubleDashes = query.pattern; args.push('--fixed-strings'); diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index 9b00ee68b63..161dfdfc8d0 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -26,6 +26,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic 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 { parseSearchPort } from 'vs/platform/environment/node/environmentService'; export class LocalSearchService extends SearchService { constructor( @@ -42,7 +43,7 @@ export class LocalSearchService extends SearchService { super(modelService, untitledEditorService, editorService, telemetryService, logService, extensionService, fileService); - this.diskSearch = instantiationService.createInstance(DiskSearch, !environmentService.isBuilt || environmentService.verbose, environmentService.debugSearch); + this.diskSearch = instantiationService.createInstance(DiskSearch, !environmentService.isBuilt || environmentService.verbose, parseSearchPort(environmentService.args, environmentService.isBuilt)); } } diff --git a/src/vs/workbench/services/search/test/common/replace.test.ts b/src/vs/workbench/services/search/test/common/replace.test.ts index 47085ed1ec0..c43e0f3930e 100644 --- a/src/vs/workbench/services/search/test/common/replace.test.ts +++ b/src/vs/workbench/services/search/test/common/replace.test.ts @@ -214,5 +214,21 @@ suite('Replace Pattern test', () => { testObject = new ReplacePattern('$0ah', { pattern: 'b(la)(?=\\stext$)', isRegExp: true }); actual = testObject.getReplaceString('this is a bla text'); assert.equal('blaah', actual); + + testObject = new ReplacePattern('newrege$1', true, /Testrege(\w*)/); + actual = testObject.getReplaceString('Testregex', true); + assert.equal('Newregex', actual); + + testObject = new ReplacePattern('newrege$1', true, /TESTREGE(\w*)/); + actual = testObject.getReplaceString('TESTREGEX', true); + assert.equal('NEWREGEX', actual); + + testObject = new ReplacePattern('new_rege$1', true, /Test_Rege(\w*)/); + actual = testObject.getReplaceString('Test_Regex', true); + assert.equal('New_Regex', actual); + + testObject = new ReplacePattern('new-rege$1', true, /Test-Rege(\w*)/); + actual = testObject.getReplaceString('Test-Regex', true); + assert.equal('New-Regex', actual); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/services/sharedProcess/electron-browser/sharedProcessService.ts b/src/vs/workbench/services/sharedProcess/electron-browser/sharedProcessService.ts new file mode 100644 index 00000000000..8f1d6810a3d --- /dev/null +++ b/src/vs/workbench/services/sharedProcess/electron-browser/sharedProcessService.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 { Client } from 'vs/base/parts/ipc/common/ipc.net'; +import { connect } from 'vs/base/parts/ipc/node/ipc.net'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; +import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +export class SharedProcessService implements ISharedProcessService { + + _serviceBrand: undefined; + + private withSharedProcessConnection: Promise>; + private sharedProcessMainChannel: IChannel; + + constructor( + @IMainProcessService mainProcessService: IMainProcessService, + @IElectronEnvironmentService environmentService: IElectronEnvironmentService + ) { + this.sharedProcessMainChannel = mainProcessService.getChannel('sharedProcess'); + + this.withSharedProcessConnection = this.whenSharedProcessReady() + .then(() => connect(environmentService.sharedIPCHandle, `window:${environmentService.windowId}`)); + } + + whenSharedProcessReady(): Promise { + return this.sharedProcessMainChannel.call('whenSharedProcessReady'); + } + + getChannel(channelName: string): IChannel { + return getDelayedChannel(this.withSharedProcessConnection.then(connection => connection.getChannel(channelName))); + } + + registerChannel(channelName: string, channel: IServerChannel): void { + this.withSharedProcessConnection.then(connection => connection.registerChannel(channelName, channel)); + } + + toggleSharedProcessWindow(): Promise { + return this.sharedProcessMainChannel.call('toggleSharedProcessWindow'); + } +} + +registerSingleton(ISharedProcessService, SharedProcessService, true); diff --git a/src/vs/platform/statusbar/common/statusbar.ts b/src/vs/workbench/services/statusbar/common/statusbar.ts similarity index 97% rename from src/vs/platform/statusbar/common/statusbar.ts rename to src/vs/workbench/services/statusbar/common/statusbar.ts index 2c5ba10591c..3cf98b09753 100644 --- a/src/vs/platform/statusbar/common/statusbar.ts +++ b/src/vs/workbench/services/statusbar/common/statusbar.ts @@ -74,7 +74,7 @@ export interface IStatusbarService { addEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority?: number): IStatusbarEntryAccessor; /** - * Allows to update an entry's visibilty with the provided ID. + * Allows to update an entry's visibility with the provided ID. */ updateEntryVisibility(id: string, visible: boolean): void; } diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index a33b25a0e3a..646bd0beb72 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; -import { NullTelemetryService, combinedAppender, LogAppender, ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; +import { NullTelemetryService, combinedAppender, LogAppender, ITelemetryAppender } 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'; @@ -15,52 +15,19 @@ import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/pla import { IStorageService } from 'vs/platform/storage/common/storage'; import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/browser/workbenchCommonProperties'; import { IProductService } from 'vs/platform/product/common/productService'; -import { ApplicationInsights } from '@microsoft/applicationinsights-web'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; export class WebTelemetryAppender implements ITelemetryAppender { - private _aiClient?: ApplicationInsights; - 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 - } - }; - - this._aiClient = new ApplicationInsights(initConfig); - this._aiClient.loadAppInsights(); - } + constructor(private _logService: ILogService, private _appender: IRemoteAgentService) { } log(eventName: string, data: any): void { - if (!this._aiClient) { - return; - } - - data = validateTelemetryData(data); this._logService.trace(`telemetry/${eventName}`, data); - - this._aiClient.trackEvent({ - name: 'monacoworkbench/' + eventName, - properties: data.properties, - measurements: data.measurements - }); + this._appender.logTelemetry(eventName, data); } flush(): Promise { - if (this._aiClient) { - return new Promise(resolve => { - this._aiClient!.flush(); - this._aiClient = undefined; - resolve(undefined); - }); - } - - return Promise.resolve(); + return this._appender.flushTelemetry(); } } @@ -75,16 +42,15 @@ export class TelemetryService extends Disposable implements ITelemetryService { @ILogService logService: ILogService, @IConfigurationService configurationService: IConfigurationService, @IStorageService storageService: IStorageService, - @IProductService productService: IProductService + @IProductService productService: IProductService, + @IRemoteAgentService remoteAgentService: IRemoteAgentService ) { super(); - const aiKey = productService.aiConfig && productService.aiConfig.asimovKey; - if (!environmentService.isExtensionDevelopment && !environmentService.args['disable-telemetry'] && !!productService.enableTelemetry && !!aiKey) { + if (!!productService.enableTelemetry) { 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] + appender: combinedAppender(new WebTelemetryAppender(logService, remoteAgentService), new LogAppender(logService)), + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.remoteAuthority, environmentService.options && environmentService.options.resolveCommonTelemetryProperties) }; this.impl = this._register(new BaseTelemetryService(config, configurationService)); diff --git a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts index 84fac20658e..c2900691c8e 100644 --- a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts @@ -38,7 +38,7 @@ 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, productService.msftInternalDomains, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId!, productService.msftInternalDomains, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), piiPaths: environmentService.extensionsPath ? [environmentService.appRoot, environmentService.extensionsPath] : [environmentService.appRoot] }; diff --git a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts index 0fb7101230f..cb553b6fcc8 100644 --- a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts +++ b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts @@ -16,7 +16,6 @@ import { IState, ITokenizationSupport, LanguageId, TokenMetadata, TokenizationRe 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'; @@ -29,6 +28,7 @@ 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'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; export abstract class AbstractTextMateService extends Disposable implements ITextMateService { public _serviceBrand: undefined; @@ -48,7 +48,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex constructor( @IModeService private readonly _modeService: IModeService, @IWorkbenchThemeService private readonly _themeService: IWorkbenchThemeService, - @IFileService protected readonly _fileService: IFileService, + @IExtensionResourceLoaderService protected readonly _extensionResourceLoaderService: IExtensionResourceLoaderService, @INotificationService private readonly _notificationService: INotificationService, @ILogService private readonly _logService: ILogService, @IConfigurationService private readonly _configurationService: IConfigurationService, @@ -191,10 +191,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex 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(); - } + readFile: (resource: URI) => this._extensionResourceLoaderService.readExtensionResource(resource) }, this._grammarDefinitions || [], vscodeTextmate, this._loadOnigLib()); this._onDidCreateGrammarFactory(this._grammarDefinitions || []); diff --git a/src/vs/workbench/services/textMate/browser/textMateService.ts b/src/vs/workbench/services/textMate/browser/textMateService.ts index 8fb8d84099c..9c644998d00 100644 --- a/src/vs/workbench/services/textMate/browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/browser/textMateService.ts @@ -8,25 +8,25 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService'; import { IOnigLib } from 'vscode-textmate'; 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'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; export class TextMateService extends AbstractTextMateService { constructor( @IModeService modeService: IModeService, @IWorkbenchThemeService themeService: IWorkbenchThemeService, - @IFileService fileService: IFileService, + @IExtensionResourceLoaderService extensionResourceLoaderService: IExtensionResourceLoaderService, @INotificationService notificationService: INotificationService, @ILogService logService: ILogService, @IConfigurationService configurationService: IConfigurationService, @IStorageService storageService: IStorageService ) { - super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService); + super(modeService, themeService, extensionResourceLoaderService, notificationService, logService, configurationService, storageService); } protected _loadVSCodeTextmate(): Promise { diff --git a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts index dc35917e961..6a4a4d4d2e2 100644 --- a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts @@ -8,7 +8,6 @@ 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 { INotificationService } from 'vs/platform/notification/common/notification'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -24,6 +23,7 @@ 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'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; const RUN_TEXTMATE_IN_WORKER = false; @@ -117,14 +117,13 @@ export class TextMateWorkerHost { constructor( private readonly textMateService: TextMateService, - @IFileService private readonly _fileService: IFileService + @IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService, ) { } async readFile(_resource: UriComponents): Promise { const resource = URI.revive(_resource); - const content = await this._fileService.readFile(resource); - return content.value.toString(); + return this._extensionResourceLoaderService.readExtensionResource(resource); } async setTokens(_resource: UriComponents, versionId: number, tokens: Uint8Array): Promise { @@ -142,14 +141,14 @@ export class TextMateService extends AbstractTextMateService { constructor( @IModeService modeService: IModeService, @IWorkbenchThemeService themeService: IWorkbenchThemeService, - @IFileService fileService: IFileService, + @IExtensionResourceLoaderService extensionResourceLoaderService: IExtensionResourceLoaderService, @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); + super(modeService, themeService, extensionResourceLoaderService, notificationService, logService, configurationService, storageService); this._worker = null; this._workerProxy = null; this._tokenizers = Object.create(null); @@ -190,7 +189,7 @@ export class TextMateService extends AbstractTextMateService { this._killWorker(); if (RUN_TEXTMATE_IN_WORKER) { - const workerHost = new TextMateWorkerHost(this, this._fileService); + const workerHost = new TextMateWorkerHost(this, this._extensionResourceLoaderService); const worker = createWebWorker(this._modelService, { createData: { grammarDefinitions diff --git a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts index 4cdfa523db0..faf8c4f881a 100644 --- a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts +++ b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts @@ -44,7 +44,7 @@ export class BrowserTextFileService extends AbstractTextFileService { if (this.fileService.canHandleResource(dirtyResource)) { const model = this.models.get(dirtyResource); - hasBackup = !!(model && model.hasBackup()); + hasBackup = !!(model?.hasBackup()); } else if (dirtyResource.scheme === Schemas.untitled) { hasBackup = this.untitledEditorService.hasBackup(dirtyResource); } @@ -57,6 +57,10 @@ export class BrowserTextFileService extends AbstractTextFileService { return false; // dirty with backups: no veto } + + protected async getWindowCount(): Promise { + return 1; // Browser only ever is 1 window + } } registerSingleton(ITextFileService, BrowserTextFileService); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 81b109727be..dd23e60c1c5 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -5,16 +5,15 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import * as errors from 'vs/base/common/errors'; import * as objects from 'vs/base/common/objects'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Event, Emitter, AsyncEmitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, IWillMoveEvent, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; +import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions } from 'vs/platform/files/common/files'; +import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -39,7 +38,6 @@ 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'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -54,8 +52,13 @@ export abstract class AbstractTextFileService extends Disposable implements ITex private readonly _onFilesAssociationChange: Emitter = this._register(new Emitter()); readonly onFilesAssociationChange: Event = this._onFilesAssociationChange.event; - private readonly _onWillMove = this._register(new Emitter()); - readonly onWillMove: Event = this._onWillMove.event; + + private _onWillRunOperation = this._register(new AsyncEmitter()); + readonly onWillRunOperation = this._onWillRunOperation.event; + + private _onDidRunOperation = this._register(new Emitter()); + readonly onDidRunOperation = this._onDidRunOperation.event; + private _models: TextFileEditorModelManager; get models(): ITextFileEditorModelManager { return this._models; } @@ -74,14 +77,13 @@ export abstract class AbstractTextFileService extends Disposable implements ITex @IFileService protected readonly fileService: IFileService, @IUntitledEditorService protected readonly untitledEditorService: IUntitledEditorService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IInstantiationService protected instantiationService: IInstantiationService, + @IInstantiationService protected readonly instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService, @IModeService private readonly modeService: IModeService, @IModelService private readonly modelService: IModelService, @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService, @INotificationService private readonly notificationService: INotificationService, @IBackupFileService private readonly backupFileService: IBackupFileService, - @IHostService private readonly hostService: IHostService, @IHistoryService private readonly historyService: IHistoryService, @IContextKeyService contextKeyService: IContextKeyService, @IDialogService private readonly dialogService: IDialogService, @@ -95,7 +97,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); const configuration = configurationService.getValue(); - this.currentFilesAssociationConfig = configuration && configuration.files && configuration.files.associations; + this.currentFilesAssociationConfig = configuration?.files?.associations; this.onFilesConfigurationChange(configuration); @@ -180,7 +182,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex case ShutdownReason.CLOSE: if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured - } else if (await this.hostService.windowCount > 1 || platform.isMacintosh) { + } else if (await this.getWindowCount() > 1 || platform.isMacintosh) { doBackup = false; // do not backup if a window is closed that does not cause quitting of the application } else { doBackup = true; // backup if last window is closed on win/linux where the application quits right after @@ -213,6 +215,8 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return true; } + protected abstract getWindowCount(): Promise; + private backupAll(dirtyToBackup: URI[]): Promise { // split up between files and untitled @@ -298,11 +302,11 @@ export abstract class AbstractTextFileService extends Disposable implements ITex protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); - const autoSaveMode = (configuration && configuration.files && configuration.files.autoSave) || AutoSaveConfiguration.OFF; + const autoSaveMode = configuration?.files?.autoSave || AutoSaveConfiguration.OFF; this.autoSaveContext.set(autoSaveMode); switch (autoSaveMode) { case AutoSaveConfiguration.AFTER_DELAY: - this.configuredAutoSaveDelay = configuration && configuration.files && configuration.files.autoSaveDelay; + this.configuredAutoSaveDelay = configuration?.files?.autoSaveDelay; this.configuredAutoSaveOnFocusChange = false; this.configuredAutoSaveOnWindowChange = false; break; @@ -335,14 +339,14 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } // Check for change in files associations - const filesAssociation = configuration && configuration.files && configuration.files.associations; + const filesAssociation = configuration?.files?.associations; if (!objects.equals(this.currentFilesAssociationConfig, filesAssociation)) { this.currentFilesAssociationConfig = filesAssociation; this._onFilesAssociationChange.fire(); } // Hot exit - const hotExitMode = configuration && configuration.files && configuration.files.hotExit; + const hotExitMode = configuration?.files?.hotExit; if (hotExitMode === HotExitConfiguration.OFF || hotExitMode === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { this.configuredHotExit = hotExitMode; } else { @@ -389,7 +393,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return { ...stream, encoding: 'utf8', - value: await createTextBufferFactoryFromStream(stream.value, undefined, options && options.acceptTextOnly ? throwOnBinary : undefined) + value: await createTextBufferFactoryFromStream(stream.value, undefined, options?.acceptTextOnly ? throwOnBinary : undefined) }; } @@ -409,6 +413,10 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } async create(resource: URI, value?: string | ITextSnapshot, options?: ICreateFileOptions): Promise { + + // before event + await this._onWillRunOperation.fireAsync(promises => new FileOperationWillRunEvent(promises, FileOperation.CREATE, resource)); + const stat = await this.doCreate(resource, value, options); // If we had an existing model for the given resource, load @@ -420,6 +428,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex await existingModel.revert(); } + // after event + this._onDidRunOperation.fire(new FileOperationDidRunEvent(FileOperation.CREATE, resource)); + return stat; } @@ -432,17 +443,20 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } async delete(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise { - const dirtyFiles = this.getDirty().filter(dirty => isEqualOrParent(dirty, resource)); + await this._onWillRunOperation.fireAsync(promises => new FileOperationWillRunEvent(promises, FileOperation.DELETE, resource)); + + const dirtyFiles = this.getDirty().filter(dirty => isEqualOrParent(dirty, resource)); await this.revertAll(dirtyFiles, { soft: true }); - return this.fileService.del(resource, options); + await this.fileService.del(resource, options); + this._onDidRunOperation.fire(new FileOperationDidRunEvent(FileOperation.DELETE, resource)); } async move(source: URI, target: URI, overwrite?: boolean): Promise { - // await onWillMove event joiners - await this.notifyOnWillMove(source, target); + // before events + await this._onWillRunOperation.fireAsync(promises => new FileOperationWillRunEvent(promises, FileOperation.MOVE, target, source)); // find all models that related to either source or target (can be many if resource is a folder) const sourceModels: ITextFileEditorModel[] = []; @@ -521,27 +535,12 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } })); + // after event + this._onDidRunOperation.fire(new FileOperationDidRunEvent(FileOperation.MOVE, target, source)); + return stat; } - private async notifyOnWillMove(source: URI, target: URI): Promise { - const waitForPromises: Promise[] = []; - - // fire event - this._onWillMove.fire({ - oldResource: source, - newResource: target, - waitUntil(promise: Promise) { - waitForPromises.push(promise.then(undefined, errors.onUnexpectedError)); - } - }); - - // prevent async waitUntil-calls - Object.freeze(waitForPromises); - - await Promise.all(waitForPromises); - } - //#endregion //#region save/revert @@ -549,7 +548,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex async save(resource: URI, options?: ISaveOptions): Promise { // Run a forced save if we detect the file is not dirty so that save participants can still run - if (options && options.force && this.fileService.canHandleResource(resource) && !this.isDirty(resource)) { + if (options?.force && this.fileService.canHandleResource(resource) && !this.isDirty(resource)) { const model = this._models.get(resource); if (model) { options.reason = SaveReason.EXPLICIT; @@ -567,15 +566,14 @@ export abstract class AbstractTextFileService extends Disposable implements ITex async confirmSave(resources?: URI[]): Promise { if (this.environmentService.isExtensionDevelopment) { - if (!this.environmentService.args['extension-development-confirm-save']) { - return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume 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); if (resourcesToConfirm.length === 0) { return ConfirmResult.DONT_SAVE; } + return promptSave(this.dialogService, resourcesToConfirm); } @@ -660,7 +658,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return result; } - protected async promptForPath(resource: URI, defaultUri: URI, availableFileSystems?: string[]): Promise { + protected async promptForPath(resource: URI, defaultUri: URI, availableFileSystems?: readonly string[]): Promise { // Help user to find a name for the file by opening it first await this.editorService.openEditor({ resource, options: { revealIfOpened: true, preserveFocus: true } }); @@ -668,7 +666,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return this.fileDialogService.pickFileToSave(this.getSaveDialogOptions(defaultUri, availableFileSystems)); } - private getSaveDialogOptions(defaultUri: URI, availableFileSystems?: string[]): ISaveDialogOptions { + private getSaveDialogOptions(defaultUri: URI, availableFileSystems?: readonly string[]): ISaveDialogOptions { const options: ISaveDialogOptions = { defaultUri, title: nls.localize('saveAsTitle', "Save As"), @@ -835,7 +833,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // Prefer an existing model if it is already loaded for the given target resource let targetExists: boolean = false; let targetModel = this.models.get(target); - if (targetModel && targetModel.isResolved()) { + if (targetModel?.isResolved()) { targetExists = true; } @@ -938,7 +936,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } private async doRevertAllFiles(resources?: URI[], options?: IRevertOptions): Promise { - const fileModels = options && options.force ? this.getFileModels(resources) : this.getDirtyFileModels(resources); + const fileModels = options?.force ? this.getFileModels(resources) : this.getDirtyFileModels(resources); const mapResourceToResult = new ResourceMap(); fileModels.forEach(m => { @@ -949,7 +947,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex await Promise.all(fileModels.map(async model => { try { - await model.revert(options && options.soft); + await model.revert(options?.soft); if (!model.isDirty()) { const result = mapResourceToResult.get(model.getResource()); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index bd6332610d8..5cfaec6676b 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -8,7 +8,7 @@ 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 } from 'vs/base/common/types'; +import { isUndefinedOrNull, assertIsDefined } 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'; @@ -75,40 +75,34 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private readonly _onDidStateChange: Emitter = this._register(new Emitter()); readonly onDidStateChange: Event = this._onDidStateChange.event; - private resource: URI; + private contentEncoding: string | undefined; // encoding as reported from disk - private contentEncoding: string; // encoding as reported from disk - private preferredEncoding: string; // encoding as chosen by the user + private versionId = 0; + private bufferSavedVersionId: number | undefined; + private blockModelContentChange = false; - private preferredMode: string; // mode as chosen by the user + private lastResolvedFileStat: IFileStatWithMetadata | undefined; - private versionId: number; - private bufferSavedVersionId: number; - private blockModelContentChange: boolean; - - private lastResolvedFileStat: IFileStatWithMetadata; - - private autoSaveAfterMillies?: number; - private autoSaveAfterMilliesEnabled: boolean; + private autoSaveAfterMillies: number | undefined; + private autoSaveAfterMilliesEnabled: boolean | undefined; private readonly autoSaveDisposable = this._register(new MutableDisposable()); - private saveSequentializer: SaveSequentializer; - private lastSaveAttemptTime: number; + private readonly saveSequentializer = new SaveSequentializer(); + private lastSaveAttemptTime = 0; - private contentChangeEventScheduler: RunOnceScheduler; - private orphanedChangeEventScheduler: RunOnceScheduler; + private readonly contentChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidContentChange.fire(StateChange.CONTENT_CHANGE), TextFileEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY)); + private readonly orphanedChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidStateChange.fire(StateChange.ORPHANED_CHANGE), TextFileEditorModel.DEFAULT_ORPHANED_CHANGE_BUFFER_DELAY)); - private dirty: boolean; - private inConflictMode: boolean; - private inOrphanMode: boolean; - private inErrorMode: boolean; - - private disposed: boolean; + private dirty = false; + private inConflictMode = false; + private inOrphanMode = false; + private inErrorMode = false; + private disposed = false; constructor( - resource: URI, - preferredEncoding: string, - preferredMode: string, + private readonly resource: URI, + private preferredEncoding: string | undefined, // encoding as chosen by the user + private preferredMode: string | undefined, // mode as chosen by the user @INotificationService private readonly notificationService: INotificationService, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @@ -123,18 +117,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ) { super(modelService, modeService); - this.resource = resource; - this.preferredEncoding = preferredEncoding; - this.preferredMode = preferredMode; - this.inOrphanMode = false; - this.dirty = false; - this.versionId = 0; - this.lastSaveAttemptTime = 0; - this.saveSequentializer = new SaveSequentializer(); - - this.contentChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidContentChange.fire(StateChange.CONTENT_CHANGE), TextFileEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY)); - this.orphanedChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidStateChange.fire(StateChange.ORPHANED_CHANGE), TextFileEditorModel.DEFAULT_ORPHANED_CHANGE_BUFFER_DELAY)); - this.updateAutoSaveConfiguration(textFileService.getAutoSaveConfiguration()); this.registerListeners(); @@ -347,8 +329,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private async loadFromFile(options?: ILoadOptions): Promise { - const forceReadFromDisk = options && options.forceReadFromDisk; - const allowBinary = this.isResolved() /* always allow if we resolved previously */ || (options && options.allowBinary); + const forceReadFromDisk = options?.forceReadFromDisk; + const allowBinary = this.isResolved() /* always allow if we resolved previously */ || options?.allowBinary; // Decide on etag let etag: string | undefined; @@ -454,7 +436,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } else { type FileGetClassification = {} & FileTelemetryDataFragment; - this.telemetryService.publicLog2('fileGet', this.getTelemetryData(options && options.reason ? options.reason : LoadReason.OTHER)); + this.telemetryService.publicLog2('fileGet', this.getTelemetryData(options?.reason ?? LoadReason.OTHER)); } return this; @@ -727,12 +709,13 @@ 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); - return this.saveSequentializer.setPending(newVersionId, this.textFileService.write(this.lastResolvedFileStat.resource, this.createSnapshot(), { + const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat); + return this.saveSequentializer.setPending(newVersionId, this.textFileService.write(lastResolvedFileStat.resource, this.createSnapshot(), { overwriteReadonly: options.overwriteReadonly, overwriteEncoding: options.overwriteEncoding, - mtime: this.lastResolvedFileStat.mtime, + mtime: lastResolvedFileStat.mtime, encoding: this.getEncoding(), - etag: this.lastResolvedFileStat.etag, + etag: lastResolvedFileStat.etag, writeElevated: options.writeElevated }).then(stat => { this.logService.trace(`doSave(${versionId}) - after write()`, this.resource); @@ -800,11 +783,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return 'keybindings'; } - // Check for locale file - if (isEqual(this.resource, joinPath(this.environmentService.userRoamingDataHome, 'locale.json'))) { - return 'locale'; - } - // Check for snippets if (isEqualOrParent(this.resource, joinPath(this.environmentService.userRoamingDataHome, 'snippets'))) { return 'snippets'; @@ -848,10 +826,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return Promise.resolve(); } - return this.saveSequentializer.setPending(versionId, this.textFileService.write(this.lastResolvedFileStat.resource, this.createSnapshot(), { - mtime: this.lastResolvedFileStat.mtime, + const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat); + return this.saveSequentializer.setPending(versionId, this.textFileService.write(lastResolvedFileStat.resource, this.createSnapshot(), { + mtime: lastResolvedFileStat.mtime, encoding: this.getEncoding(), - etag: this.lastResolvedFileStat.etag + etag: lastResolvedFileStat.etag }).then(stat => { // Updated resolved stat with updated stat since touching it might have changed mtime @@ -951,7 +930,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } } - getEncoding(): string { + getEncoding(): string | undefined { return this.preferredEncoding || this.contentEncoding; } @@ -992,7 +971,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } } - updatePreferredEncoding(encoding: string): void { + updatePreferredEncoding(encoding: string | undefined): void { if (!this.isNewEncoding(encoding)) { return; } @@ -1003,7 +982,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this._onDidStateChange.fire(StateChange.ENCODING); } - private isNewEncoding(encoding: string): boolean { + private isNewEncoding(encoding: string | undefined): boolean { if (this.preferredEncoding === encoding) { return false; // return early if the encoding is already the same } @@ -1031,7 +1010,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.resource; } - getStat(): IFileStatWithMetadata { + getStat(): IFileStatWithMetadata | undefined { return this.lastResolvedFileStat; } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 4de574861a0..562aa4c727e 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -38,8 +38,8 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE private readonly _onModelOrphanedChanged: Emitter = this._register(new Emitter()); readonly onModelOrphanedChanged: Event = this._onModelOrphanedChanged.event; - private _onModelsDirty!: Event; - get onModelsDirty(): Event { + private _onModelsDirty: Event | undefined; + get onModelsDirty(): Event { if (!this._onModelsDirty) { this._onModelsDirty = this.debounce(this.onModelDirty); } @@ -47,8 +47,8 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE return this._onModelsDirty; } - private _onModelsSaveError!: Event; - get onModelsSaveError(): Event { + private _onModelsSaveError: Event | undefined; + get onModelsSaveError(): Event { if (!this._onModelsSaveError) { this._onModelsSaveError = this.debounce(this.onModelSaveError); } @@ -56,8 +56,8 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE return this._onModelsSaveError; } - private _onModelsSaved!: Event; - get onModelsSaved(): Event { + private _onModelsSaved: Event | undefined; + get onModelsSaved(): Event { if (!this._onModelsSaved) { this._onModelsSaved = this.debounce(this.onModelSaved); } @@ -65,8 +65,8 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE return this._onModelsSaved; } - private _onModelsReverted!: Event; - get onModelsReverted(): Event { + private _onModelsReverted: Event | undefined; + get onModelsReverted(): Event { if (!this._onModelsReverted) { this._onModelsReverted = this.debounce(this.onModelReverted); } @@ -95,7 +95,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE this.lifecycleService.onShutdown(this.dispose, this); } - private debounce(event: Event): Event { + private debounce(event: Event): Event { return Event.debounce(event, (prev: TextFileModelChangeEvent[], cur: TextFileModelChangeEvent) => { if (!prev) { prev = [cur]; @@ -127,7 +127,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Model exists let model = this.get(resource); if (model) { - if (options && options.reload) { + if (options?.reload) { // async reload: trigger a reload but return immediately if (options.reload.async) { @@ -198,7 +198,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE this.mapResourceToPendingModelLoaders.delete(resource); // Apply mode if provided - if (options && options.mode) { + if (options?.mode) { resolvedModel.setMode(options.mode); } diff --git a/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts b/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts index 95495464e6d..ce6bc5f6eba 100644 --- a/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts +++ b/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts @@ -30,9 +30,9 @@ export class TextResourcePropertiesService implements ITextResourcePropertiesSer } getEOL(resource?: URI, language?: string): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files', { overrideIdentifier: language, resource }); - if (filesConfiguration && filesConfiguration.eol && filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; + const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource }); + if (eol && eol !== 'auto') { + return eol; } const os = this.getOS(resource); return os === OperatingSystem.Linux || os === OperatingSystem.Macintosh ? '\n' : '\r\n'; diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 7a624c0761d..5a752b20128 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -4,16 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { Event } from 'vs/base/common/event'; +import { Event, IWaitUntil } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IEncodingSupport, ConfirmResult, IRevertOptions, IModeSupport } from 'vs/workbench/common/editor'; -import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; +import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteFileOptions, FileOperationError, FileOperationResult, FileOperation } from 'vs/platform/files/common/files'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { ITextBufferFactory, ITextModel, ITextSnapshot } from 'vs/editor/common/model'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; import { isUndefinedOrNull } from 'vs/base/common/types'; +import { isNative } from 'vs/base/common/platform'; export const ITextFileService = createDecorator('textFileService'); @@ -21,14 +22,22 @@ export interface ITextFileService extends IDisposable { _serviceBrand: undefined; - readonly onWillMove: Event; - readonly onAutoSaveConfigurationChange: Event; readonly onFilesAssociationChange: Event; readonly isHotExitEnabled: boolean; + /** + * An event that is fired before attempting a certain file operation. + */ + readonly onWillRunOperation: Event; + + /** + * An event that is fired after a file operation has been performed. + */ + readonly onDidRunOperation: Event; + /** * Access to the manager of text file editor models providing further methods to work with them. */ @@ -146,6 +155,35 @@ export interface ITextFileService extends IDisposable { getAutoSaveConfiguration(): IAutoSaveConfiguration; } + +export class FileOperationWillRunEvent implements IWaitUntil { + + constructor( + private _thenables: Promise[], + readonly operation: FileOperation, + readonly target: URI, + readonly source?: URI | undefined + ) { } + + waitUntil(thenable: Promise): void { + if (Object.isFrozen(this._thenables)) { + throw new Error('waitUntil cannot be used aync'); + } + this._thenables.push(thenable); + } +} + + +export class FileOperationDidRunEvent { + + constructor( + readonly operation: FileOperation, + readonly target: URI, + readonly source?: URI | undefined + ) { } +} + + export interface IReadTextFileOptions extends IReadFileOptions { /** @@ -412,10 +450,10 @@ export interface ITextFileEditorModelManager { readonly onModelReverted: Event; readonly onModelOrphanedChanged: Event; - readonly onModelsDirty: Event; - readonly onModelsSaveError: Event; - readonly onModelsSaved: Event; - readonly onModelsReverted: Event; + readonly onModelsDirty: Event; + readonly onModelsSaveError: Event; + readonly onModelsSaved: Event; + readonly onModelsReverted: Event; get(resource: URI): ITextFileEditorModel | undefined; @@ -433,7 +471,7 @@ export interface ISaveOptions { overwriteEncoding?: boolean; skipSaveParticipants?: boolean; writeElevated?: boolean; - availableFileSystems?: string[]; + availableFileSystems?: readonly string[]; } export interface ILoadOptions { @@ -463,7 +501,7 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport hasState(state: ModelState): boolean; - updatePreferredEncoding(encoding: string): void; + updatePreferredEncoding(encoding: string | undefined): void; save(options?: ISaveOptions): Promise; @@ -491,13 +529,6 @@ export interface IResolvedTextFileEditorModel extends ITextFileEditorModel { createSnapshot(): ITextSnapshot; } -export interface IWillMoveEvent { - oldResource: URI; - newResource: URI; - - waitUntil(p: Promise): void; -} - /** * Helper method to convert a snapshot into its full string form. */ @@ -573,243 +604,257 @@ export function toBufferOrReadable(value: string | ITextSnapshot | undefined): V return new TextSnapshotReadable(value); } -export const SUPPORTED_ENCODINGS: { [encoding: string]: { labelLong: string; labelShort: string; order: number; encodeOnly?: boolean; alias?: string } } = { - utf8: { - labelLong: 'UTF-8', - labelShort: 'UTF-8', - order: 1, - alias: 'utf8bom' - }, - utf8bom: { - labelLong: 'UTF-8 with BOM', - labelShort: 'UTF-8 with BOM', - encodeOnly: true, - order: 2, - alias: 'utf8' - }, - utf16le: { - labelLong: 'UTF-16 LE', - labelShort: 'UTF-16 LE', - order: 3 - }, - utf16be: { - labelLong: 'UTF-16 BE', - labelShort: 'UTF-16 BE', - order: 4 - }, - windows1252: { - labelLong: 'Western (Windows 1252)', - labelShort: 'Windows 1252', - order: 5 - }, - iso88591: { - labelLong: 'Western (ISO 8859-1)', - labelShort: 'ISO 8859-1', - order: 6 - }, - iso88593: { - labelLong: 'Western (ISO 8859-3)', - labelShort: 'ISO 8859-3', - order: 7 - }, - iso885915: { - labelLong: 'Western (ISO 8859-15)', - labelShort: 'ISO 8859-15', - order: 8 - }, - macroman: { - labelLong: 'Western (Mac Roman)', - labelShort: 'Mac Roman', - order: 9 - }, - cp437: { - labelLong: 'DOS (CP 437)', - labelShort: 'CP437', - order: 10 - }, - windows1256: { - labelLong: 'Arabic (Windows 1256)', - labelShort: 'Windows 1256', - order: 11 - }, - iso88596: { - labelLong: 'Arabic (ISO 8859-6)', - labelShort: 'ISO 8859-6', - order: 12 - }, - windows1257: { - labelLong: 'Baltic (Windows 1257)', - labelShort: 'Windows 1257', - order: 13 - }, - iso88594: { - labelLong: 'Baltic (ISO 8859-4)', - labelShort: 'ISO 8859-4', - order: 14 - }, - iso885914: { - labelLong: 'Celtic (ISO 8859-14)', - labelShort: 'ISO 8859-14', - order: 15 - }, - windows1250: { - labelLong: 'Central European (Windows 1250)', - labelShort: 'Windows 1250', - order: 16 - }, - iso88592: { - labelLong: 'Central European (ISO 8859-2)', - labelShort: 'ISO 8859-2', - order: 17 - }, - cp852: { - labelLong: 'Central European (CP 852)', - labelShort: 'CP 852', - order: 18 - }, - windows1251: { - labelLong: 'Cyrillic (Windows 1251)', - labelShort: 'Windows 1251', - order: 19 - }, - cp866: { - labelLong: 'Cyrillic (CP 866)', - labelShort: 'CP 866', - order: 20 - }, - iso88595: { - labelLong: 'Cyrillic (ISO 8859-5)', - labelShort: 'ISO 8859-5', - order: 21 - }, - koi8r: { - labelLong: 'Cyrillic (KOI8-R)', - labelShort: 'KOI8-R', - order: 22 - }, - koi8u: { - labelLong: 'Cyrillic (KOI8-U)', - labelShort: 'KOI8-U', - order: 23 - }, - iso885913: { - labelLong: 'Estonian (ISO 8859-13)', - labelShort: 'ISO 8859-13', - order: 24 - }, - windows1253: { - labelLong: 'Greek (Windows 1253)', - labelShort: 'Windows 1253', - order: 25 - }, - iso88597: { - labelLong: 'Greek (ISO 8859-7)', - labelShort: 'ISO 8859-7', - order: 26 - }, - windows1255: { - labelLong: 'Hebrew (Windows 1255)', - labelShort: 'Windows 1255', - order: 27 - }, - iso88598: { - labelLong: 'Hebrew (ISO 8859-8)', - labelShort: 'ISO 8859-8', - order: 28 - }, - iso885910: { - labelLong: 'Nordic (ISO 8859-10)', - labelShort: 'ISO 8859-10', - order: 29 - }, - iso885916: { - labelLong: 'Romanian (ISO 8859-16)', - labelShort: 'ISO 8859-16', - order: 30 - }, - windows1254: { - labelLong: 'Turkish (Windows 1254)', - labelShort: 'Windows 1254', - order: 31 - }, - iso88599: { - labelLong: 'Turkish (ISO 8859-9)', - labelShort: 'ISO 8859-9', - order: 32 - }, - windows1258: { - labelLong: 'Vietnamese (Windows 1258)', - labelShort: 'Windows 1258', - order: 33 - }, - gbk: { - labelLong: 'Simplified Chinese (GBK)', - labelShort: 'GBK', - order: 34 - }, - gb18030: { - labelLong: 'Simplified Chinese (GB18030)', - labelShort: 'GB18030', - order: 35 - }, - cp950: { - labelLong: 'Traditional Chinese (Big5)', - labelShort: 'Big5', - order: 36 - }, - big5hkscs: { - labelLong: 'Traditional Chinese (Big5-HKSCS)', - labelShort: 'Big5-HKSCS', - order: 37 - }, - shiftjis: { - labelLong: 'Japanese (Shift JIS)', - labelShort: 'Shift JIS', - order: 38 - }, - eucjp: { - labelLong: 'Japanese (EUC-JP)', - labelShort: 'EUC-JP', - order: 39 - }, - euckr: { - labelLong: 'Korean (EUC-KR)', - labelShort: 'EUC-KR', - order: 40 - }, - windows874: { - labelLong: 'Thai (Windows 874)', - labelShort: 'Windows 874', - order: 41 - }, - iso885911: { - labelLong: 'Latin/Thai (ISO 8859-11)', - labelShort: 'ISO 8859-11', - order: 42 - }, - koi8ru: { - labelLong: 'Cyrillic (KOI8-RU)', - labelShort: 'KOI8-RU', - order: 43 - }, - koi8t: { - labelLong: 'Tajik (KOI8-T)', - labelShort: 'KOI8-T', - order: 44 - }, - gb2312: { - labelLong: 'Simplified Chinese (GB 2312)', - labelShort: 'GB 2312', - order: 45 - }, - cp865: { - labelLong: 'Nordic DOS (CP 865)', - labelShort: 'CP 865', - order: 46 - }, - cp850: { - labelLong: 'Western European DOS (CP 850)', - labelShort: 'CP 850', - order: 47 - } -}; +export const SUPPORTED_ENCODINGS: { [encoding: string]: { labelLong: string; labelShort: string; order: number; encodeOnly?: boolean; alias?: string } } = + + // Desktop + isNative ? + { + utf8: { + labelLong: 'UTF-8', + labelShort: 'UTF-8', + order: 1, + alias: 'utf8bom' + }, + utf8bom: { + labelLong: 'UTF-8 with BOM', + labelShort: 'UTF-8 with BOM', + encodeOnly: true, + order: 2, + alias: 'utf8' + }, + utf16le: { + labelLong: 'UTF-16 LE', + labelShort: 'UTF-16 LE', + order: 3 + }, + utf16be: { + labelLong: 'UTF-16 BE', + labelShort: 'UTF-16 BE', + order: 4 + }, + windows1252: { + labelLong: 'Western (Windows 1252)', + labelShort: 'Windows 1252', + order: 5 + }, + iso88591: { + labelLong: 'Western (ISO 8859-1)', + labelShort: 'ISO 8859-1', + order: 6 + }, + iso88593: { + labelLong: 'Western (ISO 8859-3)', + labelShort: 'ISO 8859-3', + order: 7 + }, + iso885915: { + labelLong: 'Western (ISO 8859-15)', + labelShort: 'ISO 8859-15', + order: 8 + }, + macroman: { + labelLong: 'Western (Mac Roman)', + labelShort: 'Mac Roman', + order: 9 + }, + cp437: { + labelLong: 'DOS (CP 437)', + labelShort: 'CP437', + order: 10 + }, + windows1256: { + labelLong: 'Arabic (Windows 1256)', + labelShort: 'Windows 1256', + order: 11 + }, + iso88596: { + labelLong: 'Arabic (ISO 8859-6)', + labelShort: 'ISO 8859-6', + order: 12 + }, + windows1257: { + labelLong: 'Baltic (Windows 1257)', + labelShort: 'Windows 1257', + order: 13 + }, + iso88594: { + labelLong: 'Baltic (ISO 8859-4)', + labelShort: 'ISO 8859-4', + order: 14 + }, + iso885914: { + labelLong: 'Celtic (ISO 8859-14)', + labelShort: 'ISO 8859-14', + order: 15 + }, + windows1250: { + labelLong: 'Central European (Windows 1250)', + labelShort: 'Windows 1250', + order: 16 + }, + iso88592: { + labelLong: 'Central European (ISO 8859-2)', + labelShort: 'ISO 8859-2', + order: 17 + }, + cp852: { + labelLong: 'Central European (CP 852)', + labelShort: 'CP 852', + order: 18 + }, + windows1251: { + labelLong: 'Cyrillic (Windows 1251)', + labelShort: 'Windows 1251', + order: 19 + }, + cp866: { + labelLong: 'Cyrillic (CP 866)', + labelShort: 'CP 866', + order: 20 + }, + iso88595: { + labelLong: 'Cyrillic (ISO 8859-5)', + labelShort: 'ISO 8859-5', + order: 21 + }, + koi8r: { + labelLong: 'Cyrillic (KOI8-R)', + labelShort: 'KOI8-R', + order: 22 + }, + koi8u: { + labelLong: 'Cyrillic (KOI8-U)', + labelShort: 'KOI8-U', + order: 23 + }, + iso885913: { + labelLong: 'Estonian (ISO 8859-13)', + labelShort: 'ISO 8859-13', + order: 24 + }, + windows1253: { + labelLong: 'Greek (Windows 1253)', + labelShort: 'Windows 1253', + order: 25 + }, + iso88597: { + labelLong: 'Greek (ISO 8859-7)', + labelShort: 'ISO 8859-7', + order: 26 + }, + windows1255: { + labelLong: 'Hebrew (Windows 1255)', + labelShort: 'Windows 1255', + order: 27 + }, + iso88598: { + labelLong: 'Hebrew (ISO 8859-8)', + labelShort: 'ISO 8859-8', + order: 28 + }, + iso885910: { + labelLong: 'Nordic (ISO 8859-10)', + labelShort: 'ISO 8859-10', + order: 29 + }, + iso885916: { + labelLong: 'Romanian (ISO 8859-16)', + labelShort: 'ISO 8859-16', + order: 30 + }, + windows1254: { + labelLong: 'Turkish (Windows 1254)', + labelShort: 'Windows 1254', + order: 31 + }, + iso88599: { + labelLong: 'Turkish (ISO 8859-9)', + labelShort: 'ISO 8859-9', + order: 32 + }, + windows1258: { + labelLong: 'Vietnamese (Windows 1258)', + labelShort: 'Windows 1258', + order: 33 + }, + gbk: { + labelLong: 'Simplified Chinese (GBK)', + labelShort: 'GBK', + order: 34 + }, + gb18030: { + labelLong: 'Simplified Chinese (GB18030)', + labelShort: 'GB18030', + order: 35 + }, + cp950: { + labelLong: 'Traditional Chinese (Big5)', + labelShort: 'Big5', + order: 36 + }, + big5hkscs: { + labelLong: 'Traditional Chinese (Big5-HKSCS)', + labelShort: 'Big5-HKSCS', + order: 37 + }, + shiftjis: { + labelLong: 'Japanese (Shift JIS)', + labelShort: 'Shift JIS', + order: 38 + }, + eucjp: { + labelLong: 'Japanese (EUC-JP)', + labelShort: 'EUC-JP', + order: 39 + }, + euckr: { + labelLong: 'Korean (EUC-KR)', + labelShort: 'EUC-KR', + order: 40 + }, + windows874: { + labelLong: 'Thai (Windows 874)', + labelShort: 'Windows 874', + order: 41 + }, + iso885911: { + labelLong: 'Latin/Thai (ISO 8859-11)', + labelShort: 'ISO 8859-11', + order: 42 + }, + koi8ru: { + labelLong: 'Cyrillic (KOI8-RU)', + labelShort: 'KOI8-RU', + order: 43 + }, + koi8t: { + labelLong: 'Tajik (KOI8-T)', + labelShort: 'KOI8-T', + order: 44 + }, + gb2312: { + labelLong: 'Simplified Chinese (GB 2312)', + labelShort: 'GB 2312', + order: 45 + }, + cp865: { + labelLong: 'Nordic DOS (CP 865)', + labelShort: 'CP 865', + order: 46 + }, + cp850: { + labelLong: 'Western European DOS (CP 850)', + labelShort: 'CP 850', + order: 47 + } + } : + + // Web (https://github.com/microsoft/vscode/issues/79275) + { + utf8: { + labelLong: 'UTF-8', + labelShort: 'UTF-8', + order: 1, + alias: 'utf8bom' + } + }; diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index d621479da05..10cba0883ad 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -14,7 +14,7 @@ import { Schemas } from 'vs/base/common/network'; import { exists, stat, chmod, rimraf, MAX_FILE_SIZE, MAX_HEAP_SIZE } from 'vs/base/node/pfs'; import { join, dirname } from 'vs/base/common/path'; import { isMacintosh } from 'vs/base/common/platform'; -import product from 'vs/platform/product/common/product'; +import { IProductService } from 'vs/platform/product/common/productService'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { UTF8, UTF8_with_bom, UTF16be, UTF16le, encodingExists, encodeStream, UTF8_BOM, toDecodeStream, IDecodeStreamResult, detectEncodingByBOMFromBuffer, isUTFEncoding } from 'vs/base/node/encoding'; @@ -22,15 +22,55 @@ import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; import { joinPath, extname, isEqualOrParent } from 'vs/base/common/resources'; import { Disposable } from 'vs/base/common/lifecycle'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { VSBufferReadable } from 'vs/base/common/buffer'; +import { VSBufferReadable, bufferToStream } from 'vs/base/common/buffer'; import { Readable } from 'stream'; import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { ITextSnapshot } from 'vs/editor/common/model'; import { nodeReadableToString, streamToNodeReadable, nodeStreamToVSBufferReadable } from 'vs/base/node/stream'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ConfirmResult } from 'vs/workbench/common/editor'; +import { assign } from 'vs/base/common/objects'; export class NativeTextFileService extends AbstractTextFileService { - private _encoding!: EncodingOracle; + constructor( + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IFileService fileService: IFileService, + @IUntitledEditorService untitledEditorService: IUntitledEditorService, + @ILifecycleService lifecycleService: ILifecycleService, + @IInstantiationService instantiationService: IInstantiationService, + @IConfigurationService configurationService: IConfigurationService, + @IModeService modeService: IModeService, + @IModelService modelService: IModelService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @INotificationService notificationService: INotificationService, + @IBackupFileService backupFileService: IBackupFileService, + @IHistoryService historyService: IHistoryService, + @IContextKeyService contextKeyService: IContextKeyService, + @IDialogService dialogService: IDialogService, + @IFileDialogService fileDialogService: IFileDialogService, + @IEditorService editorService: IEditorService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, + @IElectronService private readonly electronService: IElectronService, + @IProductService private readonly productService: IProductService + ) { + super(contextService, fileService, untitledEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, contextKeyService, dialogService, fileDialogService, editorService, textResourceConfigurationService); + } + + private _encoding: EncodingOracle | undefined; get encoding(): EncodingOracle { if (!this._encoding) { this._encoding = this._register(this.instantiationService.createInstance(EncodingOracle)); @@ -40,7 +80,16 @@ export class NativeTextFileService extends AbstractTextFileService { } async read(resource: URI, options?: IReadTextFileOptions): Promise { - const [bufferStream, decoder] = await this.doRead(resource, options); + const [bufferStream, decoder] = await this.doRead(resource, + assign({ + // optimization: since we know that the caller does not + // care about buffering, we indicate this to the reader. + // this reduces all the overhead the buffered reading + // has (open, read, close) if the provider supports + // unbuffered reading. + preferUnbuffered: true + }, options || Object.create(null)) + ); return { ...bufferStream, @@ -59,22 +108,31 @@ export class NativeTextFileService extends AbstractTextFileService { }; } - private async doRead(resource: URI, options?: IReadTextFileOptions): Promise<[IFileStreamContent, IDecodeStreamResult]> { + private async doRead(resource: URI, options?: IReadTextFileOptions & { preferUnbuffered?: boolean }): Promise<[IFileStreamContent, IDecodeStreamResult]> { // ensure limits options = this.ensureLimits(options); - // read stream raw - const bufferStream = await this.fileService.readFileStream(resource, options); + // read stream raw (either buffered or unbuffered) + let bufferStream: IFileStreamContent; + if (options.preferUnbuffered) { + const content = await this.fileService.readFile(resource, options); + bufferStream = { + ...content, + value: bufferToStream(content.value) + }; + } else { + bufferStream = await this.fileService.readFileStream(resource, options); + } // read through encoding library const decoder = await toDecodeStream(streamToNodeReadable(bufferStream.value), { - guessEncoding: (options && options.autoGuessEncoding) || this.textResourceConfigurationService.getValue(resource, 'files.autoGuessEncoding'), + guessEncoding: options?.autoGuessEncoding || this.textResourceConfigurationService.getValue(resource, 'files.autoGuessEncoding'), overwriteEncoding: detectedEncoding => this.encoding.getReadEncoding(resource, options, detectedEncoding) }); // validate binary - if (options && options.acceptTextOnly && decoder.detected.seemsBinary) { + if (options?.acceptTextOnly && decoder.detected.seemsBinary) { throw new TextFileOperationError(localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), TextFileOperationResult.FILE_IS_BINARY, options); } @@ -126,7 +184,7 @@ export class NativeTextFileService extends AbstractTextFileService { // check for overwriteReadonly property (only supported for local file://) try { - if (options && options.overwriteReadonly && resource.scheme === Schemas.file && await exists(resource.fsPath)) { + if (options?.overwriteReadonly && resource.scheme === Schemas.file && await exists(resource.fsPath)) { const fileStat = await stat(resource.fsPath); // try to change mode to writeable @@ -137,7 +195,7 @@ export class NativeTextFileService extends AbstractTextFileService { } // check for writeElevated property (only supported for local file://) - if (options && options.writeElevated && resource.scheme === Schemas.file) { + if (options?.writeElevated && resource.scheme === Schemas.file) { return this.writeElevated(resource, value, options); } @@ -235,12 +293,12 @@ export class NativeTextFileService extends AbstractTextFileService { return new Promise((resolve, reject) => { const promptOptions = { - name: this.environmentService.appNameLong.replace('-', ''), - icns: (isMacintosh && this.environmentService.isBuilt) ? join(dirname(this.environmentService.appRoot), `${product.nameShort}.icns`) : undefined + name: this.productService.nameLong.replace('-', ''), + icns: (isMacintosh && this.environmentService.isBuilt) ? join(dirname(this.environmentService.appRoot), `${this.productService.nameShort}.icns`) : undefined }; const sudoCommand: string[] = [`"${this.environmentService.cliPath}"`]; - if (options && options.overwriteReadonly) { + if (options?.overwriteReadonly) { sudoCommand.push('--file-chmod'); } @@ -255,6 +313,20 @@ export class NativeTextFileService extends AbstractTextFileService { }); }); } + + protected getWindowCount(): Promise { + return this.electronService.getWindowCount(); + } + + async confirmSave(resources?: URI[]): Promise { + if (this.environmentService.isExtensionDevelopment) { + if (!this.environmentService.args['extension-development-confirm-save']) { + return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) + } + } + + return super.confirmSave(resources); + } } export interface IEncodingOverride { @@ -312,7 +384,7 @@ export class EncodingOracle extends Disposable implements IResourceEncodings { // Ensure that we preserve an existing BOM if found for UTF8 // unless we are instructed to overwrite the encoding - const overwriteEncoding = options && options.overwriteEncoding; + const overwriteEncoding = options?.overwriteEncoding; if (!overwriteEncoding && encoding === UTF8) { try { const buffer = (await this.fileService.readFile(resource, { length: UTF8_BOM.length })).value; @@ -340,7 +412,7 @@ export class EncodingOracle extends Disposable implements IResourceEncodings { let preferredEncoding: string | undefined; // Encoding passed in as option - if (options && options.encoding) { + if (options?.encoding) { if (detectedEncoding === UTF8 && options.encoding === UTF8) { preferredEncoding = UTF8_with_bom; // indicate the file has BOM if we are to resolve with UTF 8 } else { diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index 629e19c6b77..07c3271fa95 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -15,6 +15,7 @@ import { FileOperationResult, FileOperationError, IFileService } from 'vs/platfo import { IModelService } from 'vs/editor/common/services/modelService'; import { timeout } from 'vs/base/common/async'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; +import { assertIsDefined } from 'vs/base/common/types'; class ServiceAccessor { constructor(@ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService, @IFileService public fileService: TestFileService) { @@ -286,8 +287,8 @@ suite('Files - TextFileEditorModel', () => { model1.textEditorModel!.setValue('foo'); - const m1Mtime = model1.getStat().mtime; - const m2Mtime = model2.getStat().mtime; + const m1Mtime = assertIsDefined(model1.getStat()).mtime; + const m2Mtime = assertIsDefined(model2.getStat()).mtime; assert.ok(m1Mtime > 0); assert.ok(m2Mtime > 0); @@ -302,8 +303,8 @@ suite('Files - TextFileEditorModel', () => { await accessor.textFileService.saveAll(); assert.ok(!accessor.textFileService.isDirty(toResource.call(this, '/path/index_async.txt'))); assert.ok(!accessor.textFileService.isDirty(toResource.call(this, '/path/index_async2.txt'))); - assert.ok(model1.getStat().mtime > m1Mtime); - assert.ok(model2.getStat().mtime > m2Mtime); + assert.ok(assertIsDefined(model1.getStat()).mtime > m1Mtime); + assert.ok(assertIsDefined(model2.getStat()).mtime > m2Mtime); assert.ok(model1.getLastSaveAttemptTime() > m1Mtime); assert.ok(model2.getLastSaveAttemptTime() > m2Mtime); diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index 1b5f490f490..857096d4b0d 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -311,4 +311,4 @@ suite('Files - TextFileEditorModelManager', () => { manager.disposeModel((model as TextFileEditorModel)); manager.dispose(); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index c8e4de0a55a..e1eda1bcc27 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -7,10 +7,9 @@ import * as sinon from 'sinon'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { ILifecycleService, BeforeShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; -import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestWindowsService, TestContextService, TestFileService, TestHostService } from 'vs/workbench/test/workbenchTestServices'; +import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestContextService, TestFileService, TestElectronService } from 'vs/workbench/test/workbenchTestServices'; import { toResource } from 'vs/base/test/common/utils'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ConfirmResult } from 'vs/workbench/common/editor'; @@ -21,18 +20,17 @@ import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/commo import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { Schemas } from 'vs/base/common/network'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IElectronService } from 'vs/platform/electron/node/electron'; class ServiceAccessor { constructor( @ILifecycleService public lifecycleService: TestLifecycleService, @ITextFileService public textFileService: TestTextFileService, @IUntitledEditorService public untitledEditorService: IUntitledEditorService, - @IWindowsService public windowsService: TestWindowsService, @IWorkspaceContextService public contextService: TestContextService, @IModelService public modelService: ModelServiceImpl, @IFileService public fileService: TestFileService, - @IHostService public hostService: TestHostService + @IElectronService public electronService: TestElectronService ) { } } @@ -426,7 +424,7 @@ suite('Files - TextFileService', () => { } // Set multiple windows if required if (multipleWindows) { - accessor.hostService.windowCount = Promise.resolve(2); + accessor.electronService.windowCount = Promise.resolve(2); } // Set cancel to force a veto if hot exit does not trigger service.setConfirmResult(ConfirmResult.CANCEL); diff --git a/src/vs/workbench/services/themes/browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts index 2512af088a0..a641d555298 100644 --- a/src/vs/workbench/services/themes/browser/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts @@ -189,8 +189,10 @@ function _loadIconThemeDocument(fileService: IFileService, location: URI): Promi return fileService.readFile(location).then((content) => { let errors: Json.ParseError[] = []; let contentValue = Json.parse(content.value.toString(), errors); - if (errors.length > 0 || !contentValue) { + if (errors.length > 0) { return Promise.reject(new Error(nls.localize('error.cannotparseicontheme', "Problems parsing file icons file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', ')))); + } else if (Json.getNodeType(contentValue) !== 'object') { + return Promise.reject(new Error(nls.localize('error.invalidformat', "Invalid format for file icons theme file: Object expected."))); } return Promise.resolve(contentValue); }); diff --git a/src/vs/workbench/services/themes/browser/fileIconThemeStore.ts b/src/vs/workbench/services/themes/browser/fileIconThemeStore.ts index e4eb557f54c..0afad15ee6c 100644 --- a/src/vs/workbench/services/themes/browser/fileIconThemeStore.ts +++ b/src/vs/workbench/services/themes/browser/fileIconThemeStore.ts @@ -14,6 +14,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { FileIconThemeData } from 'vs/workbench/services/themes/browser/fileIconThemeData'; import { URI } from 'vs/base/common/uri'; import { Disposable } from 'vs/base/common/lifecycle'; +import { find } from 'vs/base/common/arrays'; const iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'iconThemes', @@ -62,7 +63,7 @@ export class FileIconThemeStore extends Disposable { private initialize() { iconThemeExtPoint.setHandler((extensions) => { - const previousIds: { [key: string]: boolean } = {}; + const previousIds: { [key: string]: boolean; } = {}; const added: FileIconThemeData[] = []; for (const theme of this.knownIconThemes) { previousIds[theme.id] = true; @@ -131,12 +132,7 @@ export class FileIconThemeStore extends Disposable { return Promise.resolve(FileIconThemeData.noIconTheme()); } return this.getFileIconThemes().then(allIconSets => { - for (let iconSet of allIconSets) { - if (iconSet.id === iconTheme) { - return iconSet; - } - } - return undefined; + return find(allIconSets, iconSet => iconSet.id === iconTheme); }); } @@ -145,12 +141,7 @@ export class FileIconThemeStore extends Disposable { return Promise.resolve(FileIconThemeData.noIconTheme()); } return this.getFileIconThemes().then(allIconSets => { - for (let iconSet of allIconSets) { - if (iconSet.settingsId === settingsId) { - return iconSet; - } - } - return undefined; + return find(allIconSets, iconSet => iconSet.settingsId === settingsId); }); } diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index b5e65780f81..85b09406b2c 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -32,6 +32,7 @@ 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'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; // implementation @@ -73,15 +74,15 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { private container: HTMLElement; private readonly onColorThemeChange: Emitter; private watchedColorThemeLocation: URI | undefined; - private watchedColorThemeDisposable: IDisposable; + private watchedColorThemeDisposable: IDisposable | undefined; private iconThemeStore: FileIconThemeStore; private currentIconTheme: FileIconThemeData; private readonly onFileIconThemeChange: Emitter; private watchedIconThemeLocation: URI | undefined; - private watchedIconThemeDisposable: IDisposable; + private watchedIconThemeDisposable: IDisposable | undefined; - private themingParticipantChangeListener: IDisposable; + private themingParticipantChangeListener: IDisposable | undefined; private get colorCustomizations(): IColorCustomizations { return this.configurationService.getValue(CUSTOM_WORKBENCH_COLORS_SETTING) || {}; @@ -98,15 +99,17 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { @ITelemetryService private readonly telemetryService: ITelemetryService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IFileService private readonly fileService: IFileService, + @IExtensionResourceLoaderService private readonly extensionResourceLoaderService: IExtensionResourceLoaderService, @IWorkbenchLayoutService readonly layoutService: IWorkbenchLayoutService ) { this.container = layoutService.getWorkbenchContainer(); - this.colorThemeStore = new ColorThemeStore(extensionService, ColorThemeData.createLoadedEmptyTheme(DEFAULT_THEME_ID, DEFAULT_THEME_SETTING_VALUE)); + this.colorThemeStore = new ColorThemeStore(extensionService); this.onFileIconThemeChange = new Emitter(); this.iconThemeStore = new FileIconThemeStore(extensionService); this.onColorThemeChange = new Emitter({ leakWarningThreshold: 400 }); + this.currentColorTheme = ColorThemeData.createUnloadedTheme(''); this.currentIconTheme = FileIconThemeData.createUnloadedTheme(''); // In order to avoid paint flashing for tokens, because @@ -177,6 +180,8 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { // restore color this.setColorTheme(prevColorId, 'auto'); prevColorId = undefined; + } else { + this.reloadCurrentColorTheme(); } } } @@ -199,6 +204,8 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (this.currentIconTheme.id === DEFAULT_ICON_THEME_ID && !types.isUndefined(prevFileIconId) && await this.iconThemeStore.findThemeData(prevFileIconId)) { this.setFileIconTheme(prevFileIconId, 'auto'); prevFileIconId = undefined; + } else { + this.reloadCurrentFileIconTheme(); } } } @@ -206,18 +213,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.fileService.onFileChanges(async e => { if (this.watchedColorThemeLocation && this.currentColorTheme && e.contains(this.watchedColorThemeLocation, FileChangeType.UPDATED)) { - await this.currentColorTheme.reload(this.fileService); - this.currentColorTheme.setCustomColors(this.colorCustomizations); - this.currentColorTheme.setCustomTokenColors(this.tokenColorCustomizations); - this.updateDynamicCSSRules(this.currentColorTheme); - this.applyTheme(this.currentColorTheme, undefined, false); + this.reloadCurrentColorTheme(); } if (this.watchedIconThemeLocation && this.currentIconTheme && e.contains(this.watchedIconThemeLocation, FileChangeType.UPDATED)) { - await this.currentIconTheme.reload(this.fileService); - _applyIconTheme(this.currentIconTheme, () => { - this.doSetFileIconTheme(this.currentIconTheme); - return Promise.resolve(this.currentIconTheme); - }); + this.reloadCurrentFileIconTheme(); } }); } @@ -344,7 +343,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return null; } const themeData = data; - return themeData.ensureLoaded(this.fileService).then(_ => { + return themeData.ensureLoaded(this.extensionResourceLoaderService).then(_ => { if (themeId === this.currentColorTheme.id && !this.currentColorTheme.isLoaded && this.currentColorTheme.hasEqualData(themeData)) { // the loaded theme is identical to the perisisted theme. Don't need to send an event. this.currentColorTheme = themeData; @@ -362,6 +361,14 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { }); } + private async reloadCurrentColorTheme() { + await this.currentColorTheme.reload(this.extensionResourceLoaderService); + this.currentColorTheme.setCustomColors(this.colorCustomizations); + this.currentColorTheme.setCustomTokenColors(this.tokenColorCustomizations); + this.updateDynamicCSSRules(this.currentColorTheme); + this.applyTheme(this.currentColorTheme, undefined, false); + } + public restoreColorTheme() { let colorThemeSetting = this.configurationService.getValue(COLOR_THEME_SETTING); if (colorThemeSetting !== this.currentColorTheme.settingsId) { @@ -387,7 +394,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } private applyTheme(newTheme: ColorThemeData, settingsTarget: ConfigurationTarget | undefined | 'auto', silent = false): Promise { - if (this.currentColorTheme) { + if (this.currentColorTheme.id) { removeClasses(this.container, this.currentColorTheme.id); } else { removeClasses(this.container, VS_DARK_THEME, VS_LIGHT_THEME, VS_HC_THEME); @@ -499,6 +506,14 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { }); } + private async reloadCurrentFileIconTheme() { + await this.currentIconTheme.reload(this.fileService); + _applyIconTheme(this.currentIconTheme, () => { + this.doSetFileIconTheme(this.currentIconTheme); + return Promise.resolve(this.currentIconTheme); + }); + } + public restoreFileIconTheme() { let fileIconThemeSetting = this.configurationService.getValue(ICON_THEME_SETTING); if (fileIconThemeSetting !== this.currentIconTheme.settingsId) { diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index 6d39ebd157e..df2006b67c8 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -17,14 +17,14 @@ import { ThemeType } from 'vs/platform/theme/common/themeService'; import { Registry } from 'vs/platform/registry/common/platform'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import { URI } from 'vs/base/common/uri'; -import { IFileService } from 'vs/platform/files/common/files'; import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser'; import { startsWith } from 'vs/base/common/strings'; +import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; let colorRegistry = Registry.as(Extensions.ColorContribution); const tokenGroupToScopesMap = { - comments: ['comment'], + comments: ['comment', 'punctuation.definition.comment'], strings: ['string'], keywords: ['keyword - keyword.operator', 'keyword.control', 'storage', 'storage.type'], numbers: ['constant.numeric'], @@ -167,21 +167,21 @@ export class ColorThemeData implements IColorTheme { } } - public ensureLoaded(fileService: IFileService): Promise { - return !this.isLoaded ? this.load(fileService) : Promise.resolve(undefined); + public ensureLoaded(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise { + return !this.isLoaded ? this.load(extensionResourceLoaderService) : Promise.resolve(undefined); } - public reload(fileService: IFileService): Promise { - return this.load(fileService); + public reload(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise { + return this.load(extensionResourceLoaderService); } - private load(fileService: IFileService): Promise { + private load(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise { if (!this.location) { return Promise.resolve(undefined); } this.themeTokenColors = []; this.colorMap = {}; - return _loadColorTheme(fileService, this.location, this.themeTokenColors, this.colorMap).then(_ => { + return _loadColorTheme(extensionResourceLoaderService, this.location, this.themeTokenColors, this.colorMap).then(_ => { this.isLoaded = true; }); } @@ -295,17 +295,19 @@ function toCSSSelector(extensionId: string, path: string) { return str; } -function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { +function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { if (resources.extname(themeLocation) === '.json') { - return fileService.readFile(themeLocation).then(content => { + return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => { let errors: Json.ParseError[] = []; - let contentValue = Json.parse(content.value.toString(), errors); + let contentValue = Json.parse(content, errors); if (errors.length > 0) { return Promise.reject(new Error(nls.localize('error.cannotparsejson', "Problems parsing JSON theme file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', ')))); + } else if (Json.getNodeType(contentValue) !== 'object') { + return Promise.reject(new Error(nls.localize('error.invalidformat', "Invalid format for JSON theme file: Object expected."))); } let includeCompletes: Promise = Promise.resolve(null); if (contentValue.include) { - includeCompletes = _loadColorTheme(fileService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), resultRules, resultColors); + includeCompletes = _loadColorTheme(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), resultRules, resultColors); } return includeCompletes.then(_ => { if (Array.isArray(contentValue.settings)) { @@ -331,7 +333,7 @@ function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRu resultRules.push(...tokenColors); return null; } else if (typeof tokenColors === 'string') { - return _loadSyntaxTokens(fileService, resources.joinPath(resources.dirname(themeLocation), tokenColors), resultRules, {}); + return _loadSyntaxTokens(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), tokenColors), resultRules, {}); } else { return Promise.reject(new Error(nls.localize({ key: 'error.invalidformat.tokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'tokenColors' should be either an array specifying colors or a path to a TextMate theme file", themeLocation.toString()))); } @@ -340,14 +342,14 @@ function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRu }); }); } else { - return _loadSyntaxTokens(fileService, themeLocation, resultRules, resultColors); + return _loadSyntaxTokens(extensionResourceLoaderService, themeLocation, resultRules, resultColors); } } -function _loadSyntaxTokens(fileService: IFileService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { - return fileService.readFile(themeLocation).then(content => { +function _loadSyntaxTokens(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { + return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => { try { - let contentValue = parsePList(content.value.toString()); + let contentValue = parsePList(content); let settings: ITokenColorizationRule[] = contentValue.settings; if (!Array.isArray(settings)) { return Promise.reject(new Error(nls.localize('error.plist.invalidformat', "Problem parsing tmTheme file: {0}. 'settings' is not array."))); @@ -381,4 +383,4 @@ let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { { scope: 'token.error-token', settings: { foreground: '#FF0000' } }, { scope: 'token.debug-token', settings: { foreground: '#b267e6' } } ], -}; \ No newline at end of file +}; diff --git a/src/vs/workbench/services/themes/common/colorThemeStore.ts b/src/vs/workbench/services/themes/common/colorThemeStore.ts index 272338755fc..7253ada3afd 100644 --- a/src/vs/workbench/services/themes/common/colorThemeStore.ts +++ b/src/vs/workbench/services/themes/common/colorThemeStore.ts @@ -57,8 +57,8 @@ export class ColorThemeStore { private readonly onDidChangeEmitter = new Emitter(); public readonly onDidChange: Event = this.onDidChangeEmitter.event; - constructor(@IExtensionService private readonly extensionService: IExtensionService, defaultTheme: ColorThemeData) { - this.extensionsColorThemes = [defaultTheme]; + constructor(@IExtensionService private readonly extensionService: IExtensionService) { + this.extensionsColorThemes = []; this.initialize(); } @@ -69,7 +69,7 @@ export class ColorThemeStore { for (const theme of this.extensionsColorThemes) { previousIds[theme.id] = true; } - this.extensionsColorThemes.length = 1; // remove all but the default theme + this.extensionsColorThemes.length = 0; for (let ext of extensions) { let extensionData = { extensionId: ext.description.identifier.value, @@ -114,11 +114,7 @@ export class ColorThemeStore { } let themeData = ColorThemeData.fromExtensionTheme(theme, colorThemeLocation, extensionData); - if (themeData.id === this.extensionsColorThemes[0].id) { - this.extensionsColorThemes[0] = themeData; - } else { - this.extensionsColorThemes.push(themeData); - } + this.extensionsColorThemes.push(themeData); }); } diff --git a/src/vs/workbench/services/timer/electron-browser/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts index aefb915e2b6..1f761754f54 100644 --- a/src/vs/workbench/services/timer/electron-browser/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -7,7 +7,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { virtualMachineHint } from 'vs/base/node/id'; import * as perf from 'vs/base/common/performance'; import * as os from 'os'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IElectronService } from 'vs/platform/electron/node/electron'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -308,7 +308,7 @@ class TimerService implements ITimerService { private _startupMetrics?: Promise; constructor( - @IHostService private readonly _hostService: IHostService, + @IElectronService private readonly _electronService: IElectronService, @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @@ -380,7 +380,7 @@ class TimerService implements ITimerService { isLatestVersion: Boolean(await this._updateService.isLatestVersion()), didUseCachedData: didUseCachedData(), windowKind: this._lifecycleService.startupKind, - windowCount: await this._hostService.windowCount, + windowCount: await this._electronService.getWindowCount(), viewletId: activeViewlet ? activeViewlet.getId() : undefined, editorIds: this._editorService.visibleEditors.map(input => input.getTypeId()), panelId: activePanel ? activePanel.getId() : undefined, diff --git a/src/vs/workbench/services/untitled/common/untitledEditorService.ts b/src/vs/workbench/services/untitled/common/untitledEditorService.ts index ca8614f26aa..ced3aebe36d 100644 --- a/src/vs/workbench/services/untitled/common/untitledEditorService.ts +++ b/src/vs/workbench/services/untitled/common/untitledEditorService.ts @@ -34,22 +34,22 @@ export interface IUntitledEditorService { /** * Events for when untitled editors content changes (e.g. any keystroke). */ - onDidChangeContent: Event; + readonly onDidChangeContent: Event; /** * Events for when untitled editors change (e.g. getting dirty, saved or reverted). */ - onDidChangeDirty: Event; + readonly onDidChangeDirty: Event; /** * Events for when untitled editor encodings change. */ - onDidChangeEncoding: Event; + readonly onDidChangeEncoding: Event; /** * Events for when untitled editors are disposed. */ - onDidDisposeModel: Event; + readonly onDidDisposeModel: Event; /** * Returns if an untitled resource with the given URI exists. @@ -238,12 +238,12 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor // Look up default language from settings if any if (!mode && !hasAssociatedFilePath) { const configuration = this.configurationService.getValue(); - if (configuration.files && configuration.files.defaultLanguage) { + if (configuration.files?.defaultLanguage) { mode = configuration.files.defaultLanguage; } } - const input = this.instantiationService.createInstance(UntitledEditorInput, untitledResource, hasAssociatedFilePath, mode, initialValue, encoding); + const input = this.instantiationService.createInstance(UntitledEditorInput, untitledResource, !!hasAssociatedFilePath, mode, initialValue, encoding); const contentListener = input.onDidModelChangeContent(() => this._onDidChangeContent.fire(untitledResource)); const dirtyListener = input.onDidChangeDirty(() => this._onDidChangeDirty.fire(untitledResource)); diff --git a/src/vs/workbench/services/update/browser/updateService.ts b/src/vs/workbench/services/update/browser/updateService.ts index afdb075fe0b..155fb7fc720 100644 --- a/src/vs/workbench/services/update/browser/updateService.ts +++ b/src/vs/workbench/services/update/browser/updateService.ts @@ -24,7 +24,7 @@ export interface IUpdateProvider { checkForUpdate(): Promise; } -export class UpdateService extends Disposable implements IUpdateService { +export class BrowserUpdateService extends Disposable implements IUpdateService { _serviceBrand: undefined; @@ -92,4 +92,4 @@ export class UpdateService extends Disposable implements IUpdateService { } } -registerSingleton(IUpdateService, UpdateService); +registerSingleton(IUpdateService, BrowserUpdateService); diff --git a/src/vs/platform/update/electron-browser/updateService.ts b/src/vs/workbench/services/update/electron-browser/updateService.ts similarity index 90% rename from src/vs/platform/update/electron-browser/updateService.ts rename to src/vs/workbench/services/update/electron-browser/updateService.ts index 95632dead57..b8f6558b2ca 100644 --- a/src/vs/platform/update/electron-browser/updateService.ts +++ b/src/vs/workbench/services/update/electron-browser/updateService.ts @@ -7,8 +7,9 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event, Emitter } from 'vs/base/common/event'; import { IUpdateService, State } from 'vs/platform/update/common/update'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -export class UpdateService implements IUpdateService { +export class NativeUpdateService implements IUpdateService { _serviceBrand: undefined; @@ -56,3 +57,5 @@ export class UpdateService implements IUpdateService { return this.channel.call('isLatestVersion'); } } + +registerSingleton(IUpdateService, NativeUpdateService); diff --git a/src/vs/workbench/services/url/browser/urlService.ts b/src/vs/workbench/services/url/browser/urlService.ts index b073447fc26..eef5070c450 100644 --- a/src/vs/workbench/services/url/browser/urlService.ts +++ b/src/vs/workbench/services/url/browser/urlService.ts @@ -54,7 +54,7 @@ export class BrowserURLService extends AbstractURLService { private registerListeners(): void { if (this.provider) { - this._register(this.provider.onCallback(uri => this.open(uri))); + this._register(this.provider.onCallback(uri => this.open(uri, { trusted: true }))); } } diff --git a/src/vs/workbench/services/url/electron-browser/urlService.ts b/src/vs/workbench/services/url/electron-browser/urlService.ts index 45a819abc78..73fa15e1f8e 100644 --- a/src/vs/workbench/services/url/electron-browser/urlService.ts +++ b/src/vs/workbench/services/url/electron-browser/urlService.ts @@ -3,15 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; +import { IURLService, IURLHandler, IOpenURLOptions } from 'vs/platform/url/common/url'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/common/urlIpc'; +import { URLHandlerChannel } from 'vs/platform/url/common/urlIpc'; import { URLService } from 'vs/platform/url/node/urlService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import product from 'vs/platform/product/common/product'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; +import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; +import { IElectronService } from 'vs/platform/electron/node/electron'; + +export interface IRelayOpenURLOptions extends IOpenURLOptions { + openToSide?: boolean; + openExternal?: boolean; +} export class RelayURLService extends URLService implements IURLHandler { @@ -20,11 +27,12 @@ export class RelayURLService extends URLService implements IURLHandler { constructor( @IMainProcessService mainProcessService: IMainProcessService, @IOpenerService openerService: IOpenerService, - @IWindowService private windowService: IWindowService + @IElectronEnvironmentService private electronEnvironmentService: IElectronEnvironmentService, + @IElectronService private electronService: IElectronService ) { super(); - this.urlService = new URLServiceChannelClient(mainProcessService.getChannel('url')); + this.urlService = createChannelSender(mainProcessService.getChannel('url')); mainProcessService.registerChannel('urlHandler', new URLHandlerChannel(this)); openerService.registerOpener(this); @@ -35,24 +43,30 @@ export class RelayURLService extends URLService implements IURLHandler { let query = uri.query; if (!query) { - query = `windowId=${encodeURIComponent(this.windowService.windowId)}`; + query = `windowId=${encodeURIComponent(this.electronEnvironmentService.windowId)}`; } else { - query += `&windowId=${encodeURIComponent(this.windowService.windowId)}`; + query += `&windowId=${encodeURIComponent(this.electronEnvironmentService.windowId)}`; } return uri.with({ query }); } - async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise { + async open(resource: URI, options?: IRelayOpenURLOptions): Promise { if (resource.scheme !== product.urlProtocol) { return false; } - return await this.urlService.open(resource); + return await this.urlService.open(resource, options); } - handleURL(uri: URI): Promise { - return super.open(uri); + async handleURL(uri: URI, options?: IOpenURLOptions): Promise { + const result = await super.open(uri, options); + + if (result) { + await this.electronService.focusWindow(); + } + + return result; } } diff --git a/src/vs/workbench/services/userData/common/fileUserDataProvider.ts b/src/vs/workbench/services/userData/common/fileUserDataProvider.ts index 4bf98510ac4..9021b0eb963 100644 --- a/src/vs/workbench/services/userData/common/fileUserDataProvider.ts +++ b/src/vs/workbench/services/userData/common/fileUserDataProvider.ts @@ -5,20 +5,25 @@ 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 { IFileSystemProviderWithFileReadWriteCapability, IFileChange, IWatchOptions, IStat, FileOverwriteOptions, FileType, FileWriteOptions, FileDeleteOptions, FileSystemProviderCapabilities, IFileSystemProviderWithOpenReadWriteCloseCapability, FileOpenOptions, hasReadWriteCapability, hasOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadStreamCapability, FileReadStreamOptions, hasFileReadStreamCapability } 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'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { ReadableStreamEvents } from 'vs/base/common/stream'; -export class FileUserDataProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability { +export class FileUserDataProvider extends Disposable implements + IFileSystemProviderWithFileReadWriteCapability, + IFileSystemProviderWithOpenReadWriteCloseCapability, + IFileSystemProviderWithFileReadStreamCapability { readonly capabilities: FileSystemProviderCapabilities = this.fileSystemProvider.capabilities; readonly onDidChangeCapabilities: Event = Event.None; - private readonly _onDidChangeFile: Emitter = this._register(new Emitter()); - readonly onDidChangeFile: Event = this._onDidChangeFile.event; + private readonly _onDidChangeFile = this._register(new Emitter()); + readonly onDidChangeFile: Event = this._onDidChangeFile.event; private readonly userDataHome: URI; @@ -60,6 +65,13 @@ export class FileUserDataProvider extends Disposable implements IFileSystemProvi throw new Error('not supported'); } + readFileStream(resource: URI, opts: FileReadStreamOptions, token?: CancellationToken): ReadableStreamEvents { + if (hasFileReadStreamCapability(this.fileSystemProvider)) { + return this.fileSystemProvider.readFileStream(this.toFileSystemResource(resource), opts, token); + } + throw new Error('not supported'); + } + readdir(resource: URI): Promise<[string, FileType][]> { return this.fileSystemProvider.readdir(this.toFileSystemResource(resource)); } @@ -103,7 +115,7 @@ export class FileUserDataProvider extends Disposable implements IFileSystemProvi return this.fileSystemProvider.delete(this.toFileSystemResource(resource), opts); } - private handleFileChanges(changes: IFileChange[]): void { + private handleFileChanges(changes: readonly IFileChange[]): void { const userDataChanges: IFileChange[] = []; for (const change of changes) { const userDataResource = this.toUserDataResource(change.resource); @@ -139,4 +151,4 @@ export class FileUserDataProvider extends Disposable implements IFileSystemProvi 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 index 3fbd91518a6..8bd82779eb6 100644 --- a/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts +++ b/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts @@ -6,7 +6,7 @@ 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 { FileChangeType, FileType, IWatchOptions, IStat, FileSystemProviderErrorCode, FileSystemProviderError, FileWriteOptions, IFileChange, FileDeleteOptions, FileSystemProviderCapabilities, FileOverwriteOptions, IFileSystemProviderWithFileReadWriteCapability } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; class File implements IStat { @@ -50,7 +50,7 @@ class Directory implements IStat { export type Entry = File | Directory; -export class InMemoryFileSystemProvider extends Disposable implements IFileSystemProvider { +export class InMemoryFileSystemProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability { readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.FileReadWrite; readonly onDidChangeCapabilities: Event = Event.None; @@ -205,8 +205,8 @@ export class InMemoryFileSystemProvider extends Disposable implements IFileSyste // --- manage file events - private readonly _onDidChangeFile: Emitter = this._register(new Emitter()); - readonly onDidChangeFile: Event = this._onDidChangeFile.event; + private readonly _onDidChangeFile = this._register(new Emitter()); + readonly onDidChangeFile: Event = this._onDidChangeFile.event; private _bufferedChanges: IFileChange[] = []; private _fireSoonHandle?: any; diff --git a/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts b/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts index e927331f93b..097a3647e24 100644 --- a/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts +++ b/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts @@ -23,6 +23,15 @@ import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/enviro import { Emitter, Event } from 'vs/base/common/event'; import { timeout } from 'vs/base/common/async'; +class TestBrowserWorkbenchEnvironmentService extends BrowserWorkbenchEnvironmentService { + + testUserRoamingDataHome!: URI; + + get userRoamingDataHome(): URI { + return this.testUserRoamingDataHome; + } +} + suite('FileUserDataProvider', () => { let testObject: IFileService; @@ -47,8 +56,8 @@ suite('FileUserDataProvider', () => { userDataResource = URI.file(userDataPath).with({ scheme: Schemas.userData }); await Promise.all([pfs.mkdirp(userDataPath), pfs.mkdirp(backupsPath)]); - const environmentService = new BrowserWorkbenchEnvironmentService({ remoteAuthority: 'remote', workspaceId: 'workspaceId', logsPath: URI.file('logFile') }); - environmentService.userRoamingDataHome = userDataResource; + const environmentService = new TestBrowserWorkbenchEnvironmentService({ remoteAuthority: 'remote', workspaceId: 'workspaceId', logsPath: URI.file('logFile') }); + environmentService.testUserRoamingDataHome = userDataResource; const userDataFileSystemProvider = new FileUserDataProvider(URI.file(userDataPath), URI.file(backupsPath), diskFileSystemProvider, environmentService); disposables.add(userDataFileSystemProvider); @@ -277,7 +286,7 @@ suite('FileUserDataProvider', () => { class TestFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability { - constructor(readonly onDidChangeFile: Event) { } + constructor(readonly onDidChangeFile: Event) { } readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.FileReadWrite; @@ -309,7 +318,7 @@ suite('FileUserDataProvider - Watching', () => { let userDataResource: URI; const disposables = new DisposableStore(); - const fileEventEmitter: Emitter = new Emitter(); + const fileEventEmitter: Emitter = new Emitter(); disposables.add(fileEventEmitter); setup(() => { @@ -321,8 +330,8 @@ suite('FileUserDataProvider - Watching', () => { localUserDataResource = URI.file(userDataPath); userDataResource = localUserDataResource.with({ scheme: Schemas.userData }); - const environmentService = new BrowserWorkbenchEnvironmentService({ remoteAuthority: 'remote', workspaceId: 'workspaceId', logsPath: URI.file('logFile') }); - environmentService.userRoamingDataHome = userDataResource; + const environmentService = new TestBrowserWorkbenchEnvironmentService({ remoteAuthority: 'remote', workspaceId: 'workspaceId', logsPath: URI.file('logFile') }); + environmentService.testUserRoamingDataHome = userDataResource; const userDataFileSystemProvider = new FileUserDataProvider(localUserDataResource, localBackupsResource, new TestFileSystemProvider(fileEventEmitter.event), environmentService); disposables.add(userDataFileSystemProvider); diff --git a/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts b/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts index bed3e19da8a..973a7fd7a68 100644 --- a/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts +++ b/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts @@ -27,20 +27,21 @@ class SettingsMergeService implements ISettingsMergeService { @IModeService private readonly modeService: IModeService, ) { } - async merge(localContent: string, remoteContent: string, baseContent: string | null, ignoredSettings: IStringDictionary): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> { + async merge(localContent: string, remoteContent: string, baseContent: string | null, ignoredSettings: string[]): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> { const local = parse(localContent); const remote = parse(remoteContent); const base = baseContent ? parse(baseContent) : null; + const ignored = ignoredSettings.reduce((set, key) => { set.add(key); return set; }, new Set()); - const localToRemote = this.compare(local, remote, ignoredSettings); + const localToRemote = this.compare(local, remote, ignored); if (localToRemote.added.size === 0 && localToRemote.removed.size === 0 && localToRemote.updated.size === 0) { // No changes found between local and remote. return { mergeContent: localContent, hasChanges: false, hasConflicts: false }; } const conflicts: Set = new Set(); - const baseToLocal = base ? this.compare(base, local, ignoredSettings) : { added: Object.keys(local).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; - const baseToRemote = base ? this.compare(base, remote, ignoredSettings) : { added: Object.keys(remote).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; + const baseToLocal = base ? this.compare(base, local, ignored) : { added: Object.keys(local).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; + const baseToRemote = base ? this.compare(base, remote, ignored) : { added: Object.keys(remote).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; const settingsPreviewModel = this.modelService.createModel(localContent, this.modeService.create('jsonc')); // Removed settings in Local @@ -151,11 +152,12 @@ class SettingsMergeService implements ISettingsMergeService { return { mergeContent: settingsPreviewModel.getValue(), hasChanges: true, hasConflicts: conflicts.size > 0 }; } - async computeRemoteContent(localContent: string, remoteContent: string, ignoredSettings: IStringDictionary): Promise { + async computeRemoteContent(localContent: string, remoteContent: string, ignoredSettings: string[]): Promise { const remote = parse(remoteContent); const remoteModel = this.modelService.createModel(localContent, this.modeService.create('jsonc')); + const ignored = ignoredSettings.reduce((set, key) => { set.add(key); return set; }, new Set()); for (const key of Object.keys(ignoredSettings)) { - if (ignoredSettings[key]) { + if (ignored.has(key)) { this.editSetting(remoteModel, key, undefined); this.editSetting(remoteModel, key, remote[key]); } @@ -180,9 +182,9 @@ class SettingsMergeService implements ISettingsMergeService { } } - private compare(from: IStringDictionary, to: IStringDictionary, ignored: IStringDictionary): { added: Set, removed: Set, updated: Set } { - const fromKeys = Object.keys(from).filter(key => !ignored[key]); - const toKeys = Object.keys(to).filter(key => !ignored[key]); + private compare(from: IStringDictionary, to: IStringDictionary, ignored: Set): { added: Set, removed: Set, updated: Set } { + const fromKeys = Object.keys(from).filter(key => !ignored.has(key)); + const toKeys = Object.keys(to).filter(key => !ignored.has(key)); const added = toKeys.filter(key => fromKeys.indexOf(key) === -1).reduce((r, key) => { r.add(key); return r; }, new Set()); const removed = fromKeys.filter(key => toKeys.indexOf(key) === -1).reduce((r, key) => { r.add(key); return r; }, new Set()); const updated: Set = new Set(); diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts index 05e999ca64a..8a0bf37d888 100644 --- a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SyncStatus, SyncSource, IUserDataSyncService, ISyncExtension } from 'vs/platform/userDataSync/common/userDataSync'; +import { SyncStatus, SyncSource, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter, Event } from 'vs/base/common/event'; @@ -42,8 +42,8 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return this.channel.call('sync', [_continue]); } - getRemoteExtensions(): Promise { - return this.channel.call('getRemoteExtensions'); + stop(): void { + this.channel.call('stop'); } removeExtension(identifier: IExtensionIdentifier): Promise { diff --git a/src/vs/workbench/services/viewlet/browser/viewlet.ts b/src/vs/workbench/services/viewlet/browser/viewlet.ts index ffc1a81d63a..deebb5b8584 100644 --- a/src/vs/workbench/services/viewlet/browser/viewlet.ts +++ b/src/vs/workbench/services/viewlet/browser/viewlet.ts @@ -23,12 +23,12 @@ export interface IViewletService { /** * Opens a viewlet with the given identifier and pass keyboard focus to it if specified. */ - openViewlet(id: string | undefined, focus?: boolean): Promise; + openViewlet(id: string | undefined, focus?: boolean): Promise; /** - * Returns the current active viewlet or null if none. + * Returns the current active viewlet if any. */ - getActiveViewlet(): IViewlet | null; + getActiveViewlet(): IViewlet | undefined; /** * Returns the id of the default viewlet. @@ -48,7 +48,7 @@ export interface IViewletService { /** * Returns the progress indicator for the side bar. */ - getProgressIndicator(id: string): IProgressIndicator | null; + getProgressIndicator(id: string): IProgressIndicator | undefined; /** * 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 deleted file mode 100644 index fd2506c1a93..00000000000 --- a/src/vs/workbench/services/window/electron-browser/windowService.ts +++ /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. - *--------------------------------------------------------------------------------------------*/ - -import { Event } from 'vs/base/common/event'; -import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; -import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; -import { URI } from 'vs/base/common/uri'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; - -export class WindowService extends Disposable implements IWindowService { - - readonly onDidChangeFocus: Event; - readonly onDidChangeMaximize: Event; - - _serviceBrand: undefined; - - private _windowId: number; - - private _hasFocus: boolean; - get hasFocus(): boolean { return this._hasFocus; } - - constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IWindowsService private readonly windowsService: IWindowsService, - ) { - super(); - - this._windowId = environmentService.configuration.windowId; - - const onThisWindowFocus = Event.map(Event.filter(windowsService.onWindowFocus, id => id === this._windowId), _ => true); - const onThisWindowBlur = Event.map(Event.filter(windowsService.onWindowBlur, id => id === this._windowId), _ => false); - const onThisWindowMaximize = Event.map(Event.filter(windowsService.onWindowMaximize, id => id === this._windowId), _ => true); - const onThisWindowUnmaximize = Event.map(Event.filter(windowsService.onWindowUnmaximize, id => id === this._windowId), _ => false); - this.onDidChangeFocus = Event.any(onThisWindowFocus, onThisWindowBlur); - this.onDidChangeMaximize = Event.any(onThisWindowMaximize, onThisWindowUnmaximize); - - this._hasFocus = document.hasFocus(); - this.isFocused().then(focused => this._hasFocus = focused); - this._register(this.onDidChangeFocus(focus => this._hasFocus = focus)); - } - - get windowId(): number { - return this._windowId; - } - - getRecentlyOpened(): Promise { - return this.windowsService.getRecentlyOpened(this.windowId); - } - - addRecentlyOpened(recents: IRecent[]): Promise { - return this.windowsService.addRecentlyOpened(recents); - } - - removeFromRecentlyOpened(paths: URI[]): Promise { - return this.windowsService.removeFromRecentlyOpened(paths); - } - - isFocused(): Promise { - return this.windowsService.isFocused(this.windowId); - } -} - -registerSingleton(IWindowService, WindowService); diff --git a/src/vs/workbench/services/workspace/browser/workspacesService.ts b/src/vs/workbench/services/workspace/browser/workspacesService.ts deleted file mode 100644 index b919b06a94e..00000000000 --- a/src/vs/workbench/services/workspace/browser/workspacesService.ts +++ /dev/null @@ -1,31 +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 { IWorkspacesService, IWorkspaceFolderCreationData, IWorkspaceIdentifier, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces'; -import { URI } from 'vs/base/common/uri'; - -export class WorkspacesService implements IWorkspacesService { - - _serviceBrand: undefined; - - enterWorkspace(path: URI): Promise { - throw new Error('Untitled workspaces are currently unsupported in Web'); - } - - createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { - throw new Error('Untitled workspaces are currently unsupported in Web'); - } - - deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise { - throw new Error('Untitled workspaces are currently unsupported in Web'); - } - - getWorkspaceIdentifier(workspacePath: URI): Promise { - throw new Error('Untitled workspaces are currently unsupported in Web'); - } -} - -registerSingleton(IWorkspacesService, WorkspacesService, true); diff --git a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts deleted file mode 100644 index d4cd7087f34..00000000000 --- a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts +++ /dev/null @@ -1,81 +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 { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { URI } from 'vs/base/common/uri'; -import * as nls from 'vs/nls'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; -import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { isEqual, basename } from 'vs/base/common/resources'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -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 { IHostService } from 'vs/workbench/services/host/browser/host'; -import { WorkspaceEditingService } from 'vs/workbench/services/workspace/browser/workspaceEditingService'; -import { IElectronService } from 'vs/platform/electron/node/electron'; - -export class NativeWorkspaceEditingService extends WorkspaceEditingService { - - _serviceBrand: undefined; - - constructor( - @IJSONEditingService jsonEditingService: IJSONEditingService, - @IWorkspaceContextService contextService: WorkspaceService, - @IElectronService private electronService: IElectronService, - @IConfigurationService configurationService: IConfigurationService, - @IStorageService storageService: IStorageService, - @IExtensionService extensionService: IExtensionService, - @IBackupFileService backupFileService: IBackupFileService, - @INotificationService notificationService: INotificationService, - @ICommandService commandService: ICommandService, - @IFileService fileService: IFileService, - @ITextFileService textFileService: ITextFileService, - @IWindowService windowService: IWindowService, - @IWorkspacesService workspacesService: IWorkspacesService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IFileDialogService fileDialogService: IFileDialogService, - @IDialogService protected dialogService: IDialogService, - @ILifecycleService lifecycleService: ILifecycleService, - @ILabelService labelService: ILabelService, - @IHostService hostService: IHostService - ) { - super(jsonEditingService, contextService, windowService, configurationService, storageService, extensionService, backupFileService, notificationService, commandService, fileService, textFileService, workspacesService, environmentService, fileDialogService, dialogService, lifecycleService, labelService, hostService); - } - - async isValidTargetWorkspacePath(path: URI): Promise { - const windows = await this.electronService.getWindows(); - - // Prevent overwriting a workspace that is currently opened in another window - if (windows.some(window => !!window.workspace && isEqual(window.workspace.configPath, path))) { - await this.dialogService.show( - Severity.Info, - nls.localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", basename(path)), - [nls.localize('ok', "OK")], - { - detail: nls.localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again.") - } - ); - - return false; - } - - return true; // OK - } -} - -registerSingleton(IWorkspaceEditingService, NativeWorkspaceEditingService, true); diff --git a/src/vs/workbench/services/workspace/electron-browser/workspacesService.ts b/src/vs/workbench/services/workspace/electron-browser/workspacesService.ts deleted file mode 100644 index ee5fcb3dc6a..00000000000 --- a/src/vs/workbench/services/workspace/electron-browser/workspacesService.ts +++ /dev/null @@ -1,48 +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 } from 'vs/base/parts/ipc/common/ipc'; -import { IWorkspacesService, IWorkspaceIdentifier, IWorkspaceFolderCreationData, reviveWorkspaceIdentifier, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces'; -import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; -import { URI } from 'vs/base/common/uri'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWindowService } from 'vs/platform/windows/common/windows'; - -export class WorkspacesService implements IWorkspacesService { - - _serviceBrand: undefined; - - private channel: IChannel; - - constructor( - @IMainProcessService mainProcessService: IMainProcessService, - @IWindowService private readonly windowService: IWindowService - ) { - this.channel = mainProcessService.getChannel('workspaces'); - } - - async enterWorkspace(path: URI): Promise { - const result: IEnterWorkspaceResult = await this.channel.call('enterWorkspace', [this.windowService.windowId, path]); - if (result) { - result.workspace = reviveWorkspaceIdentifier(result.workspace); - } - - return result; - } - - createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { - return this.channel.call('createUntitledWorkspace', [folders, remoteAuthority]).then(reviveWorkspaceIdentifier); - } - - deleteUntitledWorkspace(workspaceIdentifier: IWorkspaceIdentifier): Promise { - return this.channel.call('deleteUntitledWorkspace', workspaceIdentifier); - } - - getWorkspaceIdentifier(configPath: URI): Promise { - return this.channel.call('getWorkspaceIdentifier', configPath).then(reviveWorkspaceIdentifier); - } -} - -registerSingleton(IWorkspacesService, WorkspacesService, true); diff --git a/src/vs/workbench/services/workspace/browser/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts similarity index 66% rename from src/vs/workbench/services/workspace/browser/workspaceEditingService.ts rename to src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts index 6e24d0d6f5b..385bf0f57a8 100644 --- a/src/vs/workbench/services/workspace/browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts @@ -3,151 +3,45 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { URI } from 'vs/base/common/uri'; import * as nls from 'vs/nls'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { IJSONEditingService, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesService, rewriteWorkspaceFileForNewLocation, WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesService, rewriteWorkspaceFileForNewLocation, WORKSPACE_FILTER, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces'; import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; -import { IStorageService } from 'vs/platform/storage/common/storage'; 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, 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, isWeb } from 'vs/base/common/platform'; -import { isEqual, isEqualOrParent, getComparisonKey } from 'vs/base/common/resources'; +import { isEqual, getComparisonKey } from 'vs/base/common/resources'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IFileService } from 'vs/platform/files/common/files'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ILabelService } from 'vs/platform/label/common/label'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -export class WorkspaceEditingService implements IWorkspaceEditingService { +export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditingService { _serviceBrand: undefined; constructor( @IJSONEditingService private readonly jsonEditingService: IJSONEditingService, @IWorkspaceContextService private readonly contextService: WorkspaceService, - @IWindowService private readonly windowService: IWindowService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IStorageService private readonly storageService: IStorageService, - @IExtensionService private readonly extensionService: IExtensionService, - @IBackupFileService private readonly backupFileService: IBackupFileService, @INotificationService private readonly notificationService: INotificationService, @ICommandService private readonly commandService: ICommandService, @IFileService private readonly fileService: IFileService, @ITextFileService private readonly textFileService: ITextFileService, - @IWorkspacesService private readonly workspacesService: IWorkspacesService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IWorkspacesService protected readonly workspacesService: IWorkspacesService, + @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService, @IFileDialogService private readonly fileDialogService: IFileDialogService, @IDialogService protected readonly dialogService: IDialogService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, - @ILabelService private readonly labelService: ILabelService, - @IHostService private readonly hostService: IHostService - ) { - this.registerListeners(); - } - - private registerListeners(): void { - this.lifecycleService.onBeforeShutdown(e => { - if (isWeb) { - return; // no support for untitled in web - } - - const saveOperation = this.saveUntitedBeforeShutdown(e.reason); - if (saveOperation) { - e.veto(saveOperation); - } - }); - } - - private async saveUntitedBeforeShutdown(reason: ShutdownReason): Promise { - if (reason !== ShutdownReason.LOAD && reason !== ShutdownReason.CLOSE) { - return false; // only interested when window is closing or loading - } - - const workspaceIdentifier = this.getCurrentWorkspaceIdentifier(); - if (!workspaceIdentifier || !isEqualOrParent(workspaceIdentifier.configPath, this.environmentService.untitledWorkspacesHome)) { - return false; // only care about untitled workspaces to ask for saving - } - - const windowCount = await this.hostService.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 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 { choice } = await this.dialogService.show(Severity.Warning, message, buttons.map(button => button.label), { detail, cancelId }); - - switch (buttons[choice].result) { - - // Cancel: veto unload - case ConfirmResult.CANCEL: - return true; - - // Don't Save: delete workspace - case ConfirmResult.DONT_SAVE: - this.workspacesService.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.workspacesService.getWorkspaceIdentifier(newWorkspacePath); - - const label = this.labelService.getWorkspaceLabel(newWorkspaceIdentifier, { verbose: true }); - this.windowService.addRecentlyOpened([{ label, workspace: newWorkspaceIdentifier }]); - - this.workspacesService.deleteUntitledWorkspace(workspaceIdentifier); - } catch (error) { - // ignore - } - - return false; - } - } - } + @IHostService protected readonly hostService: IHostService + ) { } pickNewWorkspacePath(): Promise { return this.fileDialogService.showSaveDialog({ @@ -226,7 +120,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { // 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."))); + throw new Error(nls.localize('differentSchemeRoots', "Workspace folders from different providers are not allowed in the same workspace.")); } } @@ -320,7 +214,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { return true; // OK } - private async saveWorkspaceAs(workspace: IWorkspaceIdentifier, targetConfigPathURI: URI): Promise { + protected async saveWorkspaceAs(workspace: IWorkspaceIdentifier, targetConfigPathURI: URI): Promise { const configPathURI = workspace.configPath; // Return early if target is same as source @@ -366,7 +260,9 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { ); } - async enterWorkspace(path: URI): Promise { + abstract async enterWorkspace(path: URI): Promise; + + protected async doEnterWorkspace(path: URI): Promise { if (!!this.environmentService.extensionTestsLocationURI) { throw new Error('Entering a new workspace is not possible in tests.'); } @@ -381,34 +277,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const workspaceImpl = this.contextService as WorkspaceService; await workspaceImpl.initialize(workspace); - const result = await this.workspacesService.enterWorkspace(path); - if (result) { - - // Migrate storage to new workspace - await this.migrateStorage(result.workspace); - - // Reinitialize backup service - this.environmentService.configuration.backupPath = result.backupPath; - this.environmentService.configuration.backupWorkspaceResource = result.backupPath ? toBackupWorkspaceResource(result.backupPath, this.environmentService) : undefined; - if (this.backupFileService instanceof BackupFileService) { - this.backupFileService.reinitialize(); - } - } - - // TODO@aeschli: workaround until restarting works - if (this.environmentService.configuration.remoteAuthority) { - this.hostService.reload(); - } - - // Restart the extension host: entering a workspace means a new location for - // storage and potentially a change in the workspace.rootPath property. - else { - this.extensionService.restartExtensionHost(); - } - } - - private migrateStorage(toWorkspace: IWorkspaceIdentifier): Promise { - return this.storageService.migrate(toWorkspace); + return this.workspacesService.enterWorkspace(path); } private migrateWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): Promise { @@ -435,11 +304,12 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { return this.jsonEditingService.write(toWorkspace.configPath, [{ key: 'settings', value: targetWorkspaceConfiguration }], true); } - private getCurrentWorkspaceIdentifier(): IWorkspaceIdentifier | undefined { + protected getCurrentWorkspaceIdentifier(): IWorkspaceIdentifier | undefined { const workspace = this.contextService.getWorkspace(); - if (workspace && workspace.configuration) { + if (workspace?.configuration) { return { id: workspace.id, configPath: workspace.configuration }; } + return undefined; } } diff --git a/src/vs/workbench/services/workspaces/browser/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/browser/workspaceEditingService.ts new file mode 100644 index 00000000000..b1a2011c60e --- /dev/null +++ b/src/vs/workbench/services/workspaces/browser/workspaceEditingService.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { AbstractWorkspaceEditingService } from 'vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { URI } from 'vs/base/common/uri'; + +export class BrowserWorkspaceEditingService extends AbstractWorkspaceEditingService { + + _serviceBrand: undefined; + + constructor( + @IJSONEditingService jsonEditingService: IJSONEditingService, + @IWorkspaceContextService contextService: WorkspaceService, + @IConfigurationService configurationService: IConfigurationService, + @INotificationService notificationService: INotificationService, + @ICommandService commandService: ICommandService, + @IFileService fileService: IFileService, + @ITextFileService textFileService: ITextFileService, + @IWorkspacesService workspacesService: IWorkspacesService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IFileDialogService fileDialogService: IFileDialogService, + @IDialogService dialogService: IDialogService, + @IHostService hostService: IHostService + ) { + super(jsonEditingService, contextService, configurationService, notificationService, commandService, fileService, textFileService, workspacesService, environmentService, fileDialogService, dialogService, hostService); + } + + async enterWorkspace(path: URI): Promise { + const result = await this.doEnterWorkspace(path); + if (result) { + + // Open workspace in same window + await this.hostService.openWindow([{ workspaceUri: path }], { forceReuseWindow: true }); + } + } +} + +registerSingleton(IWorkspaceEditingService, BrowserWorkspaceEditingService, true); diff --git a/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.css b/src/vs/workbench/services/workspaces/browser/workspaces.ts similarity index 50% rename from src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.css rename to src/vs/workbench/services/workspaces/browser/workspaces.ts index 18418887600..9234604c9cb 100644 --- a/src/vs/editor/browser/viewParts/currentLineMarginHighlight/currentLineMarginHighlight.css +++ b/src/vs/workbench/services/workspaces/browser/workspaces.ts @@ -3,14 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-editor .margin-view-overlays .current-line { - display: block; - position: absolute; - left: 0; - top: 0; - box-sizing: border-box; -} +import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { URI } from 'vs/base/common/uri'; +import { hash } from 'vs/base/common/hash'; -.monaco-editor .margin-view-overlays .current-line.current-line-margin.current-line-margin-both { - border-right: 0; -} \ No newline at end of file +export function getWorkspaceIdentifier(workspacePath: URI): IWorkspaceIdentifier { + return { + id: hash(workspacePath.toString()).toString(16), + configPath: workspacePath + }; +} diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/services/workspaces/browser/workspacesService.ts similarity index 50% rename from src/vs/workbench/browser/web.simpleservices.ts rename to src/vs/workbench/services/workspaces/browser/workspacesService.ts index 259c3d7e0da..6fdc7b9a5e6 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/services/workspaces/browser/workspacesService.ts @@ -3,45 +3,51 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from 'vs/base/common/uri'; -import * as browser from 'vs/base/browser/browser'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { Event } from 'vs/base/common/event'; +import { IWorkspacesService, IWorkspaceFolderCreationData, IWorkspaceIdentifier, IEnterWorkspaceResult, IRecentlyOpened, restoreRecentlyOpened, IRecent, isRecentFile, isRecentFolder, toStoreData, IStoredWorkspaceFolder, getStoredWorkspaceFolder, WORKSPACE_EXTENSION, IStoredWorkspace } from 'vs/platform/workspaces/common/workspaces'; +import { URI } from 'vs/base/common/uri'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ILogService } from 'vs/platform/log/common/log'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; -import { IRecentlyOpened, IRecent, isRecentFile, isRecentFolder } from 'vs/platform/history/common/history'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { addDisposableListener, EventType } from 'vs/base/browser/dom'; -import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage'; +import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { joinPath } from 'vs/base/common/resources'; +import { VSBuffer } from 'vs/base/common/buffer'; -//#region Window +export class BrowserWorkspacesService extends Disposable implements IWorkspacesService { -export class SimpleWindowService extends Disposable implements IWindowService { + static readonly RECENTLY_OPENED_KEY = 'recently.opened'; _serviceBrand: undefined; - readonly onDidChangeFocus: Event = Event.None; - readonly onDidChangeMaximize: Event = Event.None; - - readonly hasFocus = true; - - readonly windowId = 0; - - static readonly RECENTLY_OPENED_KEY = 'recently.opened'; + private readonly _onRecentlyOpenedChange: Emitter = this._register(new Emitter()); + readonly onRecentlyOpenedChange: Event = this._onRecentlyOpenedChange.event; constructor( @IStorageService private readonly storageService: IStorageService, @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, @ILogService private readonly logService: ILogService, + @IFileService private readonly fileService: IFileService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { super(); this.addWorkspaceToRecentlyOpened(); + this.registerListeners(); } + private registerListeners(): void { + this._register(this.storageService.onDidChangeStorage(event => { + if (event.key === BrowserWorkspacesService.RECENTLY_OPENED_KEY && event.scope === StorageScope.GLOBAL) { + this._onRecentlyOpenedChange.fire(); + } + })); + } + private addWorkspaceToRecentlyOpened(): void { const workspace = this.workspaceService.getWorkspace(); switch (this.workspaceService.getWorkbenchState()) { @@ -54,30 +60,10 @@ export class SimpleWindowService extends Disposable implements IWindowService { } } - private registerListeners(): void { - this._register(addDisposableListener(document, EventType.FULLSCREEN_CHANGE, () => { - if (document.fullscreenElement || (document).webkitFullscreenElement) { - browser.setFullscreen(true); - } else { - browser.setFullscreen(false); - } - })); - - this._register(addDisposableListener(document, EventType.WK_FULLSCREEN_CHANGE, () => { - if (document.fullscreenElement || (document).webkitFullscreenElement || (document).webkitIsFullScreen) { - browser.setFullscreen(true); - } else { - browser.setFullscreen(false); - } - })); - } - - isFocused(): Promise { - return Promise.resolve(this.hasFocus); - } + //#region Workspaces History async getRecentlyOpened(): Promise { - const recentlyOpenedRaw = this.storageService.get(SimpleWindowService.RECENTLY_OPENED_KEY, StorageScope.GLOBAL); + const recentlyOpenedRaw = this.storageService.get(BrowserWorkspacesService.RECENTLY_OPENED_KEY, StorageScope.GLOBAL); if (recentlyOpenedRaw) { return restoreRecentlyOpened(JSON.parse(recentlyOpenedRaw), this.logService); } @@ -123,50 +109,49 @@ export class SimpleWindowService extends Disposable implements IWindowService { } private async saveRecentlyOpened(data: IRecentlyOpened): Promise { - return this.storageService.store(SimpleWindowService.RECENTLY_OPENED_KEY, JSON.stringify(toStoreData(data)), StorageScope.GLOBAL); + return this.storageService.store(BrowserWorkspacesService.RECENTLY_OPENED_KEY, JSON.stringify(toStoreData(data)), StorageScope.GLOBAL); } + + async clearRecentlyOpened(): Promise { + this.storageService.remove(BrowserWorkspacesService.RECENTLY_OPENED_KEY, StorageScope.GLOBAL); + } + + //#endregion + + //#region Workspace Management + + async enterWorkspace(path: URI): Promise { + return { workspace: await this.getWorkspaceIdentifier(path) }; + } + + async createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { + const randomId = (Date.now() + Math.round(Math.random() * 1000)).toString(); + const newUntitledWorkspacePath = joinPath(this.environmentService.untitledWorkspacesHome, `Untitled-${randomId}.${WORKSPACE_EXTENSION}`); + + // Build array of workspace folders to store + const storedWorkspaceFolder: IStoredWorkspaceFolder[] = []; + if (folders) { + for (const folder of folders) { + storedWorkspaceFolder.push(getStoredWorkspaceFolder(folder.uri, folder.name, this.environmentService.untitledWorkspacesHome)); + } + } + + // Store at untitled workspaces location + const storedWorkspace: IStoredWorkspace = { folders: storedWorkspaceFolder, remoteAuthority }; + await this.fileService.writeFile(newUntitledWorkspacePath, VSBuffer.fromString(JSON.stringify(storedWorkspace, null, '\t'))); + + return this.getWorkspaceIdentifier(newUntitledWorkspacePath); + } + + deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise { + return this.fileService.del(workspace.configPath); + } + + async getWorkspaceIdentifier(workspacePath: URI): Promise { + return getWorkspaceIdentifier(workspacePath); + } + + //#endregion } -registerSingleton(IWindowService, SimpleWindowService); - -//#endregion - -//#region Window - -export class SimpleWindowsService implements IWindowsService { - _serviceBrand: undefined; - - readonly onWindowOpen: Event = Event.None; - readonly onWindowFocus: Event = Event.None; - readonly onWindowBlur: Event = Event.None; - readonly onWindowMaximize: Event = Event.None; - readonly onWindowUnmaximize: Event = Event.None; - readonly onRecentlyOpenedChange: Event = Event.None; - - isFocused(_windowId: number): Promise { - return Promise.resolve(true); - } - - addRecentlyOpened(recents: IRecent[]): Promise { - return Promise.resolve(); - } - - removeFromRecentlyOpened(_paths: URI[]): Promise { - return Promise.resolve(); - } - - clearRecentlyOpened(): Promise { - return Promise.resolve(); - } - - getRecentlyOpened(_windowId: number): Promise { - return Promise.resolve({ - workspaces: [], - files: [] - }); - } -} - -registerSingleton(IWindowsService, SimpleWindowsService); - -//#endregion +registerSingleton(IWorkspacesService, BrowserWorkspacesService, true); diff --git a/src/vs/workbench/services/workspace/common/workspaceEditing.ts b/src/vs/workbench/services/workspaces/common/workspaceEditing.ts similarity index 100% rename from src/vs/workbench/services/workspace/common/workspaceEditing.ts rename to src/vs/workbench/services/workspaces/common/workspaceEditing.ts diff --git a/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts new file mode 100644 index 00000000000..63e66f3a6b5 --- /dev/null +++ b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts @@ -0,0 +1,203 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; +import { URI } from 'vs/base/common/uri'; +import * as nls from 'vs/nls'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; +import { IWorkspacesService, isUntitledWorkspace, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { toBackupWorkspaceResource } from 'vs/workbench/services/backup/electron-browser/backup'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { isEqual, basename } from 'vs/base/common/resources'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +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 { IHostService } from 'vs/workbench/services/host/browser/host'; +import { AbstractWorkspaceEditingService } from 'vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { isMacintosh, isWindows, isLinux } from 'vs/base/common/platform'; +import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { BackupFileService } from 'vs/workbench/services/backup/common/backupFileService'; + +export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingService { + + _serviceBrand: undefined; + + constructor( + @IJSONEditingService jsonEditingService: IJSONEditingService, + @IWorkspaceContextService contextService: WorkspaceService, + @IElectronService private electronService: IElectronService, + @IConfigurationService configurationService: IConfigurationService, + @IStorageService private storageService: IStorageService, + @IExtensionService private extensionService: IExtensionService, + @IBackupFileService private backupFileService: IBackupFileService, + @INotificationService notificationService: INotificationService, + @ICommandService commandService: ICommandService, + @IFileService fileService: IFileService, + @ITextFileService textFileService: ITextFileService, + @IWorkspacesService workspacesService: IWorkspacesService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IFileDialogService fileDialogService: IFileDialogService, + @IDialogService protected dialogService: IDialogService, + @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILabelService private readonly labelService: ILabelService, + @IHostService hostService: IHostService, + ) { + super(jsonEditingService, contextService, configurationService, notificationService, commandService, fileService, textFileService, workspacesService, environmentService, fileDialogService, dialogService, hostService); + + this.registerListeners(); + } + + private registerListeners(): void { + this.lifecycleService.onBeforeShutdown(e => { + const saveOperation = this.saveUntitedBeforeShutdown(e.reason); + if (saveOperation) { + e.veto(saveOperation); + } + }); + } + + private async saveUntitedBeforeShutdown(reason: ShutdownReason): Promise { + if (reason !== ShutdownReason.LOAD && reason !== ShutdownReason.CLOSE) { + return false; // only interested when window is closing or loading + } + + const workspaceIdentifier = this.getCurrentWorkspaceIdentifier(); + if (!workspaceIdentifier || !isUntitledWorkspace(workspaceIdentifier.configPath, this.environmentService)) { + return false; // only care about untitled workspaces to ask for saving + } + + const windowCount = await this.electronService.getWindowCount(); + 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 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 { choice } = await this.dialogService.show(Severity.Warning, message, buttons.map(button => button.label), { detail, cancelId }); + + switch (buttons[choice].result) { + + // Cancel: veto unload + case ConfirmResult.CANCEL: + return true; + + // Don't Save: delete workspace + case ConfirmResult.DONT_SAVE: + this.workspacesService.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.workspacesService.getWorkspaceIdentifier(newWorkspacePath); + + const label = this.labelService.getWorkspaceLabel(newWorkspaceIdentifier, { verbose: true }); + this.workspacesService.addRecentlyOpened([{ label, workspace: newWorkspaceIdentifier }]); + + this.workspacesService.deleteUntitledWorkspace(workspaceIdentifier); + } catch (error) { + // ignore + } + + return false; + } + } + + return false; + } + + async isValidTargetWorkspacePath(path: URI): Promise { + const windows = await this.electronService.getWindows(); + + // Prevent overwriting a workspace that is currently opened in another window + if (windows.some(window => !!window.workspace && isEqual(window.workspace.configPath, path))) { + await this.dialogService.show( + Severity.Info, + nls.localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", basename(path)), + [nls.localize('ok', "OK")], + { + detail: nls.localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again.") + } + ); + + return false; + } + + return true; // OK + } + + async enterWorkspace(path: URI): Promise { + const result = await this.doEnterWorkspace(path); + if (result) { + + // Migrate storage to new workspace + await this.migrateStorage(result.workspace); + + // Reinitialize backup service + this.environmentService.configuration.backupPath = result.backupPath; + this.environmentService.configuration.backupWorkspaceResource = result.backupPath ? toBackupWorkspaceResource(result.backupPath, this.environmentService) : undefined; + if (this.backupFileService instanceof BackupFileService) { + this.backupFileService.reinitialize(); + } + } + + // TODO@aeschli: workaround until restarting works + if (this.environmentService.configuration.remoteAuthority) { + this.hostService.reload(); + } + + // Restart the extension host: entering a workspace means a new location for + // storage and potentially a change in the workspace.rootPath property. + else { + this.extensionService.restartExtensionHost(); + } + } + + private migrateStorage(toWorkspace: IWorkspaceIdentifier): Promise { + return this.storageService.migrate(toWorkspace); + } +} + +registerSingleton(IWorkspaceEditingService, NativeWorkspaceEditingService, true); diff --git a/src/vs/workbench/services/workspaces/electron-browser/workspacesService.ts b/src/vs/workbench/services/workspaces/electron-browser/workspacesService.ts new file mode 100644 index 00000000000..81e178fc33d --- /dev/null +++ b/src/vs/workbench/services/workspaces/electron-browser/workspacesService.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; +import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; + +export class NativeWorkspacesService { + + _serviceBrand: undefined; + + constructor( + @IMainProcessService mainProcessService: IMainProcessService, + @IElectronEnvironmentService electronEnvironmentService: IElectronEnvironmentService + ) { + return createChannelSender(mainProcessService.getChannel('workspaces'), { context: electronEnvironmentService.windowId }); + } +} + +registerSingleton(IWorkspacesService, NativeWorkspacesService, true); diff --git a/src/vs/workbench/test/browser/parts/editor/breadcrumbModel.test.ts b/src/vs/workbench/test/browser/parts/editor/breadcrumbModel.test.ts index 7442fd4fda7..c26f9a10ecf 100644 --- a/src/vs/workbench/test/browser/parts/editor/breadcrumbModel.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/breadcrumbModel.test.ts @@ -29,7 +29,7 @@ suite('Breadcrumb Model', function () { test('only uri, inside workspace', function () { - let model = new EditorBreadcrumbsModel(URI.parse('foo:/bar/baz/ws/some/path/file.ts'), undefined, workspaceService, configService); + let model = new EditorBreadcrumbsModel(URI.parse('foo:/bar/baz/ws/some/path/file.ts'), undefined, configService, workspaceService); let elements = model.getElements(); assert.equal(elements.length, 3); @@ -44,7 +44,7 @@ suite('Breadcrumb Model', function () { test('only uri, outside workspace', function () { - let model = new EditorBreadcrumbsModel(URI.parse('foo:/outside/file.ts'), undefined, workspaceService, configService); + let model = new EditorBreadcrumbsModel(URI.parse('foo:/outside/file.ts'), undefined, configService, workspaceService); let elements = model.getElements(); assert.equal(elements.length, 2); diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index 652994bc809..46805b2c9da 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -112,7 +112,7 @@ class TestFileEditorInput extends EditorInput implements IFileEditorInput { getTypeId() { return 'testFileEditorInputForGroups'; } resolve(): Promise { return Promise.resolve(null!); } setEncoding(encoding: string) { } - getEncoding(): string { return null!; } + getEncoding() { return undefined; } setPreferredEncoding(encoding: string) { } getResource(): URI { return this.resource; } setForceOpenAsBinary(): void { } diff --git a/src/vs/workbench/test/common/notifications.test.ts b/src/vs/workbench/test/common/notifications.test.ts index 4c81c67b61a..b8a5e1b1ee1 100644 --- a/src/vs/workbench/test/common/notifications.test.ts +++ b/src/vs/workbench/test/common/notifications.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; 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 { INotification, Severity, NotificationsFilter } from 'vs/platform/notification/common/notification'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; suite('Notifications', () => { @@ -127,6 +127,19 @@ suite('Notifications', () => { assert.equal(links[2].title, 'Click to execute command \'without.title\''); assert.equal(links[2].length, '[Link 3](command:without.title)'.length); assert.equal(links[2].offset, 'Unable to [Link 1](http://link1.com) open [Link 2](command:open.me "Open This") and '.length); + + // Filter + let item8 = NotificationViewItem.create({ severity: Severity.Error, message: 'Error Message' }, NotificationsFilter.SILENT)!; + assert.equal(item8.silent, true); + + let item9 = NotificationViewItem.create({ severity: Severity.Error, message: 'Error Message' }, NotificationsFilter.OFF)!; + assert.equal(item9.silent, false); + + let item10 = NotificationViewItem.create({ severity: Severity.Error, message: 'Error Message' }, NotificationsFilter.ERROR)!; + assert.equal(item10.silent, false); + + let item11 = NotificationViewItem.create({ severity: Severity.Warning, message: 'Error Message' }, NotificationsFilter.ERROR)!; + assert.equal(item11.silent, true); }); test('Model', () => { 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 c01ed376683..1f9dd15dda5 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -412,11 +412,8 @@ suite('ExtHostLanguageFeatureCommands', function () { assert.equal(values.length, 4); let [first, second, third, fourth] = values; assert.equal(first.label, 'item1'); - assert.equal(first.textEdit!.newText, 'item1'); - assert.equal(first.textEdit!.range.start.line, 0); - assert.equal(first.textEdit!.range.start.character, 0); - assert.equal(first.textEdit!.range.end.line, 0); - assert.equal(first.textEdit!.range.end.character, 4); + assert.equal(first.textEdit, undefined);// no text edit, default ranges + assert.ok(!types.Range.isRange(first.range)); assert.equal(second.label, 'item2'); assert.equal(second.textEdit!.newText, 'foo'); @@ -434,10 +431,13 @@ suite('ExtHostLanguageFeatureCommands', function () { assert.equal(fourth.label, 'item4'); assert.equal(fourth.textEdit, undefined); - assert.equal(fourth.range!.start.line, 0); - assert.equal(fourth.range!.start.character, 1); - assert.equal(fourth.range!.end.line, 0); - assert.equal(fourth.range!.end.character, 4); + + const range: any = fourth.range!; + assert.ok(types.Range.isRange(range)); + assert.equal(range.start.line, 0); + assert.equal(range.start.character, 1); + assert.equal(range.end.line, 0); + assert.equal(range.end.character, 4); assert.ok(fourth.insertText instanceof types.SnippetString); assert.equal((fourth.insertText).value, 'foo$0bar'); }); @@ -856,34 +856,4 @@ suite('ExtHostLanguageFeatureCommands', function () { assert.equal(value.length, 1); assert.ok(value[0].parent); }); - - // --- call hierarcht - - test('Call Hierarchy, back and forth', async function () { - - disposables.push(extHost.registerCallHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.CallHierarchyItemProvider { - provideCallHierarchyIncomingCalls(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult { - return [ - new types.CallHierarchyIncomingCall(new types.CallHierarchyItem(types.SymbolKind.Array, 'IN', '', document.uri, new types.Range(0, 0, 2, 0), new types.Range(0, 0, 2, 0)), [new types.Range(0, 0, 0, 0)]), - ]; - } - provideCallHierarchyOutgoingCalls(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult { - return [ - new types.CallHierarchyOutgoingCall(new types.CallHierarchyItem(types.SymbolKind.Array, 'OUT', '', document.uri, new types.Range(0, 0, 2, 0), new types.Range(0, 0, 2, 0)), [new types.Range(0, 0, 0, 0)]), - ]; - } - })); - - await rpcProtocol.sync(); - - let incoming = await commands.executeCommand('vscode.executeCallHierarchyProviderIncomingCalls', model.uri, new types.Position(0, 10)); - assert.equal(incoming.length, 1); - assert.ok(incoming[0].source instanceof types.CallHierarchyItem); - assert.equal(incoming[0].source.name, 'IN'); - - let outgoing = await commands.executeCommand('vscode.executeCallHierarchyProviderOutgoingCalls', model.uri, new types.Position(0, 10)); - assert.equal(outgoing.length, 1); - assert.ok(outgoing[0].target instanceof types.CallHierarchyItem); - assert.equal(outgoing[0].target.name, 'OUT'); - }); }); 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 c2bfcdd6605..f319881a103 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -20,7 +20,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData suite('ExtHostConfiguration', function () { class RecordingShape extends mock() { - lastArgs: [ConfigurationTarget, string, any]; + lastArgs!: [ConfigurationTarget, string, any]; $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): Promise { this.lastArgs = [target, key, value]; return Promise.resolve(undefined); 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 18ecedc673b..c4d2355e9b4 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -23,10 +23,9 @@ import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocum import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen'; import * as modes from 'vs/editor/common/modes'; import { getCodeLensData } from 'vs/editor/contrib/codelens/codelens'; -import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition } from 'vs/editor/contrib/goToDefinition/goToDefinition'; +import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition, getReferencesAtPosition } from 'vs/editor/contrib/goToDefinition/goToDefinition'; import { getHover } from 'vs/editor/contrib/hover/getHover'; import { getOccurrencesAtPosition } from 'vs/editor/contrib/wordHighlighter/wordHighlighter'; -import { provideReferences } from 'vs/editor/contrib/referenceSearch/referenceSearch'; import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction'; import { getWorkspaceSymbols } from 'vs/workbench/contrib/search/common/search'; import { rename } from 'vs/editor/contrib/rename/rename'; @@ -535,7 +534,7 @@ suite('ExtHostLanguageFeatures', function () { })); await rpcProtocol.sync(); - let value = await provideReferences(model, new EditorPosition(1, 2), CancellationToken.None); + let value = await getReferencesAtPosition(model, new EditorPosition(1, 2), CancellationToken.None); assert.equal(value.length, 2); let [first, second] = value; assert.equal(first.uri.path, '/second'); @@ -551,7 +550,7 @@ suite('ExtHostLanguageFeatures', function () { })); await rpcProtocol.sync(); - let value = await provideReferences(model, new EditorPosition(1, 2), CancellationToken.None); + let value = await getReferencesAtPosition(model, new EditorPosition(1, 2), CancellationToken.None); assert.equal(value.length, 1); let [item] = value; assert.deepEqual(item.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }); @@ -572,7 +571,7 @@ suite('ExtHostLanguageFeatures', function () { })); await rpcProtocol.sync(); - const value = await provideReferences(model, new EditorPosition(1, 2), CancellationToken.None); + const value = await getReferencesAtPosition(model, new EditorPosition(1, 2), CancellationToken.None); assert.equal(value.length, 1); }); 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 b3fe2988ec7..64105b9c089 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts @@ -6,7 +6,7 @@ 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, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions, IStatusMessageOptions, NotificationsFilter } 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 { IDisposable, Disposable } from 'vs/base/common/lifecycle'; @@ -55,6 +55,9 @@ const emptyNotificationService = new class implements INotificationService { status(message: string | Error, options?: IStatusMessageOptions): IDisposable { return Disposable.None; } + setFilter(filter: NotificationsFilter): void { + throw new Error('not implemented.'); + } }; class EmptyNotificationService implements INotificationService { @@ -78,11 +81,14 @@ class EmptyNotificationService implements INotificationService { throw new Error('Method not implemented.'); } prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { - throw new Error('not implemented'); + throw new Error('Method not implemented'); } status(message: string, options?: IStatusMessageOptions): IDisposable { return Disposable.None; } + setFilter(filter: NotificationsFilter): void { + throw new Error('Method not implemented.'); + } } 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 8dff457b408..bf71ebfaf5c 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -28,7 +28,7 @@ const disposables = new DisposableStore(); let mockMainThreadSearch: MockMainThreadSearch; class MockMainThreadSearch implements MainThreadSearchShape { - lastHandle: number; + lastHandle!: number; results: Array = []; diff --git a/src/vs/workbench/test/electron-browser/api/extHostTypeConverter.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTypeConverter.test.ts index 89a32a67959..aac33827faa 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTypeConverter.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTypeConverter.test.ts @@ -7,9 +7,10 @@ import * as assert from 'assert'; import { MarkdownString, LogLevel } from 'vs/workbench/api/common/extHostTypeConverters'; import { isEmptyObject } from 'vs/base/common/types'; -import { size } from 'vs/base/common/collections'; +import { size, forEach } from 'vs/base/common/collections'; import * as types from 'vs/workbench/api/common/extHostTypes'; import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log'; +import { URI } from 'vs/base/common/uri'; suite('ExtHostTypeConverter', function () { @@ -59,6 +60,20 @@ suite('ExtHostTypeConverter', function () { assert.ok(!!data.uris!['file:///somepath/here2']); }); + test('NPM script explorer running a script from the hover does not work #65561', function () { + + let data = MarkdownString.from('*hello* [click](command:npm.runScriptFromHover?%7B%22documentUri%22%3A%7B%22%24mid%22%3A1%2C%22external%22%3A%22file%3A%2F%2F%2Fc%253A%2Ffoo%2Fbaz.ex%22%2C%22path%22%3A%22%2Fc%3A%2Ffoo%2Fbaz.ex%22%2C%22scheme%22%3A%22file%22%7D%2C%22script%22%3A%22dev%22%7D)'); + // assert that both uri get extracted but that the latter is only decoded once... + assert.equal(size(data.uris!), 2); + forEach(data.uris!, entry => { + if (entry.value.scheme === 'file') { + assert.ok(URI.revive(entry.value).toString().indexOf('file:///c%3A') === 0); + } else { + assert.equal(entry.value.scheme, 'command'); + } + }); + }); + test('LogLevel', () => { assert.equal(LogLevel.from(types.LogLevel.Error), _MainLogLevel.Error); assert.equal(LogLevel.from(types.LogLevel.Info), _MainLogLevel.Info); 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 fb75ee14a20..37a88c04dcc 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts @@ -11,6 +11,7 @@ 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'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; suite('ExtHostWebview', () => { @@ -18,7 +19,11 @@ suite('ExtHostWebview', () => { const viewType = 'view.type'; const shape = createNoopMainThreadWebviews(); - const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { webviewCspSource: '', webviewResourceRoot: '' }); + const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { + webviewCspSource: '', + webviewResourceRoot: '', + isExtensionDevelopmentDebug: false, + }, undefined); let lastInvokedDeserializer: vscode.WebviewPanelSerializer | undefined = undefined; @@ -28,21 +33,23 @@ suite('ExtHostWebview', () => { } } + const extension = {} as IExtensionDescription; + const serializerA = new NoopSerializer(); const serializerB = new NoopSerializer(); - const serializerARegistration = extHostWebviews.registerWebviewPanelSerializer(viewType, serializerA); + const serializerARegistration = extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializerA); await extHostWebviews.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {}); assert.strictEqual(lastInvokedDeserializer, serializerA); assert.throws( - () => extHostWebviews.registerWebviewPanelSerializer(viewType, serializerB), + () => extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializerB), 'Should throw when registering two serializers for the same view'); serializerARegistration.dispose(); - extHostWebviews.registerWebviewPanelSerializer(viewType, serializerB); + extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializerB); await extHostWebviews.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {}); assert.strictEqual(lastInvokedDeserializer, serializerB); @@ -52,37 +59,38 @@ suite('ExtHostWebview', () => { const shape = createNoopMainThreadWebviews(); const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { webviewCspSource: '', - webviewResourceRoot: 'vscode-resource:{{resource}}' - }); + webviewResourceRoot: 'vscode-resource://{{resource}}', + isExtensionDevelopmentDebug: false, + }, undefined); const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); assert.strictEqual( webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html')).toString(), - 'vscode-resource:/Users/codey/file.html', + 'vscode-resource://file///Users/codey/file.html', 'Unix basic' ); assert.strictEqual( webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html#frag')).toString(), - 'vscode-resource:/Users/codey/file.html#frag', + 'vscode-resource://file///Users/codey/file.html#frag', 'Unix should preserve fragment' ); assert.strictEqual( webview.webview.asWebviewUri(URI.parse('file:///Users/codey/f%20ile.html')).toString(), - 'vscode-resource:/Users/codey/f%20ile.html', + 'vscode-resource://file///Users/codey/f%20ile.html', 'Unix with encoding' ); assert.strictEqual( webview.webview.asWebviewUri(URI.parse('file://localhost/Users/codey/file.html')).toString(), - 'vscode-resource://localhost/Users/codey/file.html', + 'vscode-resource://file//localhost/Users/codey/file.html', 'Unix should preserve authority' ); assert.strictEqual( webview.webview.asWebviewUri(URI.parse('file:///c:/codey/file.txt')).toString(), - 'vscode-resource:/c%3A/codey/file.txt', + 'vscode-resource://file///c%3A/codey/file.txt', 'Windows C drive' ); }); @@ -92,8 +100,9 @@ suite('ExtHostWebview', () => { const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { webviewCspSource: '', - webviewResourceRoot: `https://{{uuid}}.webview.contoso.com/commit{{resource}}` - }); + webviewResourceRoot: `https://{{uuid}}.webview.contoso.com/commit/{{resource}}`, + isExtensionDevelopmentDebug: false, + }, undefined); const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); function stripEndpointUuid(input: string) { @@ -102,31 +111,31 @@ suite('ExtHostWebview', () => { assert.strictEqual( stripEndpointUuid(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html')).toString()), - 'webview.contoso.com/commit///Users/codey/file.html', + 'webview.contoso.com/commit/file///Users/codey/file.html', 'Unix basic' ); assert.strictEqual( stripEndpointUuid(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html#frag')).toString()), - 'webview.contoso.com/commit///Users/codey/file.html#frag', + 'webview.contoso.com/commit/file///Users/codey/file.html#frag', 'Unix should preserve fragment' ); assert.strictEqual( stripEndpointUuid(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/f%20ile.html')).toString()), - 'webview.contoso.com/commit///Users/codey/f%20ile.html', + 'webview.contoso.com/commit/file///Users/codey/f%20ile.html', 'Unix with encoding' ); assert.strictEqual( stripEndpointUuid(webview.webview.asWebviewUri(URI.parse('file://localhost/Users/codey/file.html')).toString()), - 'webview.contoso.com/commit//localhost/Users/codey/file.html', + 'webview.contoso.com/commit/file//localhost/Users/codey/file.html', 'Unix should preserve authority' ); assert.strictEqual( stripEndpointUuid(webview.webview.asWebviewUri(URI.parse('file:///c:/codey/file.txt')).toString()), - 'webview.contoso.com/commit///c%3A/codey/file.txt', + 'webview.contoso.com/commit/file///c%3A/codey/file.txt', 'Windows C drive' ); }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts index aa5453e5f6c..483d634e6ea 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts @@ -79,7 +79,7 @@ suite('MainThreadDocumentsAndEditors', () => { onDidPanelOpen = Event.None; onDidPanelClose = Event.None; getActivePanel() { - return null; + return undefined; } }, TestEnvironmentService 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 bd1397d06fb..35fde4c61de 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts @@ -111,7 +111,7 @@ suite('MainThreadEditors', () => { onDidPanelOpen = Event.None; onDidPanelClose = Event.None; getActivePanel() { - return null; + return undefined; } }, TestEnvironmentService diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 36457a11aed..2fab94fd260 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -8,7 +8,7 @@ import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileE import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { join } from 'vs/base/common/path'; import * as resources from 'vs/base/common/resources'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { ConfirmResult, IEditorInputWithOptions, CloseDirection, IEditorIdentifier, IUntitledResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInput, IEditor, IEditorCloseEvent, IEditorPartOptions } from 'vs/workbench/common/editor'; @@ -35,14 +35,13 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -import { IWindowsService, IWindowService, MenuBarVisibility, IWindowConfiguration, IWindowOpenable, IOpenInWindowOptions, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { MenuBarVisibility, IWindowConfiguration, IWindowOpenable, IOpenWindowOptions, IOpenEmptyWindowOptions, IOpenedWindow } 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 { 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'; -import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { IPosition, Position as EditorPosition } from 'vs/editor/common/core/position'; import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; @@ -80,19 +79,25 @@ import { IPanel } from 'vs/workbench/common/panel'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; import { NativeTextFileService } from 'vs/workbench/services/textfile/electron-browser/nativeTextFileService'; import { Schemas } from 'vs/base/common/network'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; +import { IBackupMainService, IWorkspaceBackupInfo } from 'vs/platform/backup/electron-main/backup'; +import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { find } from 'vs/base/common/arrays'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); } -export const TestEnvironmentService = new WorkbenchEnvironmentService(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath); +export const TestEnvironmentService = new NativeWorkbenchEnvironmentService(parseArgs(process.argv, OPTIONS) as IWindowConfiguration, process.execPath, 0); export class TestContextService implements IWorkspaceContextService { public _serviceBrand: undefined; @@ -182,11 +187,11 @@ export class TestContextService implements IWorkspaceContextService { } export class TestTextFileService extends NativeTextFileService { - public cleanupBackupsBeforeShutdownCalled: boolean; + public cleanupBackupsBeforeShutdownCalled!: boolean; - private promptPath: URI; - private confirmResult: ConfirmResult; - private resolveTextContentError: FileOperationError | null; + private promptPath!: URI; + private confirmResult!: ConfirmResult; + private resolveTextContentError!: FileOperationError | null; constructor( @IWorkspaceContextService contextService: IWorkspaceContextService, @@ -200,13 +205,14 @@ export class TestTextFileService extends NativeTextFileService { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, - @IHostService hostService: IHostService, @IHistoryService historyService: IHistoryService, @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @IEditorService editorService: IEditorService, - @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, + @IElectronService electronService: IElectronService, + @IProductService productService: IProductService ) { super( contextService, @@ -220,13 +226,14 @@ export class TestTextFileService extends NativeTextFileService { environmentService, notificationService, backupFileService, - hostService, historyService, contextKeyService, dialogService, fileDialogService, editorService, - textResourceConfigurationService + textResourceConfigurationService, + electronService, + productService ); } @@ -297,6 +304,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); instantiationService.stub(IWorkbenchLayoutService, new TestLayoutService()); + instantiationService.stub(IElectronService, new TestElectronService()); instantiationService.stub(IModeService, instantiationService.createInstance(ModeServiceImpl)); instantiationService.stub(IHistoryService, new TestHistoryService()); instantiationService.stub(ITextResourcePropertiesService, new TestTextResourcePropertiesService(configService)); @@ -306,12 +314,10 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(INotificationService, new TestNotificationService()); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); - instantiationService.stub(IWindowService, new TestWindowService()); instantiationService.stub(IMenuService, new TestMenuService()); instantiationService.stub(IKeybindingService, new MockKeybindingService()); instantiationService.stub(IDecorationsService, new TestDecorationsService()); instantiationService.stub(IExtensionService, new TestExtensionService()); - instantiationService.stub(IWindowsService, new TestWindowsService()); instantiationService.stub(IHostService, instantiationService.createInstance(TestHostService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); @@ -458,15 +464,11 @@ export class TestLayoutService implements IWorkbenchLayoutService { onCenteredLayoutChange: Event = Event.None; onFullscreenChange: Event = Event.None; onPanelPositionChange: Event = Event.None; + onPartVisibilityChange: Event = Event.None; onLayout = Event.None; - private readonly _onTitleBarVisibilityChange = new Emitter(); private readonly _onMenubarVisibilityChange = new Emitter(); - public get onTitleBarVisibilityChange(): Event { - return this._onTitleBarVisibilityChange.event; - } - public get onMenubarVisibilityChange(): Event { return this._onMenubarVisibilityChange.event; } @@ -479,6 +481,14 @@ export class TestLayoutService implements IWorkbenchLayoutService { return false; } + public hasWindowBorder(): boolean { + return false; + } + + public getWindowBorderRadius(): string | undefined { + return undefined; + } + public isVisible(_part: Parts): boolean { return true; } @@ -579,8 +589,8 @@ export class TestViewletService implements IViewletService { onDidViewletOpen = this.onDidViewletOpenEmitter.event; onDidViewletClose = this.onDidViewletCloseEmitter.event; - public openViewlet(id: string, focus?: boolean): Promise { - return Promise.resolve(null!); + public openViewlet(id: string, focus?: boolean): Promise { + return Promise.resolve(undefined); } public getViewlets(): ViewletDescriptor[] { @@ -607,7 +617,7 @@ export class TestViewletService implements IViewletService { } public getProgressIndicator(id: string) { - return null!; + return undefined; } public hideActiveViewlet(): void { } @@ -623,19 +633,19 @@ export class TestPanelService implements IPanelService { onDidPanelOpen = new Emitter<{ panel: IPanel, focus: boolean }>().event; onDidPanelClose = new Emitter().event; - public openPanel(id: string, focus?: boolean): IPanel { - return null!; + public openPanel(id: string, focus?: boolean): undefined { + return undefined; } public getPanel(id: string): any { return activeViewlet; } - public getPanels(): any[] { + public getPanels() { return []; } - public getPinnedPanels(): any[] { + public getPinnedPanels() { return []; } @@ -697,14 +707,8 @@ export class TestEditorGroupsService implements IEditorGroupsService { return this.groups; } - getGroup(identifier: number): IEditorGroup { - for (const group of this.groups) { - if (group.id === identifier) { - return group; - } - } - - return undefined!; + getGroup(identifier: number): IEditorGroup | undefined { + return find(this.groups, group => group.id === identifier); } getLabel(_identifier: number): string { @@ -759,7 +763,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { return false; } - partOptions: IEditorPartOptions; + partOptions!: IEditorPartOptions; enforcePartOptions(options: IEditorPartOptions): IDisposable { return Disposable.None; } @@ -770,20 +774,20 @@ export class TestEditorGroup implements IEditorGroupView { constructor(public id: number) { } get group(): EditorGroup { throw new Error('not implemented'); } - activeControl: IVisibleEditor; - activeEditor: IEditorInput; - previewEditor: IEditorInput; - count: number; - disposed: boolean; + activeControl!: IVisibleEditor; + activeEditor!: IEditorInput; + previewEditor!: IEditorInput; + count!: number; + disposed!: boolean; editors: ReadonlyArray = []; - label: string; - index: number; + label!: string; + index!: number; whenRestored: Promise = Promise.resolve(undefined); - element: HTMLElement; - minimumWidth: number; - maximumWidth: number; - minimumHeight: number; - maximumHeight: number; + element!: HTMLElement; + minimumWidth!: number; + maximumWidth!: number; + minimumHeight!: number; + maximumHeight!: number; isEmpty = true; isMinimized = false; @@ -874,9 +878,9 @@ export class TestEditorService implements EditorServiceImpl { onDidCloseEditor: Event = Event.None; onDidOpenEditorFail: Event = Event.None; - activeControl: IVisibleEditor; + activeControl!: IVisibleEditor; activeTextEditorWidget: any; - activeEditor: IEditorInput; + activeEditor!: IEditorInput; editors: ReadonlyArray = []; visibleControls: ReadonlyArray = []; visibleTextEditorWidgets = []; @@ -926,7 +930,7 @@ export class TestFileService implements IFileService { readonly onError: Event = Event.None; private content = 'Hello Html'; - private lastReadFileUri: URI; + private lastReadFileUri!: URI; constructor() { this._onFileChanges = new Emitter(); @@ -1167,53 +1171,22 @@ export class TestCodeEditorService implements ICodeEditorService { addDiffEditor(_editor: IDiffEditor): void { } removeDiffEditor(_editor: IDiffEditor): void { } listDiffEditors(): IDiffEditor[] { return []; } - getFocusedCodeEditor(): ICodeEditor | undefined { return undefined; } + getFocusedCodeEditor(): ICodeEditor | null { return null; } registerDecorationType(_key: string, _options: IDecorationRenderOptions, _parentTypeKey?: string): void { } removeDecorationType(_key: string): void { } resolveDecorationOptions(_typeKey: string, _writable: boolean): IModelDecorationOptions { return Object.create(null); } setTransientModelProperty(_model: ITextModel, _key: string, _value: any): void { } getTransientModelProperty(_model: ITextModel, _key: string) { } - getActiveCodeEditor(): ICodeEditor | undefined { return undefined; } - openCodeEditor(_input: IResourceInput, _source: ICodeEditor, _sideBySide?: boolean): Promise { return Promise.resolve(undefined); } -} - -export class TestWindowService implements IWindowService { - - public _serviceBrand: undefined; - - onDidChangeFocus: Event = new Emitter().event; - onDidChangeMaximize: Event; - - hasFocus = true; - - readonly windowId = 0; - - isFocused(): Promise { - return Promise.resolve(false); - } - - getRecentlyOpened(): Promise { - return Promise.resolve({ - workspaces: [], - files: [] - }); - } - - addRecentlyOpened(_recents: IRecent[]): Promise { - return Promise.resolve(); - } - - removeFromRecentlyOpened(_paths: URI[]): Promise { - return Promise.resolve(); - } + getActiveCodeEditor(): ICodeEditor | null { return null; } + openCodeEditor(_input: IResourceInput, _source: ICodeEditor, _sideBySide?: boolean): Promise { return Promise.resolve(null); } } export class TestLifecycleService implements ILifecycleService { public _serviceBrand: undefined; - public phase: LifecyclePhase; - public startupKind: StartupKind; + public phase!: LifecyclePhase; + public startupKind!: StartupKind; private readonly _onBeforeShutdown = new Emitter(); private readonly _onWillShutdown = new Emitter(); @@ -1247,41 +1220,6 @@ export class TestLifecycleService implements ILifecycleService { } } -export class TestWindowsService implements IWindowsService { - - _serviceBrand: undefined; - - readonly onWindowOpen: Event = Event.None; - readonly onWindowFocus: Event = Event.None; - readonly onWindowBlur: Event = Event.None; - readonly onWindowMaximize: Event = Event.None; - readonly onWindowUnmaximize: Event = Event.None; - readonly onRecentlyOpenedChange: Event = Event.None; - - isFocused(_windowId: number): Promise { - return Promise.resolve(false); - } - - addRecentlyOpened(_recents: IRecent[]): Promise { - return Promise.resolve(); - } - - removeFromRecentlyOpened(_paths: URI[]): Promise { - return Promise.resolve(); - } - - clearRecentlyOpened(): Promise { - return Promise.resolve(); - } - - getRecentlyOpened(_windowId: number): Promise { - return Promise.resolve({ - workspaces: [], - files: [] - }); - } -} - export class TestTextResourceConfigurationService implements ITextResourceConfigurationService { _serviceBrand: undefined; @@ -1309,12 +1247,10 @@ export class TestTextResourcePropertiesService implements ITextResourcePropertie ) { } - getEOL(resource: URI): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files'); - if (filesConfiguration && filesConfiguration.eol) { - if (filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; - } + getEOL(resource: URI, language?: string): string { + const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource }); + if (eol && eol !== 'auto') { + return eol; } return (isLinux || isMacintosh) ? '\n' : '\r\n'; } @@ -1342,7 +1278,12 @@ export class RemoteFileSystemProvider implements IFileSystemProvider { readonly capabilities: FileSystemProviderCapabilities = this.diskFileSystemProvider.capabilities; readonly onDidChangeCapabilities: Event = this.diskFileSystemProvider.onDidChangeCapabilities; - readonly onDidChangeFile: Event = Event.map(this.diskFileSystemProvider.onDidChangeFile, changes => changes.map(c => { c.resource = c.resource.with({ scheme: Schemas.vscodeRemote, authority: this.remoteAuthority }); return c; })); + readonly onDidChangeFile: Event = Event.map(this.diskFileSystemProvider.onDidChangeFile, changes => changes.map((c): IFileChange => { + return { + type: c.type, + resource: c.resource.with({ scheme: Schemas.vscodeRemote, authority: this.remoteAuthority }), + }; + })); watch(resource: URI, opts: IWatchOptions): IDisposable { return this.diskFileSystemProvider.watch(this.toFileResource(resource), opts); } stat(resource: URI): Promise { return this.diskFileSystemProvider.stat(this.toFileResource(resource)); } @@ -1370,16 +1311,148 @@ export class TestHostService implements IHostService { _serviceBrand: undefined; - windowCount = Promise.resolve(1); + readonly hasFocus: boolean = true; + readonly onDidChangeFocus: Event = Event.None; async restart(): Promise { } async reload(): Promise { } - async closeWorkspace(): Promise { } async focus(): Promise { } - async openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { } - async openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise { } + async openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { } async toggleFullScreen(): Promise { } } + +export class TestElectronService implements IElectronService { + _serviceBrand: undefined; + + onWindowOpen: Event = Event.None; + onWindowMaximize: Event = Event.None; + onWindowUnmaximize: Event = Event.None; + onWindowFocus: Event = Event.None; + onWindowBlur: Event = Event.None; + + windowCount = Promise.resolve(1); + getWindowCount(): Promise { return this.windowCount; } + + async getWindows(): Promise { return []; } + async getActiveWindowId(): Promise { return undefined; } + + openWindow(options?: IOpenEmptyWindowOptions): Promise; + openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; + openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { + throw new Error('Method not implemented.'); + } + + async toggleFullScreen(): Promise { } + async handleTitleDoubleClick(): Promise { } + async isMaximized(): Promise { return true; } + async maximizeWindow(): Promise { } + async unmaximizeWindow(): Promise { } + async minimizeWindow(): Promise { } + async isWindowFocused(): Promise { return true; } + async focusWindow(options?: { windowId?: number | undefined; } | undefined): Promise { } + async showMessageBox(options: Electron.MessageBoxOptions): Promise { throw new Error('Method not implemented.'); } + async showSaveDialog(options: Electron.SaveDialogOptions): Promise { throw new Error('Method not implemented.'); } + async showOpenDialog(options: Electron.OpenDialogOptions): Promise { throw new Error('Method not implemented.'); } + async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise { } + async pickFileAndOpen(options: INativeOpenDialogOptions): Promise { } + async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise { } + async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise { } + async showItemInFolder(path: string): Promise { } + async setRepresentedFilename(path: string): Promise { } + async setDocumentEdited(edited: boolean): Promise { } + async openExternal(url: string): Promise { return false; } + async updateTouchBar(items: { id: string; title: string | { value: string; original: string; }; category?: string | { value: string; original: string; } | undefined; iconLocation?: { dark: UriComponents; light?: { readonly scheme: string; readonly authority: string; readonly path: string; readonly query: string; readonly fragment: string; readonly fsPath: string; with: {}; toString: {}; toJSON: {}; } | undefined; } | undefined; precondition?: { getType: {}; equals: {}; evaluate: {}; serialize: {}; keys: {}; map: {}; negate: {}; } | undefined; toggled?: { getType: {}; equals: {}; evaluate: {}; serialize: {}; keys: {}; map: {}; negate: {}; } | undefined; }[][]): Promise { } + async newWindowTab(): Promise { } + async showPreviousWindowTab(): Promise { } + async showNextWindowTab(): Promise { } + async moveWindowTabToNewWindow(): Promise { } + async mergeAllWindowTabs(): Promise { } + async toggleWindowTabsBar(): Promise { } + async relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined; } | undefined): Promise { } + async reload(): Promise { } + async closeWindow(): Promise { } + async quit(): Promise { } + async openDevTools(options?: Electron.OpenDevToolsOptions | undefined): Promise { } + async toggleDevTools(): Promise { } + async startCrashReporter(options: Electron.CrashReporterStartOptions): Promise { } + async resolveProxy(url: string): Promise { return undefined; } +} + +export class TestBackupMainService implements IBackupMainService { + _serviceBrand: undefined; + + isHotExitEnabled(): boolean { + throw new Error('Method not implemented.'); + } + + getWorkspaceBackups(): IWorkspaceBackupInfo[] { + throw new Error('Method not implemented.'); + } + + getFolderBackupPaths(): URI[] { + throw new Error('Method not implemented.'); + } + + getEmptyWindowBackupPaths(): IEmptyWindowBackupInfo[] { + throw new Error('Method not implemented.'); + } + + registerWorkspaceBackupSync(workspace: IWorkspaceBackupInfo, migrateFrom?: string | undefined): string { + throw new Error('Method not implemented.'); + } + + registerFolderBackupSync(folderUri: URI): string { + throw new Error('Method not implemented.'); + } + + registerEmptyWindowBackupSync(backupFolder?: string | undefined, remoteAuthority?: string | undefined): string { + throw new Error('Method not implemented.'); + } + + unregisterWorkspaceBackupSync(workspace: IWorkspaceIdentifier): void { + throw new Error('Method not implemented.'); + } + + unregisterFolderBackupSync(folderUri: URI): void { + throw new Error('Method not implemented.'); + } + + unregisterEmptyWindowBackupSync(backupFolder: string): void { + throw new Error('Method not implemented.'); + } +} + +export class TestDialogMainService implements IDialogMainService { + _serviceBrand: undefined; + + pickFileFolder(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + pickFolder(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + pickFile(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + pickWorkspace(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + showMessageBox(options: Electron.MessageBoxOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + showSaveDialog(options: Electron.SaveDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + showOpenDialog(options: Electron.OpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } +} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index b6a1c8d8577..8a48a4c1528 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -15,6 +15,7 @@ import 'vs/workbench/browser/workbench.contribution'; //#region --- workbench actions +import 'vs/workbench/browser/actions/textInputActions'; import 'vs/workbench/browser/actions/developerActions'; import 'vs/workbench/browser/actions/helpActions'; import 'vs/workbench/browser/actions/layoutActions'; @@ -79,7 +80,7 @@ import 'vs/workbench/services/extensionManagement/common/extensionEnablementServ import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/extensions/common/staticExtensions'; import 'vs/workbench/services/userDataSync/common/settingsMergeService'; -import 'vs/workbench/services/workspace/browser/workspaceEditingService'; +import 'vs/workbench/services/path/common/remotePathService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; @@ -124,9 +125,6 @@ registerSingleton(IOpenerService, OpenerService, true); //#region --- workbench contributions -// Workspace File Watching -import 'vs/workbench/services/files/common/workspaceWatcher'; - // Telemetry import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution'; @@ -239,7 +237,6 @@ import 'vs/workbench/contrib/surveys/browser/languageSurveys.contribution'; import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; import 'vs/workbench/contrib/welcome/page/browser/welcomePage.contribution'; import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; -import 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution'; // Call Hierarchy import 'vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution'; diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index a1e46ccee59..460c38ba63a 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -31,7 +31,7 @@ import 'vs/workbench/services/dialogs/electron-browser/fileDialogService'; import 'vs/workbench/services/integrity/node/integrityService'; import 'vs/workbench/services/textMate/electron-browser/textMateService'; import 'vs/workbench/services/search/node/searchService'; -import 'vs/workbench/services/output/node/outputChannelModelService'; +import 'vs/workbench/services/output/electron-browser/outputChannelModelService'; import 'vs/workbench/services/textfile/electron-browser/nativeTextFileService'; import 'vs/workbench/services/dialogs/electron-browser/dialogService'; import 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; @@ -40,51 +40,34 @@ import 'vs/workbench/services/extensions/electron-browser/extensionService'; import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; import 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService'; import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; -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 'vs/workbench/services/extensionManagement/node/extensionManagementService'; import 'vs/workbench/services/accessibility/node/accessibilityService'; import 'vs/workbench/services/remote/node/tunnelService'; import 'vs/workbench/services/backup/node/backupFileService'; -import 'vs/workbench/services/credentials/node/credentialsService'; import 'vs/workbench/services/url/electron-browser/urlService'; -import 'vs/workbench/services/workspace/electron-browser/workspacesService'; +import 'vs/workbench/services/workspaces/electron-browser/workspacesService'; +import 'vs/workbench/services/workspaces/electron-browser/workspaceEditingService'; import 'vs/workbench/services/userDataSync/electron-browser/userDataSyncService'; +import 'vs/workbench/services/authToken/electron-browser/authTokenService'; import 'vs/workbench/services/host/electron-browser/desktopHostService'; import 'vs/workbench/services/request/electron-browser/requestService'; +import 'vs/workbench/services/lifecycle/electron-browser/lifecycleService'; +import 'vs/workbench/services/sharedProcess/electron-browser/sharedProcessService'; +import 'vs/workbench/services/electron/electron-browser/electronService'; +import 'vs/workbench/services/localizations/electron-browser/localizationsService'; +import 'vs/workbench/services/clipboard/electron-browser/clipboardService'; +import 'vs/workbench/services/update/electron-browser/updateService'; +import 'vs/workbench/services/issue/electron-browser/issueService'; +import 'vs/workbench/services/menubar/electron-browser/menubarService'; +import 'vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; -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 { 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/node/issue'; -import { IssueService } from 'vs/platform/issue/electron-browser/issueService'; -import { IMenubarService } from 'vs/platform/menubar/node/menubar'; -import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService'; -import { IElectronService } from 'vs/platform/electron/node/electron'; -import { ElectronService } from 'vs/platform/electron/electron-browser/electronService'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { NativeWorkspaceEditingService } from 'vs/workbench/services/workspace/electron-browser/workspaceEditingService'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; +import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService'; -registerSingleton(IClipboardService, ClipboardService, true); -registerSingleton(ILifecycleService, LifecycleService); -registerSingleton(ILocalizationsService, LocalizationsService); -registerSingleton(ISharedProcessService, SharedProcessService, true); -registerSingleton(IWindowsService, WindowsService); -registerSingleton(IUpdateService, UpdateService); -registerSingleton(IIssueService, IssueService); -registerSingleton(IMenubarService, MenubarService); -registerSingleton(IElectronService, ElectronService, true); -registerSingleton(IWorkspaceEditingService, NativeWorkspaceEditingService, true); +registerSingleton(ICredentialsService, KeytarCredentialsService, true); //#endregion @@ -130,9 +113,6 @@ import 'vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution // Execution import 'vs/workbench/contrib/externalTerminal/node/externalTerminalService'; -// Update -import 'vs/workbench/contrib/update/electron-browser/update.contribution'; - // Performance import 'vs/workbench/contrib/performance/electron-browser/performance.contribution'; @@ -151,7 +131,10 @@ import 'vs/workbench/contrib/tasks/electron-browser/taskService'; // User Data Sync import 'vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution'; -// Welcome -import 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution'; +// Telemetry Opt Out +import 'vs/workbench/contrib/welcome/telemetryOptOut/electron-browser/telemetryOptOut.contribution'; + +// Configuration Exporter +import 'vs/workbench/contrib/configExporter/node/configurationExportHelper.contribution'; //#endregion diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index 38bb092333d..8d5a72ae332 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -15,6 +15,7 @@ import { LogLevel } from 'vs/platform/log/common/log'; import { IUpdateProvider, IUpdate } from 'vs/workbench/services/update/browser/updateService'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { IWorkspaceProvider, IWorkspace } from 'vs/workbench/services/host/browser/browserHostService'; interface IWorkbenchConstructionOptions { @@ -36,14 +37,9 @@ interface IWorkbenchConstructionOptions { webviewEndpoint?: string; /** - * Experimental: An optional folder that is set as workspace context for the workbench. + * Experimental: a handler for opening workspaces and providing the initial workspace. */ - folderUri?: URI; - - /** - * Experimental: An optional workspace that is set as workspace context for the workbench. - */ - workspaceUri?: URI; + workspaceProvider?: IWorkspaceProvider; /** * Experimental: The userDataProvider is used to handle user specific application @@ -91,6 +87,11 @@ interface IWorkbenchConstructionOptions { */ updateProvider?: IUpdateProvider; + /** + * Experimental: Support adding additional properties to telemetry. + */ + resolveCommonTelemetryProperties?: () => { [key: string]: any }; + /** * Experimental: Resolves an external uri before it is opened. */ @@ -121,6 +122,10 @@ export { IDisposable, Disposable, + // Workspace + IWorkspace, + IWorkspaceProvider, + // FileSystem IFileSystemProvider, FileSystemProviderCapabilities, @@ -145,5 +150,5 @@ export { // Updates IUpdateProvider, - IUpdate + IUpdate, }; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index ee239acabf7..bed3663cfcb 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -40,44 +40,46 @@ import 'vs/workbench/services/credentials/browser/credentialsService'; import 'vs/workbench/services/url/browser/urlService'; import 'vs/workbench/services/update/browser/updateService'; import 'vs/workbench/contrib/stats/browser/workspaceStatsService'; -import 'vs/workbench/services/workspace/browser/workspacesService'; +import 'vs/workbench/services/workspaces/browser/workspacesService'; +import 'vs/workbench/services/workspaces/browser/workspaceEditingService'; import 'vs/workbench/services/dialogs/browser/dialogService'; import 'vs/workbench/services/dialogs/browser/fileDialogService'; import 'vs/workbench/services/host/browser/browserHostService'; import 'vs/workbench/services/request/browser/requestService'; -import 'vs/workbench/browser/web.simpleservices'; +import 'vs/workbench/services/lifecycle/browser/lifecycleService'; +import 'vs/workbench/services/clipboard/browser/clipboardService'; +import 'vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { BrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; -import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycleService'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { 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 { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; import { NoOpTunnelService } from 'vs/platform/remote/common/tunnelService'; -import { IUserDataSyncStoreService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; +import { ILoggerService } from 'vs/platform/log/common/log'; +import { FileLoggerService } from 'vs/platform/log/common/fileLogService'; +import { IAuthTokenService } from 'vs/platform/auth/common/auth'; +import { AuthTokenService } from 'vs/platform/auth/common/authTokenService'; +import { IUserDataSyncStoreService, IUserDataSyncService, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { WorkspaceEditingService } from 'vs/workbench/services/workspace/browser/workspaceEditingService'; registerSingleton(IExtensionManagementService, ExtensionManagementService); registerSingleton(IBackupFileService, BackupFileService); -registerSingleton(IClipboardService, BrowserClipboardService, true); registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); -registerSingleton(ILifecycleService, BrowserLifecycleService); registerSingleton(IContextMenuService, ContextMenuService); registerSingleton(ITunnelService, NoOpTunnelService, true); +registerSingleton(ILoggerService, FileLoggerService); +registerSingleton(IAuthTokenService, AuthTokenService); +registerSingleton(IUserDataSyncLogService, UserDataSyncLogService); registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService); registerSingleton(IUserDataSyncService, UserDataSyncService); -registerSingleton(IWorkspaceEditingService, WorkspaceEditingService, true); //#endregion @@ -95,7 +97,7 @@ import 'vs/workbench/contrib/debug/browser/extensionHostDebugService'; // Webview import 'vs/workbench/contrib/webview/browser/webviewService'; -import 'vs/workbench/contrib/webview/browser/webviewEditorService'; +import 'vs/workbench/contrib/webview/browser/webviewWorkbenchService'; // Terminal import 'vs/workbench/contrib/terminal/browser/terminalNativeService'; @@ -104,4 +106,10 @@ import 'vs/workbench/contrib/terminal/browser/terminalInstanceService'; // Tasks import 'vs/workbench/contrib/tasks/browser/taskService'; +// Telemetry Opt Out +import 'vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution'; + +// Issues +import 'vs/workbench/contrib/issue/browser/issue.contribution'; + //#endregion diff --git a/test/automation/src/debug.ts b/test/automation/src/debug.ts index 04c2f631511..2dc548e5cb3 100644 --- a/test/automation/src/debug.ts +++ b/test/automation/src/debug.ts @@ -12,7 +12,7 @@ import { IElement } from '../src/driver'; const VIEWLET = 'div[id="workbench.view.debug"]'; const DEBUG_VIEW = `${VIEWLET} .debug-view-content`; -const CONFIGURE = `div[id="workbench.parts.sidebar"] .actions-container .configure`; +const CONFIGURE = `div[id="workbench.parts.sidebar"] .actions-container .codicon-gear`; const STOP = `.debug-toolbar .action-label[title*="Stop"]`; const STEP_OVER = `.debug-toolbar .action-label[title*="Step Over"]`; const STEP_IN = `.debug-toolbar .action-label[title*="Step Into"]`; diff --git a/test/automation/src/keybindings.ts b/test/automation/src/keybindings.ts index 70be12b2378..0e8739dd04c 100644 --- a/test/automation/src/keybindings.ts +++ b/test/automation/src/keybindings.ts @@ -24,7 +24,7 @@ export class KeybindingsEditor { await this.code.waitAndClick('.keybindings-list-container .monaco-list-row.keybinding-item'); await this.code.waitForElement('.keybindings-list-container .monaco-list-row.keybinding-item.focused.selected'); - await this.code.waitAndClick('.keybindings-list-container .monaco-list-row.keybinding-item .action-item .codicon.add'); + await this.code.waitAndClick('.keybindings-list-container .monaco-list-row.keybinding-item .action-item .codicon.codicon-add'); await this.code.waitForActiveElement('.defineKeybindingWidget .monaco-inputbox input'); await this.code.dispatchKeybinding(keybinding); diff --git a/test/automation/src/problems.ts b/test/automation/src/problems.ts index 424274bff6f..8cabe8e320b 100644 --- a/test/automation/src/problems.ts +++ b/test/automation/src/problems.ts @@ -39,7 +39,7 @@ export class Problems { } public static getSelectorInProblemsView(problemType: ProblemSeverity): string { - let selector = problemType === ProblemSeverity.WARNING ? 'severity-warning' : 'severity-error'; + let selector = problemType === ProblemSeverity.WARNING ? 'codicon-warning' : 'codicon-error'; return `div[id="workbench.panel.markers"] .monaco-tl-contents .marker-icon.${selector}`; } diff --git a/test/automation/src/puppeteerDriver.ts b/test/automation/src/puppeteerDriver.ts index ceb76add39c..40fd699b6d3 100644 --- a/test/automation/src/puppeteerDriver.ts +++ b/test/automation/src/puppeteerDriver.ts @@ -92,9 +92,17 @@ let endpoint: string | undefined; export async function launch(_args: string[]): Promise { args = _args; - const webUserDataDir = args.filter(e => e.includes('--user-data-dir='))[0].replace('--user-data-dir=', ''); - await promisify(mkdir)(webUserDataDir); - server = spawn(join(args[0], `resources/server/web.${process.platform === 'win32' ? 'bat' : 'sh'}`), ['--browser', 'none', '--driver', 'web', '--web-user-data-dir', webUserDataDir]); + const agentFolder = args.filter(e => e.includes('--user-data-dir='))[0].replace('--user-data-dir=', ''); + await promisify(mkdir)(agentFolder); + const env = { + VSCODE_AGENT_FOLDER: agentFolder, + ...process.env + }; + server = spawn( + join(args[0], `resources/server/web.${process.platform === 'win32' ? 'bat' : 'sh'}`), + ['--browser', 'none', '--driver', 'web'], + { env } + ); server.stderr.on('data', e => console.log('Server stderr: ' + e)); server.stdout.on('data', e => console.log('Server stdout: ' + e)); process.on('exit', teardown); diff --git a/test/automation/src/scm.ts b/test/automation/src/scm.ts index 519faddb27c..60a33abb93f 100644 --- a/test/automation/src/scm.ts +++ b/test/automation/src/scm.ts @@ -9,7 +9,7 @@ import { findElement, findElements, Code } from './code'; const VIEWLET = 'div[id="workbench.view.scm"]'; const SCM_INPUT = `${VIEWLET} .scm-editor textarea`; -const SCM_RESOURCE = `${VIEWLET} .monaco-list-row > .resource`; +const SCM_RESOURCE = `${VIEWLET} .monaco-list-row .resource`; const REFRESH_COMMAND = `div[id="workbench.parts.sidebar"] .actions-container a.action-label[title="Refresh"]`; const COMMIT_COMMAND = `div[id="workbench.parts.sidebar"] .actions-container a.action-label[title="Commit"]`; const SCM_RESOURCE_CLICK = (name: string) => `${SCM_RESOURCE} .monaco-icon-label[title*="${name}"] .label-name`; @@ -67,7 +67,7 @@ export class SCM extends Viewlet { async unstage(name: string): Promise { await this.code.waitAndClick(SCM_RESOURCE_ACTION_CLICK(name, 'Unstage Changes')); - await this.waitForChange('app.js', 'Modified'); + await this.waitForChange(name, 'Modified'); } async commit(message: string): Promise { diff --git a/test/automation/src/search.ts b/test/automation/src/search.ts index 2b8076cc27e..8f7767802f5 100644 --- a/test/automation/src/search.ts +++ b/test/automation/src/search.ts @@ -84,11 +84,11 @@ export class Search extends Viewlet { } async expandReplace(): Promise { - await this.code.waitAndClick(`${VIEWLET} .search-widget .monaco-button.toggle-replace-button.collapse`); + await this.code.waitAndClick(`${VIEWLET} .search-widget .monaco-button.toggle-replace-button.codicon-chevron-right`); } async collapseReplace(): Promise { - await this.code.waitAndClick(`${VIEWLET} .search-widget .monaco-button.toggle-replace-button.expand`); + await this.code.waitAndClick(`${VIEWLET} .search-widget .monaco-button.toggle-replace-button.codicon-chevron-down`); } async setReplaceText(text: string): Promise { @@ -100,12 +100,12 @@ export class Search extends Viewlet { await retry( () => this.code.waitAndClick(fileMatch), - () => this.code.waitForElement(`${fileMatch} .action-label.codicon.action-replace-all`, el => !!el && el.top > 0 && el.left > 0, 10) + () => this.code.waitForElement(`${fileMatch} .action-label.codicon.codicon-replace-all`, el => !!el && el.top > 0 && el.left > 0, 10) ); // ¯\_(ツ)_/¯ await new Promise(c => setTimeout(c, 500)); - await this.code.waitAndClick(`${fileMatch} .action-label.codicon.action-replace-all`); + await this.code.waitAndClick(`${fileMatch} .action-label.codicon.codicon-replace-all`); } async waitForResultText(text: string): Promise { diff --git a/test/automation/src/statusbar.ts b/test/automation/src/statusbar.ts index 629d82d16fe..d090e9938a7 100644 --- a/test/automation/src/statusbar.ts +++ b/test/automation/src/statusbar.ts @@ -44,11 +44,11 @@ export class StatusBar { private getSelector(element: StatusBarElement): string { switch (element) { case StatusBarElement.BRANCH_STATUS: - return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-git-branch`; + return `${this.mainSelector} ${this.leftSelector} .codicon.codicon-git-branch`; case StatusBarElement.SYNC_STATUS: - return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-sync`; + return `${this.mainSelector} ${this.leftSelector} .codicon.codicon-sync`; case StatusBarElement.PROBLEMS_STATUS: - return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-error`; + return `${this.mainSelector} ${this.leftSelector} .codicon.codicon-error`; case StatusBarElement.SELECTION_STATUS: return `${this.mainSelector} ${this.rightSelector}[title="Go to Line"]`; case StatusBarElement.INDENTATION_STATUS: diff --git a/test/automation/yarn.lock b/test/automation/yarn.lock index 60949e0192b..94a1350861f 100644 --- a/test/automation/yarn.lock +++ b/test/automation/yarn.lock @@ -730,9 +730,9 @@ hosted-git-info@^2.1.4: integrity sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ== https-proxy-agent@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz#271ea8e90f836ac9f119daccd39c19ff7dfb0793" - integrity sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg== + version "2.2.3" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.3.tgz#fb6cd98ed5b9c35056b5a73cd01a8a721d7193d1" + integrity sha512-Ytgnz23gm2DVftnzqRRz2dOXZbGd2uiajSw/95bPp6v53zPRspQjLm/AfBgqbJ2qfeRXWIOMVLpp86+/5yX39Q== dependencies: agent-base "^4.3.0" debug "^3.1.0" diff --git a/test/smoke/README.md b/test/smoke/README.md index dc905211950..5f86605f15a 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -43,7 +43,12 @@ yarn smoketest --build PATH_TO_NEW_RELEASE_PARENT_FOLDER --stable-build PATH_TO_ ### Develop -Start a watch task in `test/smoke`: +Start two watch tasks: + +```bash +cd test/automation +yarn watch +``` ```bash cd test/smoke diff --git a/test/smoke/package.json b/test/smoke/package.json index be3067a8727..2ae2926ada1 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -13,13 +13,13 @@ "@types/mkdirp": "0.5.1", "@types/mocha": "2.2.41", "@types/ncp": "2.0.1", - "@types/node": "^10.14.8", + "@types/node": "^12.11.7", "@types/rimraf": "2.0.2", "concurrently": "^3.5.1", "cpx": "^1.5.0", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", - "mocha": "^5.2.0", + "mocha": "^6.1.4", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "ncp": "^2.0.0", diff --git a/test/smoke/src/areas/git/git.test.ts b/test/smoke/src/areas/git/git.test.ts index 300c832694d..91948d04b1f 100644 --- a/test/smoke/src/areas/git/git.test.ts +++ b/test/smoke/src/areas/git/git.test.ts @@ -51,6 +51,7 @@ export function setup() { await app.workbench.scm.waitForChange('app.js', 'Modified'); await app.workbench.scm.stage('app.js'); + await app.workbench.scm.openChange('app.js'); await app.workbench.scm.unstage('app.js'); }); @@ -60,6 +61,7 @@ export function setup() { await app.workbench.scm.openSCMViewlet(); await app.workbench.scm.waitForChange('app.js', 'Modified'); + await app.workbench.scm.openChange('app.js'); await app.workbench.scm.stage('app.js'); await app.workbench.scm.commit('first commit'); diff --git a/test/smoke/src/areas/statusbar/statusbar.test.ts b/test/smoke/src/areas/statusbar/statusbar.test.ts index a4ecca8e047..34ea9661154 100644 --- a/test/smoke/src/areas/statusbar/statusbar.test.ts +++ b/test/smoke/src/areas/statusbar/statusbar.test.ts @@ -5,7 +5,7 @@ import { Application, Quality, StatusBarElement } from '../../../../automation'; -export function setup() { +export function setup(isWeb) { describe('Statusbar', () => { it('verifies presence of all default status bar elements', async function () { const app = this.app as Application; @@ -18,7 +18,10 @@ export function setup() { await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.PROBLEMS_STATUS); await app.workbench.quickopen.openFile('app.js'); - await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.ENCODING_STATUS); + if (!isWeb) { + // Encoding picker currently hidden in web (only UTF-8 supported) + await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.ENCODING_STATUS); + } await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.EOL_STATUS); await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.INDENTATION_STATUS); await app.workbench.statusbar.waitForStatusbarElement(StatusBarElement.LANGUAGE_STATUS); @@ -36,9 +39,12 @@ export function setup() { await app.workbench.statusbar.clickOn(StatusBarElement.INDENTATION_STATUS); await app.workbench.quickinput.waitForQuickInputOpened(); await app.workbench.quickinput.closeQuickInput(); - await app.workbench.statusbar.clickOn(StatusBarElement.ENCODING_STATUS); - await app.workbench.quickinput.waitForQuickInputOpened(); - await app.workbench.quickinput.closeQuickInput(); + if (!isWeb) { + // Encoding picker currently hidden in web (only UTF-8 supported) + await app.workbench.statusbar.clickOn(StatusBarElement.ENCODING_STATUS); + await app.workbench.quickinput.waitForQuickInputOpened(); + await app.workbench.quickinput.closeQuickInput(); + } await app.workbench.statusbar.clickOn(StatusBarElement.EOL_STATUS); await app.workbench.quickinput.waitForQuickInputOpened(); await app.workbench.quickinput.closeQuickInput(); diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 1f05158f281..0e34ec32cd9 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -289,7 +289,7 @@ describe('Running Code', () => { setupDataEditorTests(); if (!opts.web) { setupDataDebugTests(); } setupDataGitTests(); - setupDataStatusbarTests(); + setupDataStatusbarTests(!!opts.web); setupDataExtensionTests(); setupTerminalTests(); if (!opts.web) { setupDataMultirootTests(); } diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index 221596fc2cb..82626a55c7a 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -44,10 +44,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@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@^12.11.7": + version "12.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" + integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== "@types/rimraf@2.0.2": version "2.0.2" @@ -62,6 +62,11 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +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@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -77,11 +82,23 @@ ansi-regex@^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@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" integrity sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94= +ansi-styles@^3.2.0, 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" + anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" @@ -103,6 +120,13 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" +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" + arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" @@ -254,6 +278,11 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +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@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" @@ -265,6 +294,15 @@ chalk@0.5.1: strip-ansi "^0.3.0" supports-color "^0.2.0" +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" @@ -301,6 +339,15 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +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" + 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" @@ -314,10 +361,17 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -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== +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= commander@2.6.0: version "2.6.0" @@ -400,12 +454,12 @@ 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@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, 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, debug@^2.3.3: version "2.6.9" @@ -414,12 +468,17 @@ debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.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== +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.1.1" + 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= decode-uri-component@^0.2.0: version "0.2.0" @@ -431,6 +490,13 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +define-properties@^1.1.2, define-properties@^1.1.3: + 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" + define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -506,16 +572,51 @@ duplexer@^0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= +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== + entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0: +es-abstract@^1.5.1: + version "1.14.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497" + integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.0" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-inspect "^1.6.0" + object-keys "^1.1.1" + string.prototype.trimleft "^2.0.0" + string.prototype.trimright "^2.0.0" + +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.0, 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== + exec-sh@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" @@ -617,6 +718,20 @@ find-index@^0.1.1: resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" integrity sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ= +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" + 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" @@ -656,6 +771,11 @@ fsevents@^1.0.0: nan "^2.12.1" node-pre-gyp "^0.12.0" +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== + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -670,6 +790,11 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +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-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" @@ -697,7 +822,19 @@ glob2base@^0.0.12: dependencies: find-index "^0.1.1" -glob@7.1.2, glob@^7.0.5: +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.0.5: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== @@ -736,6 +873,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +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-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -772,10 +914,17 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -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@^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== htmlparser2@^3.9.2: version "3.9.2" @@ -847,6 +996,16 @@ is-buffer@^1.1.5, is-buffer@~1.1.1: 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-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" @@ -861,6 +1020,11 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +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-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -963,6 +1127,20 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= +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-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" + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -973,6 +1151,11 @@ isarray@1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +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= + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -985,6 +1168,14 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +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" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -1014,16 +1205,36 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== +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.15: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + lodash@^4.5.1: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw== +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-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -1159,29 +1370,41 @@ 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.2.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.1.tgz#da941c99437da9bac412097859ff99543969f94c" + integrity sha512-VCcWkLHwk79NYQc8cxhkmI8IigTIhsCwZ6RTxQsqK6go4UvEhzJkYuHm8B2YtlSxcYq2fY+ucr4JBwoD6ci80A== 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.3.0" + yargs-parser "13.1.1" + yargs-unparser "1.6.0" ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@^2.1.1: +ms@2.1.1, 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== @@ -1222,6 +1445,14 @@ needle@^2.2.1: iconv-lite "^0.4.4" sax "^1.2.4" +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" + 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" @@ -1295,6 +1526,16 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-inspect@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" + integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -1302,6 +1543,24 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" +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" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -1342,6 +1601,25 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + 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== + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -1357,6 +1635,11 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +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" @@ -1485,6 +1768,16 @@ repeat-string@^1.5.2, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +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@^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== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -1546,7 +1839,12 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== -set-blocking@~2.0.0: +semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +set-blocking@^2.0.0, 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= @@ -1639,6 +1937,11 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +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= + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -1664,6 +1967,31 @@ string-width@^1.0.1: 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.prototype.trimleft@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" + integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" + integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" @@ -1699,7 +2027,14 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: +strip-ansi@^5.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-json-comments@2.0.1, strip-json-comments@^2.0.1, 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= @@ -1711,10 +2046,10 @@ subarg@^1.0.0: dependencies: minimist "^1.1.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== +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: has-flag "^3.0.0" @@ -1730,6 +2065,13 @@ supports-color@^3.2.3: dependencies: has-flag "^1.0.0" +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: + has-flag "^3.0.0" + tar@^4: version "4.4.10" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" @@ -1826,13 +2168,34 @@ watch@^1.0.2: exec-sh "^0.2.0" minimist "^1.2.0" -wide-align@^1.1.0: +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: + 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, wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" +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" @@ -1843,7 +2206,45 @@ xml@^1.0.0: resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= +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== + 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== + +yargs-parser@13.1.1, yargs-parser@^13.1.1: + 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.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs@13.3.0, yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + 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.1" diff --git a/tslint.json b/tslint.json index e894c1faabf..a0feadaf2c0 100644 --- a/tslint.json +++ b/tslint.json @@ -93,7 +93,7 @@ "restrictions": [ "vs/nls", "**/vs/base/{common,browser,node}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -129,7 +129,7 @@ "vs/nls", "**/vs/base/{common,browser,node}/**", "**/vs/base/parts/*/{common,browser,node}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -139,7 +139,7 @@ "vs/css!./**/*", "**/vs/base/{common,browser,node,electron-browser}/**", "**/vs/base/parts/*/{common,browser,node,electron-browser}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -148,7 +148,7 @@ "vs/nls", "**/vs/base/{common,browser,node,electron-main}/**", "**/vs/base/parts/*/{common,browser,node,electron-main}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -188,7 +188,7 @@ "**/vs/base/{common,browser,node}/**", "**/vs/base/parts/*/{common,browser,node}/**", "**/vs/platform/*/{common,browser,node}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -199,7 +199,7 @@ "**/vs/base/{common,browser,node}/**", "**/vs/base/parts/*/{common,browser,node,electron-browser}/**", "**/vs/platform/*/{common,browser,node,electron-browser}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -209,7 +209,7 @@ "**/vs/base/{common,browser,node}/**", "**/vs/base/parts/*/{common,browser,node,electron-browser}/**", "**/vs/platform/*/{common,browser,node,electron-main}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -414,7 +414,7 @@ "**/vs/editor/contrib/**", // editor/contrib is equivalent to /browser/ by convention "**/vs/workbench/{common,browser,node,electron-browser,api}/**", "**/vs/workbench/services/*/{common,browser,node,electron-browser}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -429,7 +429,7 @@ "vs/workbench/contrib/files/common/editors/fileEditorInput", "**/vs/workbench/services/**", "**/vs/workbench/test/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -472,8 +472,7 @@ "**/vs/workbench/api/{common,browser}/**", "**/vs/workbench/services/**/{common,browser}/**", "vscode-textmate", - "onigasm-umd", - "@microsoft/applicationinsights-web" + "onigasm-umd" ] }, { @@ -486,7 +485,7 @@ "**/vs/workbench/{common,node}/**", "**/vs/workbench/api/{common,node}/**", "**/vs/workbench/services/**/{common,node}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -499,7 +498,7 @@ "**/vs/editor/**", "**/vs/workbench/{common,browser,node,electron-browser,api}/**", "**/vs/workbench/services/**/{common,browser,node,electron-browser}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -564,7 +563,7 @@ "**/vs/base/parts/**/{common,browser,node}/**", "**/vs/platform/**/{common,browser,node}/**", "**/vs/code/**/{common,browser,node}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -576,7 +575,7 @@ "**/vs/base/parts/**/{common,browser,node,electron-browser}/**", "**/vs/platform/**/{common,browser,node,electron-browser}/**", "**/vs/code/**/{common,browser,node,electron-browser}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -587,7 +586,7 @@ "**/vs/base/parts/**/{common,browser,node,electron-main}/**", "**/vs/platform/**/{common,browser,node,electron-main}/**", "**/vs/code/**/{common,browser,node,electron-main}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { @@ -600,7 +599,7 @@ "**/vs/workbench/**/{common,node}/**", "**/vs/server/**", "**/vs/code/**/{common,node}/**", - "*" // node modules + "!path" // node modules (except path where we have our own impl) ] }, { diff --git a/yarn.lock b/yarn.lock index d71018e8ee6..e52f09005dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -95,68 +95,12 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" -"@microsoft/applicationinsights-analytics-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-2.1.1.tgz#6d09c1915f808026e2d45165d04802f09affed59" - integrity sha512-VKIutoFKY99CyKwxLUuj6Vnq14/QwXo9/QSQDpYnHEjo+uKn7QmLsHqWw0K9uYNfNAXt4BZimX/zDg6jZtzeXg== +"@types/chokidar@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@types/chokidar/-/chokidar-2.1.3.tgz#123ab795dba6d89be04bf076e6aecaf8620db674" + integrity sha512-6qK3xoLLAhQVTucQGHTySwOVA1crHRXnJeLwqK6KIFkkKa2aoMFXh+WEi8PotxDtvN6MQJLyYN9ag9P6NLV81w== dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-channel-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-2.1.1.tgz#e205eddd93e49d17d9e0711a612b4bfc9810888f" - integrity sha512-fYr9IAqtaEr9AmaPaL3SLQVT3t3GQzl+n74gpNKyAVakDIm0nYQ/bimjdcAhJMDf1VGNSPg/xICneyuZg7Wxlg== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-common@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-common/-/applicationinsights-common-2.1.1.tgz#27e6074584a7a3a8ca3f11f7ff2b7ff0f395bf2d" - integrity sha512-2hkS1Ia1FmAjCuYZ5JlG20/WgObqdsKtmK5YALAFGHIB4KSQ/Za1qazS+7GsG+E0F9UJivNWL1geUIcNqg5Qjg== - dependencies: - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-core-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.1.1.tgz#30fb6a519cc1c6119c419c4811ce72c260217d9e" - integrity sha512-4t4wf6SKqIcWEQDPg/uOhm+BxtHhu/AFreyEoYZmMfcxzAu33h1FtTQRtxBNbYH1+thiNZCh80yUpnT7d9Hrlw== - dependencies: - tslib "^1.9.3" - -"@microsoft/applicationinsights-dependencies-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-2.1.1.tgz#8154c3efcb24617d015d0bce7c2cc47797a8d3c4" - integrity sha512-yhb4EToBp+aI+qLo0h5NDNtoo3sDFV60uyIOK843YjzXqVotcXX/lRShlghTkJtYH09QhrdzDjViUHnD4sMFSQ== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-properties-js@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-2.1.1.tgz#ca34232766eb16167b5d87693e2ae5d94f2a1559" - integrity sha512-8l+/ppw6xKTam2RL4EHZ52Lcf217olw81j6kyBNKtIcGwSnLNHrFwEeF3vBWIteG2JKzlg1GhGjrkB3oxXsV2g== - dependencies: - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - tslib "^1.9.3" - -"@microsoft/applicationinsights-web@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web/-/applicationinsights-web-2.1.1.tgz#1a44eddda7c244b88d9eb052dab6c855682e4f05" - integrity sha512-crvhCkNsNxkFuPWmttyWNSAA96D5FxBtKS6UA9MV9f9XHevTfchf/E3AuU9JZcsXufWMQLwLrUQ9ZiA1QJ0EWA== - dependencies: - "@microsoft/applicationinsights-analytics-js" "2.1.1" - "@microsoft/applicationinsights-channel-js" "2.1.1" - "@microsoft/applicationinsights-common" "2.1.1" - "@microsoft/applicationinsights-core-js" "2.1.1" - "@microsoft/applicationinsights-dependencies-js" "2.1.1" - "@microsoft/applicationinsights-properties-js" "2.1.1" + chokidar "*" "@types/commander@^2.11.0": version "2.12.2" @@ -175,6 +119,20 @@ resolved "https://registry.yarnpkg.com/@types/fancy-log/-/fancy-log-1.3.0.tgz#a61ab476e5e628cd07a846330df53b85e05c8ce0" integrity sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw== +"@types/graceful-fs@4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.2.tgz#fbc9575dbcc6d1d91dd768d30c5fc0c19f6c50bd" + integrity sha512-epDhsJAVxJsWfeqpzEDFhLnhHMbHie/VMFY+2Hvt5p7FemeW5ELM+6gcVYL/ZsUwdu3zrWpDE3VUTddXW+EMYg== + dependencies: + "@types/node" "*" + +"@types/iconv-lite@0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@types/iconv-lite/-/iconv-lite-0.0.1.tgz#aa3b8bda2be512b1ae0a057b942e869c370a5569" + integrity sha1-qjuL2ivlErGuCgV7lC6GnDcKVWk= + dependencies: + "@types/node" "*" + "@types/keytar@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@types/keytar/-/keytar-4.4.0.tgz#ca24e6ee6d0df10c003aafe26e93113b8faf0d8e" @@ -426,14 +384,21 @@ acorn@^6.0.2: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.7.tgz#490180ce18337270232d9488a44be83d9afb7fd3" integrity sha512-HNJNgE60C9eOTgn974Tlp3dpLZdUr+SoxxDwPaY9J/kDNOLQTkaDgwBUXAF4SSsrAwD9RpdxuHK/EbuF+W9Ahw== -agent-base@4, agent-base@^4.1.0: +agent-base@4: 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: +agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +agent-base@~4.2.1: 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== @@ -585,10 +550,10 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.0.tgz#e609350e50a9313b472789b2f14ef35808ee14d6" - integrity sha512-Ozz7l4ixzI7Oxj2+cw+p0tVUt27BpaJ+1+q1TCeANWxHpvyn2+Un+YamBdfKu0uh8xLodGhoa1v7595NhKDAuA== +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -1117,7 +1082,7 @@ braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.2: +braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -1423,20 +1388,20 @@ cheerio@^1.0.0-rc.1: lodash "^4.15.0" parse5 "^3.0.1" -chokidar@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.1.0.tgz#ff23d077682a90eadd209bfa76eb10ed6d359668" - integrity sha512-6vZfo+7W0EOlbSo0nhVKMz4yyssrwiPbBZ8wj1lq8/+l4ZhGZ2U4Md7PspvmijXp1a26D3B7AHEBmIB7aVtaOQ== +chokidar@*, chokidar@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.2.3.tgz#b9270a565d14f02f6bfdd537a6a2bbf5549b8c8c" + integrity sha512-GtrxGuRf6bzHQmXWRepvsGnXpkQkVU+D2/9a7dAe4a7v1NhrfZOZ2oKf76M3nOs46fFYL8D+Q8JYA4GYeJ8Cjw== dependencies: - anymatch "^3.1.0" - braces "^3.0.2" - glob-parent "^5.0.0" - is-binary-path "^2.1.0" - is-glob "^4.0.1" - normalize-path "^3.0.0" - readdirp "^3.1.1" + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.2.0" optionalDependencies: - fsevents "^2.0.6" + fsevents "~2.1.1" chokidar@^2.0.0: version "2.1.0" @@ -1502,6 +1467,11 @@ chromium-pickle-js@^0.2.0: resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" integrity sha1-BKEGZywYsIWrd02YPfo+oTjyIgU= +ci-info@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -3020,6 +2990,11 @@ find-cache-dir@^1.0.0: make-dir "^1.0.0" pkg-dir "^2.0.0" +find-parent-dir@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54" + integrity sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ= + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -3270,10 +3245,10 @@ fsevents@^1.2.7: nan "^2.9.2" node-pre-gyp "^0.10.0" -fsevents@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a" - integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ== +fsevents@~2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.1.tgz#74c64e21df71721845d0c44fe54b7f56b82995a9" + integrity sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw== fstream@^1.0.2: version "1.0.11" @@ -3388,10 +3363,10 @@ glob-parent@^3.0.0, glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.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== +glob-parent@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" + integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== dependencies: is-glob "^4.0.1" @@ -3782,10 +3757,10 @@ gulp-symdest@^1.1.1: queue "^3.1.0" vinyl-fs "^2.4.3" -gulp-tsb@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-4.0.4.tgz#c0486534e2f86cd4a11c2393593d9eae3a426ac4" - integrity sha512-BIIls2PpT3+JR1Svvd0SLjkBj2AmlHIRnum/ajf1XQUgbVA9wwsZuTjpVXU/K06KbTYfGsSSYAPRK2dICNAMZQ== +gulp-tsb@4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-4.0.5.tgz#2c4b41c5049de374934ca0fdb90dd713638af17a" + integrity sha512-zzjLZZBByrtljBhTbDBsScMVB10TYMXiMUV6FUKogs/hpHyTWdkqtMW/5nDPfsDA1xA+HFLgB19FAgWuPE0ZYw== dependencies: ansi-colors "^1.0.1" fancy-log "^1.3.2" @@ -4058,7 +4033,7 @@ http-errors@1.6.2, http-errors@~1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" -http-proxy-agent@2.1.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== @@ -4089,14 +4064,24 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -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== +https-proxy-agent@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== dependencies: - agent-base "^4.1.0" + agent-base "^4.3.0" debug "^3.1.0" +husky@^0.13.1: + version "0.13.4" + resolved "https://registry.yarnpkg.com/husky/-/husky-0.13.4.tgz#48785c5028de3452a51c48c12c4f94b2124a1407" + integrity sha1-SHhcUCjeNFKlHEjBLE+UshJKFAc= + dependencies: + chalk "^1.1.3" + find-parent-dir "^0.3.0" + is-ci "^1.0.9" + normalize-path "^1.0.0" + iconv-lite@0.4.19, iconv-lite@^0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -4315,7 +4300,7 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" -is-binary-path@^2.1.0: +is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== @@ -4339,6 +4324,13 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-ci@^1.0.9: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" + integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== + dependencies: + ci-info "^1.5.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" @@ -4438,7 +4430,7 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-glob@^4.0.1: +is-glob@^4.0.1, 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== @@ -5750,12 +5742,12 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -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== +node-pty@^0.10.0-beta2: + version "0.10.0-beta2" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta2.tgz#6fd0d2fbbe881869e4e19795a05c557ac958da81" + integrity sha512-IU2lzlPUZ+gKG7pHJjzBHpnuwPTxWGgT3iyQicZfdL7dwLvP5cm00QxavAXCInBmRkOMhvM4aBSKvfzqQnCDBA== dependencies: - nan "^2.13.2" + nan "^2.14.0" node.extend@~1.1.2: version "1.1.8" @@ -5802,6 +5794,11 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" +normalize-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" + integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= + normalize-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" @@ -5814,7 +5811,7 @@ normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" -normalize-path@^3.0.0: +normalize-path@^3.0.0, 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== @@ -7129,10 +7126,10 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.2.tgz#fa85d2d14d4289920e4671dead96431add2ee78a" - integrity sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw== +readdirp@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" + integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== dependencies: picomatch "^2.0.4" @@ -7707,10 +7704,10 @@ slice-ansi@^2.0.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -smart-buffer@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" - integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== snapdragon-node@^2.0.1: version "2.1.1" @@ -7756,21 +7753,21 @@ sntp@2.x.x: dependencies: hoek "4.x.x" -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== +socks-proxy-agent@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" + integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== dependencies: - agent-base "~4.2.0" - socks "~2.2.0" + agent-base "~4.2.1" + socks "~2.3.2" -socks@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9" - integrity sha512-0GabKw7n9mI46vcNrVfs0o6XzWzjVa3h6GaSo2UPxtWAROXUWavfJWh1M4PR5tnE0dcnQXZIDFP4yrAysLze/w== +socks@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e" + integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ== dependencies: ip "^1.1.5" - smart-buffer "^4.0.1" + smart-buffer "4.0.2" sort-keys@^1.0.0: version "1.1.2" @@ -8452,11 +8449,6 @@ 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== -tslib@^1.9.3: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - tslint@^5.16.0: version "5.16.0" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.16.0.tgz#ae61f9c5a98d295b9a4f4553b1b1e831c1984d67" @@ -8546,10 +8538,10 @@ typescript-formatter@7.1.0: commandpost "^1.0.0" editorconfig "^0.15.0" -typescript@3.6: - version "3.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.2.tgz#105b0f1934119dde543ac8eb71af3a91009efe54" - integrity sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw== +typescript@3.7.1-rc: + version "3.7.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.1-rc.tgz#2054b872d67f8dc732e36c1df397f9327f37ada0" + integrity sha512-2rMtWppLsaPvmpXsoIAXWDBQVnJMw1ITGGSnidMuayLj9iCmMRT69ncKZw/Mk5rXfJkilApKucWQZxproALoRw== typescript@^2.6.2: version "2.6.2" @@ -8993,15 +8985,15 @@ vscode-nls-dev@^3.3.1: xml2js "^0.4.19" yargs "^13.2.4" -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== +vscode-proxy-agent@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.1.tgz#7fd15e157c02176a0dca9f87840ad0991a62ca57" + integrity sha512-Nnkc7gBk9iAbbZURYZm3p/wvDvRVwDvdzEvDqF1Jh40p6przwQU/JTlV1XLrmd4cCwh6TOAWD81Z3cq+K7Xdmw== dependencies: - debug "3.1.0" - http-proxy-agent "2.1.0" - https-proxy-agent "2.2.1" - socks-proxy-agent "4.0.1" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.3" + socks-proxy-agent "^4.0.1" vscode-ripgrep@^1.5.7: version "1.5.7" @@ -9015,17 +9007,17 @@ vscode-sqlite3@4.0.8: dependencies: nan "^2.14.0" -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== +vscode-textmate@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.3.0.tgz#6e1f0f273d84148cfa1e9c7ed85bd16c974f9f61" + integrity sha512-MhEZ3hvxOVuYGsrRzW/PZLDR2VdtG2+V6TIKPvmE9JT+RAq/OtPlrFd1+ZQwBefoHEhjRNuRJ0OktcFezuxPmg== 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== +vscode-windows-ca-certs@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.2.0.tgz#086f0f4de57e2760a35ac6920831bff246237115" + integrity sha512-YBrJRT0zos+Yb1Qdn73GD8QZr7pa2IE96b5Y1hmmp6XeR8aYB7Iiq5gDAF/+/AxL+caSR9KPZQ6jiYWh5biD7w== dependencies: node-addon-api "1.6.2" @@ -9302,20 +9294,20 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" - integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== +xterm-addon-search@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0.tgz#fc6843bebab1873eff0c89e31f7b74bb3c4d8947" + integrity sha512-ZvRmkNBSz2dT00w0qJ3Hd5cwYoOfkVZpHou7Xxy1kO34wQglU/8Ec4DNTvU27sS9BUzEg8kUcTTru0DxhJXrTA== -xterm-addon-web-links@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" - integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== +xterm-addon-web-links@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2" + integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ== -xterm@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.0.0.tgz#eac93e08cbe69cf238cbace9185ed9e38873df1a" - integrity sha512-Xbx3vvf9FnrUcI1qU31Jww7/fc/NqpXGqgByTvjj7+g3/yPvt/RvLkP/LLMcof2kLAC3evzZGMiovs7NkjdWDw== +xterm@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0.tgz#b9980b2ae18c64ed31bcc95eace3bcecffebbbd9" + integrity sha512-oNfLqt+LmghLPOt5UcskP5Km1fXpTBHsTZ99nxJKY2N0MNFXBKIVXUcNNhHCa74JGZFMGhLT58A/UN3HcPXSfg== y18n@^3.2.1: version "3.2.1"